diff --git a/krusader/Archive/abstractthreadedjob.cpp b/krusader/Archive/abstractthreadedjob.cpp index 702e50d4..a7d431e3 100644 --- a/krusader/Archive/abstractthreadedjob.cpp +++ b/krusader/Archive/abstractthreadedjob.cpp @@ -1,649 +1,675 @@ /*************************************************************************** packjob.cpp - description ------------------- copyright : (C) 2009 + 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 "abstractthreadedjob.h" // QtCore #include #include #include #include #include #include // QtWidgets #include #include #include #include #include "krarchandler.h" #include "../krglobal.h" #include "../krservices.h" #include "../FileSystem/filesystemprovider.h" #include "../FileSystem/filesystem.h" extern KRarcHandler arcHandler; AbstractThreadedJob::AbstractThreadedJob() : KIO::Job(), _locker(), _waiter(), _stack(), _maxProgressValue(0), _currentProgress(0), _exiting(false), _jobThread(0) { } void AbstractThreadedJob::startAbstractJobThread(AbstractJobThread * jobThread) { _jobThread = jobThread; _jobThread->setJob(this); _jobThread->moveToThread(_jobThread); _jobThread->start(); } AbstractThreadedJob::~AbstractThreadedJob() { _exiting = true; if (_jobThread) { _jobThread->abort(); _locker.lock(); _waiter.wakeAll(); _locker.unlock(); _jobThread->wait(); delete _jobThread; } } bool AbstractThreadedJob::event(QEvent *e) { if (e->type() == QEvent::User) { UserEvent *event = (UserEvent*) e; switch (event->command()) { case CMD_SUCCESS: { emitResult(); } break; case CMD_ERROR: { int error = event->args()[ 0 ].value(); QString errorText = event->args()[ 1 ].value(); setError(error); setErrorText(errorText); emitResult(); } break; case CMD_INFO: { QString info = event->args()[ 0 ].value(); QString arg1 = event->args()[ 1 ].value(); QString arg2 = event->args()[ 2 ].value(); QString arg3 = event->args()[ 3 ].value(); QString arg4 = event->args()[ 4 ].value(); _title = info; emit description(this, info, qMakePair(arg1, arg2), qMakePair(arg3, arg4)); } break; case CMD_RESET: { QString info = event->args()[ 0 ].value(); QString arg1 = event->args()[ 1 ].value(); QString arg2 = event->args()[ 2 ].value(); QString arg3 = event->args()[ 3 ].value(); QString arg4 = event->args()[ 4 ].value(); _title = info; setProcessedAmount(KJob::Bytes, 0); setTotalAmount(KJob::Bytes, 0); emitSpeed(0); emit description(this, info, qMakePair(arg1, arg2), qMakePair(arg3, arg4)); } break; case CMD_UPLOAD_FILES: case CMD_DOWNLOAD_FILES: { QList sources = KrServices::toUrlList(event->args()[ 0 ].value()); QUrl dest = event->args()[ 1 ].value(); KIO::Job *job = KIO::copy(sources, dest, KIO::HideProgressInfo); addSubjob(job); job->setUiDelegate(new KIO::JobUiDelegate()); connect(job, SIGNAL(result(KJob*)), this, SLOT(slotDownloadResult(KJob*))); connect(job, SIGNAL(processedAmount(KJob *, KJob::Unit, qulonglong)), this, SLOT(slotProcessedAmount(KJob *, KJob::Unit, qulonglong))); connect(job, SIGNAL(totalAmount(KJob *, KJob::Unit, qulonglong)), this, SLOT(slotTotalAmount(KJob *, KJob::Unit, qulonglong))); connect(job, SIGNAL(speed(KJob *, unsigned long)), this, SLOT(slotSpeed(KJob *, unsigned long))); connect(job, SIGNAL(description(KJob *, const QString &, const QPair &, const QPair &)), this, SLOT(slotDescription(KJob *, const QString &, const QPair &, const QPair &))); } break; case CMD_MAXPROGRESSVALUE: { qulonglong maxValue = event->args()[ 0 ].value(); _maxProgressValue = maxValue; _currentProgress = 0; } break; case CMD_ADD_PROGRESS: { qulonglong progress = event->args()[ 0 ].value(); _currentProgress += progress; if (_maxProgressValue != 0) { setPercent(100 * _currentProgress / _maxProgressValue); int elapsed = _time.isNull() ? 1 : _time.secsTo(QTime::currentTime()); if (elapsed != 0 && event->args().count() > 1) { _time = QTime::currentTime(); QString progressString = (event->args()[ 1 ].value()); emit description(this, _title, qMakePair(progressString, QString("%1/%2").arg(_currentProgress).arg(_maxProgressValue)), qMakePair(QString(), QString()) ); } } } break; case CMD_GET_PASSWORD: { QString path = event->args()[ 0 ].value(); QString password = KRarcHandler::getPassword(path); QList *resultResp = new QList (); (*resultResp) << password; addEventResponse(resultResp); } break; case CMD_MESSAGE: { QString message = event->args()[ 0 ].value(); KIO::JobUiDelegate *ui = static_cast(uiDelegate()); KMessageBox::information(ui ? ui->window() : 0, message); QList *resultResp = new QList (); addEventResponse(resultResp); } break; } return true; } else { return KIO::Job::event(e); } } void AbstractThreadedJob::addEventResponse(QList * obj) { _locker.lock(); _stack.push(obj); _waiter.wakeOne(); _locker.unlock(); } QList * AbstractThreadedJob::getEventResponse(UserEvent * event) { _locker.lock(); QApplication::postEvent(this, event); _waiter.wait(&_locker); if (_exiting) return 0; QList *resp = _stack.pop(); _locker.unlock(); return resp; } void AbstractThreadedJob::sendEvent(UserEvent * event) { QApplication::postEvent(this, event); } void AbstractThreadedJob::slotDownloadResult(KJob* job) { QList *resultResp = new QList (); if (job) { (*resultResp) << QVariant(job->error()); (*resultResp) << QVariant(job->errorText()); } else { (*resultResp) << QVariant(KJob::UserDefinedError); (*resultResp) << QVariant(QString(i18n("Internal error, undefined in result signal"))); } addEventResponse(resultResp); } void AbstractThreadedJob::slotProcessedAmount(KJob *, KJob::Unit unit, qulonglong xu) { setProcessedAmount(unit, xu); } void AbstractThreadedJob::slotTotalAmount(KJob *, KJob::Unit unit, qulonglong xu) { setTotalAmount(unit, xu); } void AbstractThreadedJob::slotSpeed(KJob *, unsigned long spd) { emitSpeed(spd); } void AbstractThreadedJob::slotDescription(KJob *, const QString &title, const QPair &field1, const QPair &field2) { QString mytitle = title; if (!_title.isNull()) mytitle = _title; emit description(this, mytitle, field1, field2); } class AbstractJobObserver : public KRarcObserver { protected: AbstractJobThread * _jobThread; public: AbstractJobObserver(AbstractJobThread * thread): _jobThread(thread) {} virtual ~AbstractJobObserver() {} virtual void processEvents() Q_DECL_OVERRIDE { usleep(1000); qApp->processEvents(); } virtual void subJobStarted(const QString & jobTitle, int count) Q_DECL_OVERRIDE { _jobThread->sendReset(jobTitle); _jobThread->sendMaxProgressValue(count); } virtual void subJobStopped() Q_DECL_OVERRIDE { } virtual bool wasCancelled() Q_DECL_OVERRIDE { return _jobThread->_exited; } virtual void error(const QString & error) Q_DECL_OVERRIDE { _jobThread->sendError(KIO::ERR_NO_CONTENT, error); } virtual void detailedError(const QString & error, const QString & details) Q_DECL_OVERRIDE { _jobThread->sendError(KIO::ERR_NO_CONTENT, error + '\n' + details); } virtual void incrementProgress(int c) Q_DECL_OVERRIDE { _jobThread->sendAddProgress(c, _jobThread->_progressTitle); } }; AbstractJobThread::AbstractJobThread() : _job(0), _downloadTempDir(0), _observer(0), _tempFile(0), _tempDir(0), _exited(false) { } AbstractJobThread::~AbstractJobThread() { if (_downloadTempDir) { delete _downloadTempDir; _downloadTempDir = 0; } if (_observer) { delete _observer; _observer = 0; } if (_tempFile) { delete _tempFile; _tempFile = 0; } } void AbstractJobThread::run() { QTimer::singleShot(0, this, SLOT(slotStart())); QPointer threadLoop = new QEventLoop(this); _loop = threadLoop; threadLoop->exec(); _loop = 0; delete threadLoop; } void AbstractJobThread::terminate() { if (_loop && !_exited) { _loop->quit(); _exited = true; } } void AbstractJobThread::abort() { terminate(); } QList AbstractJobThread::remoteUrls(const QUrl &baseUrl, const QStringList & files) { QList urlList; foreach(const QString &name, files) { QUrl url = baseUrl; url = url.adjusted(QUrl::StripTrailingSlash); url.setPath(url.path() + '/' + (name)); urlList << url; } return urlList; } QUrl AbstractJobThread::downloadIfRemote(const QUrl &baseUrl, const QStringList & files) { // download remote URL-s if necessary if (!baseUrl.isLocalFile()) { sendInfo(i18n("Downloading remote files")); _downloadTempDir = new QTemporaryDir(); QList urlList = remoteUrls(baseUrl, files); QUrl dest(_downloadTempDir->path()); QList args; args << KrServices::toStringList(urlList); args << dest; UserEvent * downloadEvent = new UserEvent(CMD_DOWNLOAD_FILES, args); QList * result = _job->getEventResponse(downloadEvent); if (result == 0) return QUrl(); int errorCode = (*result)[ 0 ].value(); QString errorText = (*result)[ 1 ].value(); delete result; if (errorCode) { sendError(errorCode, errorText); return QUrl(); } else { return dest; } } else { return baseUrl; } } QString AbstractJobThread::tempFileIfRemote(const QUrl &kurl, const QString &type) { if (kurl.isLocalFile()) { return kurl.path(); } _tempFile = new QTemporaryFile(QDir::tempPath() + QLatin1String("/krusader_XXXXXX.") + type); _tempFile->open(); _tempFileName = _tempFile->fileName(); _tempFile->close(); // necessary to create the filename QFile::remove(_tempFileName); _tempFileTarget = kurl; return _tempFileName; } QString AbstractJobThread::tempDirIfRemote(const QUrl &kurl) { if (kurl.isLocalFile()) { return kurl.adjusted(QUrl::StripTrailingSlash).path(); } _tempDir = new QTemporaryDir(); _tempDirTarget = kurl; return _tempDirName = _tempDir->path(); } void AbstractJobThread::sendSuccess() { terminate(); QList args; UserEvent * errorEvent = new UserEvent(CMD_SUCCESS, args); _job->sendEvent(errorEvent); } void AbstractJobThread::sendError(int errorCode, QString message) { terminate(); QList args; args << errorCode; args << message; UserEvent * errorEvent = new UserEvent(CMD_ERROR, args); _job->sendEvent(errorEvent); } void AbstractJobThread::sendInfo(QString message, QString a1, QString a2, QString a3, QString a4) { QList args; args << message; args << a1; args << a2; args << a3; args << a4; UserEvent * infoEvent = new UserEvent(CMD_INFO, args); _job->sendEvent(infoEvent); } void AbstractJobThread::sendReset(QString message, QString a1, QString a2, QString a3, QString a4) { QList args; args << message; args << a1; args << a2; args << a3; args << a4; UserEvent * infoEvent = new UserEvent(CMD_RESET, args); _job->sendEvent(infoEvent); } void AbstractJobThread::sendMaxProgressValue(qulonglong value) { QList args; args << value; UserEvent * infoEvent = new UserEvent(CMD_MAXPROGRESSVALUE, args); _job->sendEvent(infoEvent); } void AbstractJobThread::sendAddProgress(qulonglong value, const QString &progress) { QList args; args << value; if (!progress.isNull()) args << progress; UserEvent * infoEvent = new UserEvent(CMD_ADD_PROGRESS, args); _job->sendEvent(infoEvent); } -void AbstractJobThread::calcSpaceLocal(const QUrl &baseUrl, const QStringList & files, KIO::filesize_t &totalSize, - unsigned long &totalDirs, unsigned long &totalFiles) +void countFiles(const QString &path, unsigned long &totalFiles, bool &stop) { - sendReset(i18n("Calculating space")); + const QDir dir(path); + if (!dir.exists()) { + totalFiles++; // assume its a file + return; + } + + for (const QString name : dir.entryList()) { + if (stop) + return; + + if (name == QStringLiteral(".") || name == QStringLiteral("..")) + continue; + + countFiles(dir.absoluteFilePath(name), totalFiles, stop); + } +} + +void AbstractJobThread::countLocalFiles(const QUrl &baseUrl, const QStringList &files, + unsigned long &totalFiles) +{ + sendReset(i18n("Counting files")); FileSystem *calcSpaceFileSystem = FileSystemProvider::instance().getFilesystem(baseUrl); calcSpaceFileSystem->refresh(baseUrl); + for (const QString name : files) { + if (_exited) + return; - for (int i = 0; i != files.count(); i++) { - calcSpaceFileSystem->calcSpace(files[i], &totalSize, &totalFiles, &totalDirs, &_exited); + const QString path = calcSpaceFileSystem->getUrl(name).toLocalFile(); + if (!QFileInfo(path).exists()) + return; + + countFiles(path, totalFiles, _exited); } + delete calcSpaceFileSystem; } KRarcObserver * AbstractJobThread::observer() { if (_observer) return _observer; _observer = new AbstractJobObserver(this); return _observer; } bool AbstractJobThread::uploadTempFiles() { if (_tempFile != 0 || _tempDir != 0) { sendInfo(i18n("Uploading to remote destination")); if (_tempFile) { QList urlList; urlList << QUrl::fromLocalFile(_tempFileName); QList args; args << KrServices::toStringList(urlList); args << _tempFileTarget; UserEvent * uploadEvent = new UserEvent(CMD_UPLOAD_FILES, args); QList * result = _job->getEventResponse(uploadEvent); if (result == 0) return false; int errorCode = (*result)[ 0 ].value(); QString errorText = (*result)[ 1 ].value(); delete result; if (errorCode) { sendError(errorCode, errorText); return false; } } if (_tempDir) { QList urlList; QDir tempDir(_tempDirName); QStringList list = tempDir.entryList(); foreach(const QString &name, list) { if (name == "." || name == "..") continue; QUrl url = QUrl::fromLocalFile(_tempDirName).adjusted(QUrl::StripTrailingSlash); url.setPath(url.path() + '/' + (name)); urlList << url; } QList args; args << KrServices::toStringList(urlList); args << _tempDirTarget; UserEvent * uploadEvent = new UserEvent(CMD_UPLOAD_FILES, args); QList * result = _job->getEventResponse(uploadEvent); if (result == 0) return false; int errorCode = (*result)[ 0 ].value(); QString errorText = (*result)[ 1 ].value(); delete result; if (errorCode) { sendError(errorCode, errorText); return false; } } } return true; } QString AbstractJobThread::getPassword(const QString &path) { QList args; args << path; UserEvent * getPasswdEvent = new UserEvent(CMD_GET_PASSWORD, args); QList * result = _job->getEventResponse(getPasswdEvent); if (result == 0) return QString(); QString password = (*result)[ 0 ].value(); if (password.isNull()) password = QString(""); delete result; return password; } void AbstractJobThread::sendMessage(const QString &message) { QList args; args << message; UserEvent * getPasswdEvent = new UserEvent(CMD_MESSAGE, args); QList * result = _job->getEventResponse(getPasswdEvent); if (result == 0) return; delete result; } //! Gets some archive information that is needed in several cases. /*! \param path A path to the archive. \param type The type of the archive. \param password The password of the archive. \param arcName The name of the archive. \param sourceFolder A QUrl, which may be remote, of the folder where the archive is. \return If the archive information has been obtained. */ bool AbstractJobThread::getArchiveInformation(QString &path, QString &type, QString &password, QString &arcName, const QUrl &sourceFolder) { // Safety checks (though the user shouldn't have been able to select something named "" or "..") if (arcName.isEmpty()) return false; if (arcName == "..") return false; QUrl url = sourceFolder.adjusted(QUrl::StripTrailingSlash); url.setPath(url.path() + '/' + arcName); path = url.adjusted(QUrl::StripTrailingSlash).path(); QMimeDatabase db; QMimeType mt = db.mimeTypeForUrl(url); QString mime = mt.isValid() ? mt.name() : QString(); bool encrypted = false; type = arcHandler.getType(encrypted, path, mime); // Check that the archive is supported if (!KRarcHandler::arcSupported(type)) { sendError(KIO::ERR_NO_CONTENT, i18nc("%1=archive filename", "%1, unsupported archive type.", arcName)); return false; } password = encrypted ? getPassword(path) : QString(); return true; } diff --git a/krusader/Archive/abstractthreadedjob.h b/krusader/Archive/abstractthreadedjob.h index 33374fb0..a48bb32a 100644 --- a/krusader/Archive/abstractthreadedjob.h +++ b/krusader/Archive/abstractthreadedjob.h @@ -1,199 +1,198 @@ /*************************************************************************** threadedjob.h - description ------------------- copyright : (C) 2009 + 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 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 ABSTRACTTHREADEDJOB_H #define ABSTRACTTHREADEDJOB_H // QtCore #include #include #include #include #include #include #include #include #include #include #include #include class AbstractJobThread; class QTemporaryDir; class UserEvent; class KRarcObserver; class QTemporaryFile; class AbstractThreadedJob : public KIO::Job { friend class AbstractJobThread; Q_OBJECT protected: AbstractThreadedJob(); void addEventResponse(QList * obj); QList * getEventResponse(UserEvent * event); void sendEvent(UserEvent * event); virtual ~AbstractThreadedJob(); virtual bool event(QEvent *) Q_DECL_OVERRIDE; virtual void startAbstractJobThread(AbstractJobThread*); virtual bool doSuspend() Q_DECL_OVERRIDE { return false; } protected slots: void slotDownloadResult(KJob*); void slotProcessedAmount(KJob *, KJob::Unit, qulonglong); void slotTotalAmount(KJob *, KJob::Unit, qulonglong); void slotSpeed(KJob *, unsigned long); void slotDescription(KJob *job, const QString &title, const QPair &field1, const QPair &field2); public: QMutex _locker; QWaitCondition _waiter; QStack *> _stack; QString _title; qulonglong _maxProgressValue; qulonglong _currentProgress; QTime _time; bool _exiting; private: AbstractJobThread * _jobThread; }; class AbstractJobThread : public QThread { friend class AbstractThreadedJob; friend class AbstractJobObserver; Q_OBJECT public: AbstractJobThread(); virtual ~AbstractJobThread(); void abort(); KRarcObserver * observer(); protected slots: virtual void slotStart() = 0; protected: virtual void run() Q_DECL_OVERRIDE; void setJob(AbstractThreadedJob * job) { _job = job; } QList remoteUrls(const QUrl &baseUrl, const QStringList & files); QUrl downloadIfRemote(const QUrl &baseUrl, const QStringList & files); - void calcSpaceLocal(const QUrl &baseUrl, const QStringList & files, KIO::filesize_t &totalSize, - unsigned long &totalDirs, unsigned long &totalFiles); + void countLocalFiles(const QUrl &baseUrl, const QStringList &files, unsigned long &totalFiles); void sendError(int errorCode, QString message); void sendInfo(QString message, QString a1 = QString(), QString a2 = QString(), QString a3 = QString(), QString a4 = QString()); void sendReset(QString message, QString a1 = QString(""), QString a2 = QString(""), QString a3 = QString(""), QString a4 = QString("")); void sendSuccess(); void sendMessage(const QString &message); void sendMaxProgressValue(qulonglong value); void sendAddProgress(qulonglong value, const QString &progress = QString()); void setProgressTitle(const QString &title) { _progressTitle = title; } QString tempFileIfRemote(const QUrl &kurl, const QString &type); QString tempDirIfRemote(const QUrl &kurl); bool uploadTempFiles(); bool isExited() { return _exited; } void terminate(); QString getPassword(const QString &path); bool getArchiveInformation(QString &, QString &, QString &, QString &, const QUrl &); AbstractThreadedJob *_job; QEventLoop *_loop; QTemporaryDir *_downloadTempDir; KRarcObserver *_observer; QTemporaryFile *_tempFile; QString _tempFileName; QUrl _tempFileTarget; QTemporaryDir *_tempDir; QString _tempDirName; QUrl _tempDirTarget; bool _exited; QString _progressTitle; }; enum PossibleCommands { CMD_ERROR = 1, CMD_INFO = 2, CMD_RESET = 3, CMD_DOWNLOAD_FILES = 4, CMD_UPLOAD_FILES = 5, CMD_SUCCESS = 6, CMD_MAXPROGRESSVALUE = 7, CMD_ADD_PROGRESS = 8, CMD_GET_PASSWORD = 9, CMD_MESSAGE = 10 }; class UserEvent : public QEvent { public: UserEvent(int command, const QList &args) : QEvent(QEvent::User), _command(command), _args(args) {} inline int command() { return _command; } inline const QList & args() { return _args; } protected: int _command; QList _args; }; #endif // __ABSTRACTTHREADED_JOB_H__ diff --git a/krusader/Archive/packjob.cpp b/krusader/Archive/packjob.cpp index 776ac79a..dc21c415 100644 --- a/krusader/Archive/packjob.cpp +++ b/krusader/Archive/packjob.cpp @@ -1,180 +1,179 @@ /*************************************************************************** packjob.cpp - description ------------------- copyright : (C) 2009 + 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 "packjob.h" #include "krarchandler.h" // QtCore #include #include #include #include #include extern KRarcHandler arcHandler; PackJob::PackJob(const QUrl &srcUrl, const QUrl &destUrl, const QStringList & fileNames, const QString &type, const QMap &packProps) : AbstractThreadedJob() { startAbstractJobThread(new PackThread(srcUrl, destUrl, fileNames, type, packProps)); } PackJob * PackJob::createPacker(const QUrl &srcUrl, const QUrl &destUrl, const QStringList & fileNames, const QString &type, const QMap &packProps) { return new PackJob(srcUrl, destUrl, fileNames, type, packProps); } PackThread::PackThread(const QUrl &srcUrl, const QUrl &destUrl, const QStringList & fileNames, const QString &type, const QMap &packProps) : AbstractJobThread(), _sourceUrl(srcUrl), _destUrl(destUrl), _fileNames(fileNames), _type(type), _packProperties(packProps) { } void PackThread::slotStart() { QUrl newSource = downloadIfRemote(_sourceUrl, _fileNames); if (newSource.isEmpty()) return; - KIO::filesize_t totalSize = 0; - unsigned long totalDirs = 0, totalFiles = 0; + unsigned long totalFiles = 0; - calcSpaceLocal(newSource, _fileNames, totalSize, totalDirs, totalFiles); + countLocalFiles(newSource, _fileNames, totalFiles); QString arcFile = tempFileIfRemote(_destUrl, _type); QString arcDir = newSource.adjusted(QUrl::StripTrailingSlash).path(); setProgressTitle(i18n("Processed files")); QString save = QDir::currentPath(); QDir::setCurrent(arcDir); - bool result = KRarcHandler::pack(_fileNames, _type, arcFile, totalFiles + totalDirs, _packProperties, observer()); + bool result = KRarcHandler::pack(_fileNames, _type, arcFile, totalFiles, _packProperties, observer()); QDir::setCurrent(save); if (isExited()) return; if (!result) { sendError(KIO::ERR_INTERNAL, i18n("Error while packing")); return; } if (!uploadTempFiles()) return; sendSuccess(); } TestArchiveJob::TestArchiveJob(const QUrl &srcUrl, const QStringList & fileNames) : AbstractThreadedJob() { startAbstractJobThread(new TestArchiveThread(srcUrl, fileNames)); } TestArchiveJob * TestArchiveJob::testArchives(const QUrl &srcUrl, const QStringList & fileNames) { return new TestArchiveJob(srcUrl, fileNames); } TestArchiveThread::TestArchiveThread(const QUrl &srcUrl, const QStringList & fileNames) : AbstractJobThread(), _sourceUrl(srcUrl), _fileNames(fileNames) { } void TestArchiveThread::slotStart() { // Gets a QUrl of the source folder, which may be remote QUrl newSource = downloadIfRemote(_sourceUrl, _fileNames); if (newSource.isEmpty()) return; for (int i = 0; i < _fileNames.count(); ++i) { QString path, type, password, arcName = _fileNames[i]; if (!getArchiveInformation(path, type, password, arcName, newSource)) return; // test the archive if (!KRarcHandler::test(path, type, password, observer(), 0)) { sendError(KIO::ERR_NO_CONTENT, i18nc("%1=archive filename", "%1, test failed.", arcName)); return ; } } sendMessage(i18n("Archive tests passed.")); sendSuccess(); } UnpackJob::UnpackJob(const QUrl &srcUrl, const QUrl &destUrl, const QStringList & fileNames) : AbstractThreadedJob() { startAbstractJobThread(new UnpackThread(srcUrl, destUrl, fileNames)); } UnpackJob * UnpackJob::createUnpacker(const QUrl &srcUrl, const QUrl &destUrl, const QStringList & fileNames) { return new UnpackJob(srcUrl, destUrl, fileNames); } UnpackThread::UnpackThread(const QUrl &srcUrl, const QUrl &destUrl, const QStringList & fileNames) : AbstractJobThread(), _sourceUrl(srcUrl), _destUrl(destUrl), _fileNames(fileNames) { } void UnpackThread::slotStart() { // Gets a QUrl of the source folder, which may be remote QUrl newSource = downloadIfRemote(_sourceUrl, _fileNames); if (newSource.isEmpty()) return; QString localDest = tempDirIfRemote(_destUrl); for (int i = 0; i < _fileNames.count(); ++i) { QString path, type, password, arcName = _fileNames[i]; if (!getArchiveInformation(path, type, password, arcName, newSource)) return; setProgressTitle(i18n("Processed files")); // unpack the files bool result = KRarcHandler::unpack(path, type, password, localDest, observer()); if (isExited()) return; if (!result) { sendError(KIO::ERR_INTERNAL, i18n("Error while unpacking")); return; } } if (!uploadTempFiles()) return; sendSuccess(); } diff --git a/krusader/FileSystem/CMakeLists.txt b/krusader/FileSystem/CMakeLists.txt index 5ac61612..1fc66d5a 100644 --- a/krusader/FileSystem/CMakeLists.txt +++ b/krusader/FileSystem/CMakeLists.txt @@ -1,26 +1,27 @@ include_directories(${KF5_INCLUDES_DIRS} ${QT_INCLUDES}) set(FileSystem_SRCS defaultfilesystem.cpp dirlisterinterface.cpp fileitem.cpp filesystem.cpp filesystemprovider.cpp krpermhandler.cpp krquery.cpp krtrashhandler.cpp + sizecalculator.cpp virtualfilesystem.cpp ../../krArc/krlinecountingprocess.cpp ) add_library(FileSystem STATIC ${FileSystem_SRCS}) target_link_libraries(FileSystem KF5::I18n KF5::KIOCore KF5::KIOWidgets ) if(ACL_FOUND) target_link_libraries(FileSystem ${ACL_LIBS}) endif(ACL_FOUND) diff --git a/krusader/FileSystem/defaultfilesystem.cpp b/krusader/FileSystem/defaultfilesystem.cpp index 7d9ae6d5..464c754a 100644 --- a/krusader/FileSystem/defaultfilesystem.cpp +++ b/krusader/FileSystem/defaultfilesystem.cpp @@ -1,385 +1,385 @@ /*************************************************************************** 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 "../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, destination, flags); connect(krJob, &KrJob::started, [=](KIO::Job *job) { connectJob(job, dest); }); if (mode == KIO::CopyJob::Move) { // notify source about removed files connect(krJob, &KrJob::started, [=](KIO::Job *job) { connectSourceFileSystem(job, urls); }); } krJobMan->manageJob(krJob, startMode); } void DefaultFileSystem::dropFiles(const QUrl &destination, QDropEvent *event) { // resolve relative path before resolving symlinks const QUrl dest = resolveRelativePath(destination); KIO::DropJob *job = KIO::drop(event, dest); // 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())); // NOTE: DrobJobs are internally recorded //recordJobUndo(job, type, dst, src); } void DefaultFileSystem::connectSourceFileSystem(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 const QUrl url = urls.first().adjusted(QUrl::RemoveFilename); connect(job, &KIO::Job::result, [=]() { emit fileSystemChanged(url); }); } } void DefaultFileSystem::addFiles(const QList &fileUrls, KIO::CopyJob::CopyMode mode, 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(cleanUrl(destination).path()).exists()) // if we get out from the archive change the protocol destination.setScheme("file"); } } copyFiles(fileUrls, destination, mode); } void DefaultFileSystem::mkDir(const QString &name) { KIO::SimpleJob* job = KIO::mkdir(getUrl(name)); connectJob(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); connectJob(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; } 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 showHidden) { 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()) { // we could read local directories with KIO but using Qt is a lot faster! return refreshLocal(directory); } _currentDirectory = cleanUrl(directory); // start the listing job KIO::ListJob *job = KIO::listDir(_currentDirectory, KIO::HideProgressInfo, showHidden); 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) { if (job && job->error()) { // we failed to refresh _listError = true; 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) { krOut << "redirection to " << url; // 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::slotWatcherDirty(const QString& path) { if (path == realPath()) { // this happens // 1. if a directory was created/deleted/renamed inside this directory. No deleted // 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) { krOut << "dirty watcher file not found (unexpected): " << 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); *fileItem = *newFileItem; delete newFileItem; emit updatedFileItem(fileItem); } void DefaultFileSystem::slotWatcherDeleted(const QString& 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) { 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); // 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(const QString&)), this, SLOT(slotWatcherCreated(const 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 92d7cd4f..0f4ee444 100644 --- a/krusader/FileSystem/filesystem.cpp +++ b/krusader/FileSystem/filesystem.cpp @@ -1,427 +1,298 @@ /*************************************************************************** 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 #include #include "../defaults.h" #include "../krglobal.h" #include "../JobMan/jobman.h" #include "../JobMan/krjob.h" #include "krpermhandler.h" FileSystem::FileSystem() : DirListerInterface(0), _isRefreshing(false) {} FileSystem::~FileSystem() { clear(_fileItems); emit cleared(); // please don't remove this line. This informs the view about deleting the references } 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; } QList FileSystem::searchFileItems(const KRQuery &filter) { QList result; for (FileItem *item : _fileItems.values()) { if (filter.match(item)) { result.append(item); } } return result; } 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; } -void FileSystem::calcSpace(const QString &name, KIO::filesize_t *totalSize, - unsigned long *totalFiles, unsigned long *totalDirs, bool *stop) -{ - const QUrl url = getUrl(name); - if (url.isEmpty()) { - krOut << "item for calculating space not found: " << name; - return; - } - - calcSpace(url, totalSize, totalFiles, totalDirs, stop); -} - - 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::refresh(const QUrl &directory) { 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 res = refreshInternal(toRefresh, showHiddenFiles()); _isRefreshing = false; if (!res) { // cleanup and abort if (!dirChange) emit cleared(); clear(tempFileItems); return false; } emit refreshDone(dirChange); clear(tempFileItems); updateFilesystemInfo(); return true; } void FileSystem::deleteFiles(const QStringList &fileNames, bool moveToTrash) { // get absolute URLs for file names const QList fileUrls = getUrls(fileNames); KrJob *krJob = KrJob::createDeleteJob(fileUrls, moveToTrash); connect(krJob, &KrJob::started, [=](KIO::Job *job) { connectJob(job, currentDirectory()); }); if (moveToTrash) { // update destination: the trash bin (in case a panel/tab is showing it) connect(krJob, &KrJob::started, [=](KIO::Job *job) { // Note: the "trash" protocal should always have only one "/" after the "scheme:" part connect(job, &KIO::Job::result, [=]() { emit fileSystemChanged(QUrl("trash:/")); }); }); } krJobMan->manageJob(krJob); } void FileSystem::connectJob(KJob *job, const QUrl &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); }); connect(job, &KIO::Job::result, [=]() { emit fileSystemChanged(destination); }); } bool FileSystem::showHiddenFiles() { const KConfigGroup gl(krConfig, "Look&Feel"); return gl.readEntry("Show Hidden", _ShowHidden); } -void FileSystem::calcSpace(const QUrl &url, KIO::filesize_t *totalSize, unsigned long *totalFiles, - unsigned long *totalDirs, bool *stop) -{ - if (url.isLocalFile()) { - calcSpaceLocal(cleanUrl(url).path(), totalSize, totalFiles, totalDirs, stop); - } else { - calcSpaceKIO(url, totalSize, totalFiles, totalDirs, stop); - } -} - -void FileSystem::calcSpaceLocal(const QString &path, KIO::filesize_t *totalSize, unsigned long *totalFiles, - unsigned long *totalDirs, bool *stop) -{ - if (stop && *stop) - return; - - if (path == "/proc") - return; - - QT_STATBUF stat_p; // KDE lstat is necessary as QFileInfo and KFileItem - // if the name is wrongly encoded, then we zero the size out - stat_p.st_size = 0; - stat_p.st_mode = 0; - QT_LSTAT(path.toLocal8Bit(), &stat_p); // reports wrong size for a symbolic link - - if (S_ISLNK(stat_p.st_mode) || !S_ISDIR(stat_p.st_mode)) { // single files are easy : ) - ++(*totalFiles); - (*totalSize) += stat_p.st_size; - } else { // handle directories avoid a nasty crash on un-readable dirs - bool readable = ::access(path.toLocal8Bit(), R_OK | X_OK) == 0; - if (!readable) - return; - - QDir dir(path); - if (!dir.exists()) - return; - - ++(*totalDirs); - dir.setFilter(QDir::TypeMask | QDir::System | QDir::Hidden); - dir.setSorting(QDir::Name | QDir::DirsFirst); - - // recurse on all the files in the directory - QFileInfoList fileList = dir.entryInfoList(); - for (int k = 0; k != fileList.size(); k++) { - if (*stop) - return; - QFileInfo qfiP = fileList[k]; - if (qfiP.fileName() != "." && qfiP.fileName() != "..") - calcSpaceLocal(path + '/' + qfiP.fileName(), totalSize, totalFiles, totalDirs, - stop); - } - } -} - -// TODO called from another thread, creating KIO jobs does not work here -void FileSystem::calcSpaceKIO(const QUrl &url, KIO::filesize_t *totalSize, unsigned long *totalFiles, - unsigned long *totalDirs, bool *stop) -{ - return; - - if (stop && *stop) - return; - - _calcKdsBusy = stop; - _calcKdsTotalSize = totalSize; - _calcKdsTotalFiles = totalFiles; - _calcKdsTotalDirs = totalDirs; - - _calcStatBusy = true; - KIO::StatJob *statJob = KIO::stat(url, KIO::HideProgressInfo); // thread problem here - connect(statJob, &KIO::Job::result, this, &FileSystem::slotCalcStatResult); - - while (!(*stop) && _calcStatBusy) { - usleep(1000); - } - - if (_calcEntry.count() == 0) - return; // statJob failed - - const KFileItem kfi(_calcEntry, url, true); - if (kfi.isFile() || kfi.isLink()) { - (*totalFiles)++; - *totalSize += kfi.size(); - return; - } - - KIO::DirectorySizeJob *directorySizeJob = KIO::directorySize(url); - connect(directorySizeJob, &KIO::Job::result, this, &FileSystem::slotCalcKdsResult); - - while (!(*stop)) { - // we are in a separate thread - so sleeping is OK - usleep(1000); - } -} - 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 // 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 { krOut << "Failed to read link: " << path; } } return new FileItem(virt ? path : name, QUrl::fromLocalFile(path), isDir, size, stat_p.st_mode, stat_p.st_mtime, 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 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, (uid_t) -1, (gid_t) -1, kfi.user(), kfi.group(), kfi.isLink(), kfi.linkDest(), false, kfi.ACL().asString(), kfi.defaultACL().asString()); } // ==== protected slots ==== 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(); } } -/// to be implemented -void FileSystem::slotCalcKdsResult(KJob *job) -{ - if (!job->error()) { - KIO::DirectorySizeJob *kds = static_cast(job); - *_calcKdsTotalSize += kds->totalSize(); - *_calcKdsTotalFiles += kds->totalFiles(); - *_calcKdsTotalDirs += kds->totalSubdirs(); - } - *_calcKdsBusy = true; -} - -void FileSystem::slotCalcStatResult(KJob *job) -{ - _calcEntry = job->error() ? KIO::UDSEntry() : static_cast(job)->statResult(); - _calcStatBusy = false; -} - // ==== private ==== void FileSystem::clear(FileItemDict &fileItems) { QHashIterator lit(fileItems); while (lit.hasNext()) { delete lit.next().value(); } fileItems.clear(); } diff --git a/krusader/FileSystem/filesystem.h b/krusader/FileSystem/filesystem.h index fa30bac4..a1c2e808 100644 --- a/krusader/FileSystem/filesystem.h +++ b/krusader/FileSystem/filesystem.h @@ -1,245 +1,216 @@ /*************************************************************************** filesystem.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 *************************************************************************** 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 FILESYSTEM_H #define FILESYSTEM_H #include "dirlisterinterface.h" // QtCore #include #include #include #include #include // QtGui #include // QtWidgets #include #include +#include #include "fileitem.h" #include "krquery.h" #include "../JobMan/jobman.h" /** * An abstract filesystem. Use the implementations of this class for all file operations. * * It represents a directory and gives access to its files. All common file operations * are supported. Methods with absolute URL as argument can be used independently from the current * directory. Otherwise - if the methods argument is a file name - the operation is performed inside * the current directory. * * Notification signals are emitted if the directory content may have been changed. */ class FileSystem : public DirListerInterface { Q_OBJECT public: enum FS_TYPE { /// Virtual filesystem. Krusaders custom virt:/ protocol FS_VIRTUAL, /// Filesystem supporting all KIO protocols (file:/, ftp:/, smb:/, etc.) FS_DEFAULT }; FileSystem(); virtual ~FileSystem(); // DirListerInterface implementation inline QList fileItems() const { return _fileItems.values(); } inline unsigned long numFileItems() const { return _fileItems.count(); } inline bool isRoot() const { const QString path = _currentDirectory.path(); return path.isEmpty() || path == "/"; } /// Copy (copy, move or link) files in this filesystem. /// Destination is absolute URL. May implemented async. virtual void copyFiles(const QList &urls, const QUrl &destination, KIO::CopyJob::CopyMode mode = KIO::CopyJob::Copy, bool showProgressInfo = true, JobMan::StartMode startMode = JobMan::Default) = 0; /// Handle file dropping in this filesystem. Destination is absolute URL. May implemented async. virtual void dropFiles(const QUrl &destination, QDropEvent *event) = 0; /// Copy (copy, move or link) files to the current filesystem directory or to "dir", the /// directory name relative to the current dir. May implemented async. virtual void addFiles(const QList &fileUrls, KIO::CopyJob::CopyMode mode, QString dir = "") = 0; /// Create a new directory in the current directory. May implemented async. virtual void mkDir(const QString &name) = 0; /// Rename file/directory in the current directory. May implemented async. virtual void rename(const QString &fileName, const QString &newName) = 0; /// Return an absolute URL for a single file/directory name in the current directory - with no /// trailing slash. virtual QUrl getUrl(const QString &name) const = 0; /// Return a list of URLs for multiple files/directories in the current directory. QList getUrls(const QStringList &names) const; /// Return true if all files can be moved to trash, else false. virtual bool canMoveToTrash(const QStringList &fileNames) const = 0; /// Return the filesystem mount point of the current directory. Empty string by default. virtual QString mountPoint() const { return QString(); } /// Returns true if this filesystem implementation does not need to be notified about changes in the /// current directory. Else false. virtual bool hasAutoUpdate() const { return false; } /// Notify this filesystem that the filesystem info of the current directory may have changed. virtual void updateFilesystemInfo() {} /// Returns the current directory path of this filesystem. inline QUrl currentDirectory() const { return _currentDirectory; } /// Return the file item for a file name in the current directory. Or 0 if not found. FileItem *getFileItem(const QString &name) const; /// Return a list of file items for a search query. Or an empty list if nothing was found. QList searchFileItems(const KRQuery &filter); /// The total size of all files in the current directory (only valid after refresh). // TODO unused KIO::filesize_t totalSize() const; /// Return the filesystem type. inline FS_TYPE type() const { return _type; } /// Return true if the current directory is local (without recognizing mount points). inline bool isLocal() const { return _currentDirectory.isLocalFile(); } /// Return true if the current directory is a remote (network) location. inline bool isRemote() const { const QString sc = _currentDirectory.scheme(); return (sc == "fish" || sc == "ftp" || sc == "sftp" || sc == "nfs" || sc == "smb" || sc == "webdav"); } /// Returns true if this filesystem is currently refreshing the current directory. inline bool isRefreshing() const { return _isRefreshing; } /// Delete or trash files in the current directory. Implemented async. void deleteFiles(const QStringList &fileNames, bool moveToTrash = true); - /// Calculate the amount of space occupied by a file or directory in the current directory - /// (recursive). - virtual void calcSpace(const QString &name, KIO::filesize_t *totalSize, - unsigned long *totalFiles, unsigned long *totalDirs, bool *stop); - /// Return the input URL with a trailing slash if absent. static QUrl ensureTrailingSlash(const QUrl &url); /// Return the input URL without trailing slash. static QUrl cleanUrl(const QUrl &url) { return url.adjusted(QUrl::StripTrailingSlash); } /// Add 'file' scheme to non-empty URL without scheme static QUrl preferLocalUrl(const QUrl &url); /// Return a file item for a local file inside a directory static FileItem *createLocalFileItem(const QString &name, const QString &directory, bool virt = false); /// Return a file item for a KIO result. Returns 0 if entry is not needed - static FileItem *createFileItemFromKIO(const KIO::UDSEntry &_calcEntry, const QUrl &directory, + static FileItem *createFileItemFromKIO(const KIO::UDSEntry &entry, const QUrl &directory, bool virt = false); // set the parent window to be used for dialogs void setParentWindow(QWidget *widget) { parentWindow = widget; } public slots: /// Re-read the current directory files or change to another directory. Blocking. /// Returns true if directory was read. Returns false if failed or refresh job was killed. // optional TODO: add an async version of this bool refresh(const QUrl &directory = QUrl()); signals: /// Emitted when this filesystem is currently refreshing the filesystem directory. void refreshJobStarted(KIO::Job *job); /// Emitted when an error occured in this filesystem during refresh. void error(const QString &msg); /// Emitted when the content of a directory was changed by this filesystem. void fileSystemChanged(const QUrl &directory); /// Emitted when the information for the filesystem of the current directory changed. /// Information is either /// * 'metaInfo': a displayable string about the fs, empty by default, OR /// * 'fsType', 'total' and 'free': filesystem type, size and free space, /// empty string or 0 by default void fileSystemInfoChanged(const QString &metaInfo, const QString &fsType, KIO::filesize_t total, KIO::filesize_t free); /// Emitted before a directory path is opened for reading. Used for automounting. void aboutToOpenDir(const QString &path); protected: /// Fill the filesystem dictionary with file items, must be implemented for each filesystem. virtual bool refreshInternal(const QUrl &origin, bool showHidden) = 0; /// Connect the result signal of a file operation job. void connectJob(KJob *job, const QUrl &destination); /// Returns true if showing hidden files is set in config. bool showHiddenFiles(); /// Add a new file item to the internal dictionary (while refreshing). inline void addFileItem(FileItem *item) { _fileItems.insert(item->getName(), item); } - /// Calculate the size of a file or directory (recursive). - void calcSpace(const QUrl &url, KIO::filesize_t *totalSize, unsigned long *totalFiles, - unsigned long *totalDirs, bool *stop); - /// Calculate the size of a local file or directory (recursive). - void calcSpaceLocal(const QString &path, KIO::filesize_t *totalSize, unsigned long *totalFiles, - unsigned long *totalDirs, bool *stop); - /// Calculate the size of any KIO file or directory. - void calcSpaceKIO(const QUrl &url, KIO::filesize_t *totalSize, unsigned long *totalFiles, - unsigned long *totalDirs, bool *stop); - FS_TYPE _type; // the filesystem type. QUrl _currentDirectory; // the path or file the filesystem originates from. bool _isRefreshing; // true if filesystem is busy with refreshing QPointer parentWindow; protected slots: /// Handle result after job (except when refreshing!) finished void slotJobResult(KJob *job, bool refresh); -private slots: - /// Handle result of KIO::DirectorySizeJob when calculating URL size - void slotCalcKdsResult(KJob *job); - /// Handle result of KIO::StatJob when calculating URL size - void slotCalcStatResult(KJob *job); - private: typedef QHash FileItemDict; /// Delete and clear file items. void clear(FileItemDict &fileItems); FileItemDict _fileItems; // the list of files in the current dictionary - - // used in the calcSpace function - bool *_calcKdsBusy; - bool _calcStatBusy; - KIO::UDSEntry _calcEntry; - KIO::filesize_t *_calcKdsTotalSize; - unsigned long *_calcKdsTotalFiles; - unsigned long *_calcKdsTotalDirs; - }; #endif diff --git a/krusader/FileSystem/sizecalculator.cpp b/krusader/FileSystem/sizecalculator.cpp new file mode 100644 index 00000000..45e5f641 --- /dev/null +++ b/krusader/FileSystem/sizecalculator.cpp @@ -0,0 +1,158 @@ +/***************************************************************************** + * 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 "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(nextUrl())); +} + +SizeCalculator::~SizeCalculator() +{ + if (m_directorySizeJob) + m_directorySizeJob->kill(); +} + +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; + + 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->refresh(m_currentUrl)) { + krOut << "cannot refresh virtual fs, url=" << m_currentUrl; + 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()) { + krOut << "stat job failed"; + 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, &KIO::Job::result, this, &SizeCalculator::slotDirectorySizeResult); +} + +void SizeCalculator::slotDirectorySizeResult(KJob *) +{ + if (!m_directorySizeJob->error()) { + m_totalSize += m_directorySizeJob->totalSize(); + m_currentUrlSize += 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(); +} diff --git a/krusader/FileSystem/sizecalculator.h b/krusader/FileSystem/sizecalculator.h new file mode 100644 index 00000000..b5e9bf37 --- /dev/null +++ b/krusader/FileSystem/sizecalculator.h @@ -0,0 +1,92 @@ +/***************************************************************************** + * 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 * + *****************************************************************************/ + +#ifndef SIZECALCULATOR_H +#define SIZECALCULATOR_H + +// QtCore +#include +#include + +#include + +/** + * Calculate the size of files and directories (recursive). + * + * Krusader's virtual filesystem and all KIO protocols are supported. + * + * This calculator will delete itself when its finished (like KJob). + */ +class SizeCalculator : public QObject +{ + Q_OBJECT +public: + /** + * Calculate the size of files and directories defined by URLs. + * + * The calculation is automatically started (like KJob). + */ + explicit SizeCalculator(const QList &urls); + ~SizeCalculator(); + + /** Return the URLs this calculator was created with. */ + QList urls() const { return m_urls; } + /** Return the current total size calculation result. */ + KIO::filesize_t totalSize() const; + /** Return the current total number of files counted. */ + unsigned long totalFiles() const; + /** Return the current number of directories counted. */ + unsigned long totalDirs() const; + +public slots: + /** Cancel the calculation and mark for deletion. finished() will be emitted.*/ + void cancel(); + +signals: + /** Emitted when an intermediate size for one of the URLs was calculated. */ + void calculated(const QUrl &url, KIO::filesize_t size); + /** Emitted when calculation is finished or was canceled. Calculator will be deleted afterwards. */ + void finished(bool canceled); + +private: + void nextSubUrl(); + void done(); + +private slots: + void nextUrl(); + void slotStatResult(KJob *job); + void slotDirectorySizeResult(KJob *job); + +private: + const QList m_urls; + + QList m_nextUrls; + QUrl m_currentUrl; + QList m_nextSubUrls; + + KIO::filesize_t m_currentUrlSize; + KIO::filesize_t m_totalSize; + unsigned long m_totalFiles; + unsigned long m_totalDirs; + + bool m_canceled; + + QPointer m_directorySizeJob; +}; + +#endif // SIZECALCULATOR_H diff --git a/krusader/FileSystem/virtualfilesystem.cpp b/krusader/FileSystem/virtualfilesystem.cpp index bac721f4..943befd0 100644 --- a/krusader/FileSystem/virtualfilesystem.cpp +++ b/krusader/FileSystem/virtualfilesystem.cpp @@ -1,365 +1,345 @@ /***************************************************************************** * Copyright (C) 2003 Shie Erlich * * Copyright (C) 2003 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 "virtualfilesystem.h" // QtCore #include #include #include // QtWidgets #include #include #include #include #include #include #include #include #include #include #include "../defaults.h" #include "../krglobal.h" #include "../krservices.h" #define VIRTUALFILESYSTEM_DB "virtualfilesystem.db" QHash *> VirtualFileSystem::_virtFilesystemDict; QHash VirtualFileSystem::_metaInfoDict; VirtualFileSystem::VirtualFileSystem() : FileSystem() { if (_virtFilesystemDict.isEmpty()) { restore(); } _type = FS_VIRTUAL; } void VirtualFileSystem::copyFiles(const QList &urls, const QUrl &destination, KIO::CopyJob::CopyMode /*mode*/, bool /*showProgressInfo*/, JobMan::StartMode /*startMode*/) { const QString dir = QDir(destination.path()).absolutePath().remove('/'); if (dir.isEmpty()) { showError(i18n("You cannot copy files directly to the 'virt:/' folder.\n" "You can create a sub folder and copy your files into it.")); return; } if (!_virtFilesystemDict.contains(dir)) { mkDirInternal(dir); } QList *urlList = _virtFilesystemDict[dir]; for (const QUrl &fileUrl : urls) { if (!urlList->contains(fileUrl)) { urlList->push_back(fileUrl); } } emit fileSystemChanged(QUrl("virt:///" + dir)); // may call refresh() } void VirtualFileSystem::dropFiles(const QUrl &destination, QDropEvent *event) { const QList &urls = KUrlMimeData::urlsFromMimeData(event->mimeData()); // dropping on virtual filesystem is always copy operation copyFiles(urls, destination); } void VirtualFileSystem::addFiles(const QList &fileUrls, KIO::CopyJob::CopyMode /*mode*/, QString dir) { QUrl destination(_currentDirectory); if (!dir.isEmpty()) { destination.setPath(QDir::cleanPath(destination.path() + '/' + dir)); } copyFiles(fileUrls, destination); } void VirtualFileSystem::remove(const QStringList &fileNames) { const QString parentDir = currentDir(); if (parentDir == "/") { // remove virtual directory for (const QString &filename : fileNames) { _virtFilesystemDict["/"]->removeAll(QUrl(QStringLiteral("virt:/") + filename)); delete _virtFilesystemDict[filename]; _virtFilesystemDict.remove(filename); _metaInfoDict.remove(filename); } } else { // remove the URLs from the collection for (const QString name : fileNames) { if (_virtFilesystemDict.find(parentDir) != _virtFilesystemDict.end()) { QList *urlList = _virtFilesystemDict[parentDir]; urlList->removeAll(getUrl(name)); } } } emit fileSystemChanged(currentDirectory()); // will call refresh() } QUrl VirtualFileSystem::getUrl(const QString &name) const { FileItem *item = getFileItem(name); if (!item) { return QUrl(); // not found } return item->getUrl(); } void VirtualFileSystem::mkDir(const QString &name) { if (currentDir() != "/") { showError(i18n("Creating new folders is allowed only in the 'virt:/' folder.")); return; } mkDirInternal(name); emit fileSystemChanged(currentDirectory()); // will call refresh() } void VirtualFileSystem::rename(const QString &fileName, const QString &newName) { FileItem *item = getFileItem(fileName); if (!item) return; // not found if (currentDir() == "/") { // rename virtual directory _virtFilesystemDict["/"]->append(QUrl(QStringLiteral("virt:/") + newName)); _virtFilesystemDict["/"]->removeAll(QUrl(QStringLiteral("virt:/") + fileName)); _virtFilesystemDict.insert(newName, _virtFilesystemDict.take(fileName)); refresh(); return; } // newName can be a (local) path or a full url QUrl dest(newName); if (dest.scheme().isEmpty()) dest.setScheme("file"); // add the new url to the list // the list is refreshed, only existing files remain - // so we don't have to worry if the job was successful _virtFilesystemDict[currentDir()]->append(dest); KIO::Job *job = KIO::moveAs(item->getUrl(), dest, KIO::HideProgressInfo); connect(job, &KIO::Job::result, this, [=](KJob* job) { slotJobResult(job, false); }); connect(job, &KIO::Job::result, [=]() { emit fileSystemChanged(currentDirectory()); }); } -void VirtualFileSystem::calcSpace(const QString &name, KIO::filesize_t *totalSize, unsigned long *totalFiles, - unsigned long *totalDirs, bool *stop) -{ - if (currentDir() == "/") { - if (!_virtFilesystemDict.contains(name)) { - return; // virtual folder not found - } - - const QList *urlList = _virtFilesystemDict[name]; - if (urlList) { - for (int i = 0; (i != urlList->size()) && !(*stop); i++) { - FileSystem::calcSpace((*urlList)[i], totalSize, totalFiles, totalDirs, stop); - } - } - return; - } - - FileSystem::calcSpace(name, totalSize, totalFiles, totalDirs, stop); -} - bool VirtualFileSystem::canMoveToTrash(const QStringList &fileNames) const { if (isRoot()) return false; for (const QString fileName : fileNames) { if (!getUrl(fileName).isLocalFile()) { return false; } } return true; } void VirtualFileSystem::setMetaInformation(const QString &info) { _metaInfoDict[currentDir()] = info; } // ==== protected ==== bool VirtualFileSystem::refreshInternal(const QUrl &directory, bool /*showHidden*/) { _currentDirectory = cleanUrl(directory); _currentDirectory.setHost(""); // remove invalid subdirectories _currentDirectory.setPath("/" + _currentDirectory.path().remove('/')); if (!_virtFilesystemDict.contains(currentDir())) { // NOTE: silently creating non-existing directories here. The search and locate tools expect // this. (And user can enter some directory and it will be created). mkDirInternal(currentDir()); save(); // infinite loop possible //emit fileSystemChanged(currentDirectory()); return true; } QList *urlList = _virtFilesystemDict[currentDir()]; const QString metaInfo = _metaInfoDict[currentDir()]; emit fileSystemInfoChanged(metaInfo.isEmpty() ? i18n("Virtual filesystem") : metaInfo, "", 0, 0); QMutableListIterator it(*urlList); while (it.hasNext()) { const QUrl url = it.next(); FileItem *item = createFileItem(url); if (!item) { // remove URL from the list for a file that no longer exists it.remove(); } else { addFileItem(item); } } save(); return true; } // ==== private ==== void VirtualFileSystem::mkDirInternal(const QString &name) { // clean path, consistent with currentDir() QString dirName = name; dirName = dirName.remove('/'); if (dirName.isEmpty()) dirName = "/"; _virtFilesystemDict.insert(dirName, new QList()); _virtFilesystemDict["/"]->append(QUrl(QStringLiteral("virt:/") + dirName)); } void VirtualFileSystem::save() { KConfig *db = &VirtualFileSystem::getVirtDB(); db->deleteGroup("virt_db"); KConfigGroup group(db, "virt_db"); QHashIterator *> it(_virtFilesystemDict); while (it.hasNext()) { it.next(); QList *urlList = it.value(); QList::iterator url; QStringList entry; for (url = urlList->begin(); url != urlList->end(); ++url) { entry.append((*url).toDisplayString()); } // KDE 4.0 workaround: 'Item_' prefix is added as KConfig fails on 1 char names (such as /) group.writeEntry("Item_" + it.key(), entry); group.writeEntry("MetaInfo_" + it.key(), _metaInfoDict[it.key()]); } db->sync(); } void VirtualFileSystem::restore() { KConfig *db = &VirtualFileSystem::getVirtDB(); const KConfigGroup dbGrp(db, "virt_db"); const QMap map = db->entryMap("virt_db"); QMapIterator it(map); while (it.hasNext()) { it.next(); // KDE 4.0 workaround: check and remove 'Item_' prefix if (!it.key().startsWith(QLatin1String("Item_"))) continue; const QString key = it.key().mid(5); const QList urlList = KrServices::toUrlList(dbGrp.readEntry(it.key(), QStringList())); _virtFilesystemDict.insert(key, new QList(urlList)); _metaInfoDict.insert(key, dbGrp.readEntry("MetaInfo_" + key, QString())); } if (!_virtFilesystemDict["/"]) { // insert root element if missing for some reason _virtFilesystemDict.insert("/", new QList()); } } FileItem *VirtualFileSystem::createFileItem(const QUrl &url) { if (url.scheme() == "virt") { // return a virtual directory in root QString path = url.path().mid(1); if (path.isEmpty()) path = '/'; return FileItem::createVirtualDir(path, url); } const QUrl directory = url.adjusted(QUrl::RemoveFilename); if (url.isLocalFile()) { QFileInfo file(url.path()); return file.exists() ? FileSystem::createLocalFileItem(url.fileName(), directory.path(), true) : 0; } KIO::StatJob *statJob = KIO::stat(url, KIO::HideProgressInfo); connect(statJob, &KIO::Job::result, this, &VirtualFileSystem::slotStatResult); // ugly: we have to wait here until the stat job is finished QEventLoop eventLoop; connect(statJob, &KJob::finished, &eventLoop, &QEventLoop::quit); eventLoop.exec(); // blocking until quit() if (_fileEntry.count() == 0) { return 0; // stat job failed } if (!_fileEntry.contains(KIO::UDSEntry::UDS_MODIFICATION_TIME)) { // TODO this also happens for FTP directories return 0; // file not found } return FileSystem::createFileItemFromKIO(_fileEntry, directory, true); } KConfig &VirtualFileSystem::getVirtDB() { //virtualfilesystem_db = new KConfig("data",VIRTUALFILESYSTEM_DB,KConfig::NoGlobals); static KConfig db(VIRTUALFILESYSTEM_DB, KConfig::CascadeConfig, QStandardPaths::AppDataLocation); return db; } void VirtualFileSystem::slotStatResult(KJob *job) { _fileEntry = job->error() ? KIO::UDSEntry() : static_cast(job)->statResult(); } void VirtualFileSystem::showError(const QString &error) { QWidget *window = QApplication::activeWindow(); KMessageBox::sorry(window, error); // window can be null, is allowed } diff --git a/krusader/FileSystem/virtualfilesystem.h b/krusader/FileSystem/virtualfilesystem.h index 7ae14085..b98085f4 100644 --- a/krusader/FileSystem/virtualfilesystem.h +++ b/krusader/FileSystem/virtualfilesystem.h @@ -1,105 +1,103 @@ /***************************************************************************** * Copyright (C) 2003 Shie Erlich * * Copyright (C) 2003 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 * *****************************************************************************/ #ifndef VIRTUALFILESYSTEM_H #define VIRTUALFILESYSTEM_H // QtCore #include #include "filesystem.h" /** * Custom virtual filesystem implementation: It holds arbitrary lists of files which are only * virtual references to real files. The filename of a virtual file is the full path of the real * file. * * Only two filesystem levels are supported: On root level only directories can be created; these * virtual root directories can contain a set of virtual files and directories. Entering a directory * on the sublevel is out of scope and the real directory will be opened. * * The filesystem content is saved in a separate config file and preserved between application runs. * * Used at least by bookmarks, locate, search and synchronizer dialog. */ class VirtualFileSystem : public FileSystem { Q_OBJECT public: VirtualFileSystem(); /// Create virtual files in this filesystem. Copy mode and showProgressInfo are ignored. void copyFiles(const QList &urls, const QUrl &destination, KIO::CopyJob::CopyMode mode = KIO::CopyJob::Copy, bool showProgressInfo = false, JobMan::StartMode startMode = JobMan::Start) Q_DECL_OVERRIDE; /// Handle file dropping in this filesystem: Always creates virtual files. void dropFiles(const QUrl &destination, QDropEvent *event) Q_DECL_OVERRIDE; /// Add virtual files to the current directory. void addFiles(const QList &fileUrls, KIO::CopyJob::CopyMode mode = KIO::CopyJob::Copy, QString dir = "") Q_DECL_OVERRIDE; /// Create a virtual directory. Only possible in the root directory. void mkDir(const QString &name) Q_DECL_OVERRIDE; /// Rename a (real) file in the current directory. void rename(const QString &fileName, const QString &newName) Q_DECL_OVERRIDE; - void calcSpace(const QString &name, KIO::filesize_t *totalSize, unsigned long *totalFiles, - unsigned long *totalDirs, bool *stop) Q_DECL_OVERRIDE; /// Returns the URL of the real file or an empty URL if file with name does not exist. QUrl getUrl(const QString& name) const Q_DECL_OVERRIDE; bool canMoveToTrash(const QStringList &fileNames) const Q_DECL_OVERRIDE; /// Remove virtual files or directories. Real files stay untouched. void remove(const QStringList &fileNames); /// Set meta information to be displayed in UI for the current directory void setMetaInformation(const QString &info); protected: bool refreshInternal(const QUrl &origin, bool showHidden) Q_DECL_OVERRIDE; private: /// Return current dir: "/" or pure directory name inline QString currentDir() { const QString path = _currentDirectory.path().mid(1); // remove slash return path.isEmpty() ? "/" : path; } void mkDirInternal(const QString& name); /// Save the dictionary to file void save(); /// Restore the dictionary from file void restore(); /// Create local or KIO fileItem. Returns 0 if file does not exist FileItem *createFileItem(const QUrl &url); /// Return the configuration file storing the urls of virtual files KConfig &getVirtDB(); private slots: void slotStatResult(KJob *job); private: void showError(const QString &error); static QHash *> _virtFilesystemDict; // map virtual directories to containing files static QHash _metaInfoDict; // map virtual directories to meta infos QString _metaInfo; // displayable string with information about the current virtual directory KIO::UDSEntry _fileEntry; // for async call, save stat job result here }; #endif diff --git a/krusader/Konfigurator/kgpanel.cpp b/krusader/Konfigurator/kgpanel.cpp index 76305481..317f8015 100644 --- a/krusader/Konfigurator/kgpanel.cpp +++ b/krusader/Konfigurator/kgpanel.cpp @@ -1,728 +1,724 @@ /*************************************************************************** kgpanel.cpp - description ------------------- copyright : (C) 2003 by Csaba Karai 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 "kgpanel.h" #include "../defaults.h" #include "../Dialogs/krdialogs.h" // QtGui #include // QtWidgets #include #include #include #include #include #include #include #include "../GUI/krtreewidget.h" #include "../Panel/krsearchbar.h" #include "../Panel/krselectionmode.h" #include "../Panel/krview.h" #include "../Panel/krviewfactory.h" #include "../Panel/krlayoutfactory.h" enum { PAGE_MISC = 0, PAGE_VIEW, PAGE_PANELTOOLBAR, PAGE_MOUSE, PAGE_MEDIA_MENU, PAGE_LAYOUT }; KgPanel::KgPanel(bool first, QWidget* parent) : KonfiguratorPage(first, parent) { tabWidget = new QTabWidget(this); setWidget(tabWidget); setWidgetResizable(true); setupMiscTab(); setupPanelTab(); setupButtonsTab(); setupMouseModeTab(); setupMediaMenuTab(); setupLayoutTab(); } // --------------------------------------------------------------------------------------- // ---------------------------- Misc TAB ------------------------------------------------ // --------------------------------------------------------------------------------------- void KgPanel::setupMiscTab() { QScrollArea *scrollArea = new QScrollArea(tabWidget); QWidget *tab = new QWidget(scrollArea); scrollArea->setFrameStyle(QFrame::NoFrame); scrollArea->setWidget(tab); scrollArea->setWidgetResizable(true); tabWidget->addTab(scrollArea, i18n("General")); QVBoxLayout *miscLayout = new QVBoxLayout(tab); miscLayout->setSpacing(6); miscLayout->setContentsMargins(11, 11, 11, 11); // --------------------------------------------------------------------------------------- // ------------------------------- Navigator bar ------------------------------------- // --------------------------------------------------------------------------------------- QGroupBox *miscGrp = createFrame(i18n("Navigator bar"), tab); QGridLayout *miscGrid = createGridLayout(miscGrp); KONFIGURATOR_CHECKBOX_PARAM navigatorbar_settings[] = { // cfg_class, cfg_name, default, text, restart, tooltip {"Look&Feel", "Navigator Edit Mode", false, i18n("Edit Mode by default"), true, i18n("Show editable path in Navigator bar by default") }, {"Look&Feel", "Navigator Full Path", false, i18n("Show full path by default"), true, i18n("Always show full path in Navigator bar by default.") }, }; cbs = createCheckBoxGroup(2, 0, navigatorbar_settings, 2 /*count*/, miscGrp, PAGE_MISC); miscGrid->addWidget(cbs, 0, 0); miscLayout->addWidget(miscGrp); // --------------------------------------------------------------------------------------- // ------------------------------- Operation --------------------------------------------- // --------------------------------------------------------------------------------------- miscGrp = createFrame(i18n("Operation"), tab); miscGrid = createGridLayout(miscGrp); KONFIGURATOR_CHECKBOX_PARAM operation_settings[] = { // cfg_class, cfg_name, default, text, restart, tooltip {"Look&Feel", "Mark Dirs", _MarkDirs, i18n("Autoselect folders"), false, i18n("When matching the select criteria, not only files will be selected, but also folders.") }, {"Look&Feel", "Rename Selects Extension", true, i18n("Rename selects extension"), false, i18n("When renaming a file, the whole text is selected. If you want Total-Commander like renaming of just the name, without extension, uncheck this option.") }, {"Look&Feel", "UnselectBeforeOperation", _UnselectBeforeOperation, i18n("Unselect files before copy/move"), false, i18n("Unselect files, which are to be copied/moved, before the operation starts.") }, {"Look&Feel", "FilterDialogRemembersSettings", _FilterDialogRemembersSettings, i18n("Filter dialog remembers settings"), false, i18n("The filter dialog is opened with the last filter settings that where applied to the panel.") }, }; cbs = createCheckBoxGroup(2, 0, operation_settings, 4 /*count*/, miscGrp, PAGE_MISC); miscGrid->addWidget(cbs, 0, 0); miscLayout->addWidget(miscGrp); // --------------------------------------------------------------------------------------- // ------------------------------ Tabs --------------------------------------------------- // --------------------------------------------------------------------------------------- miscGrp = createFrame(i18n("Tabs"), tab); miscGrid = createGridLayout(miscGrp); KONFIGURATOR_CHECKBOX_PARAM tabbar_settings[] = { // cfg_class cfg_name default text restart tooltip {"Look&Feel", "Fullpath Tab Names", _FullPathTabNames, i18n("Use full path tab names"), true , i18n("Display the full path in the folder tabs. By default only the last part of the path is displayed.") }, {"Look&Feel", "Show Tab Buttons", true, i18n("Show new/close tab buttons"), true , i18n("Show the new/close tab buttons") }, }; KonfiguratorCheckBoxGroup *cbs = createCheckBoxGroup(2, 0, tabbar_settings, 2 /*count*/, miscGrp, PAGE_MISC); miscGrid->addWidget(cbs, 0, 0); // ----------------- Tab Bar position ---------------------------------- QHBoxLayout *hbox = new QHBoxLayout(); hbox->addWidget(new QLabel(i18n("Tab Bar position:"), miscGrp)); KONFIGURATOR_NAME_VALUE_PAIR positions[] = { { i18n("Top"), "top" }, { i18n("Bottom"), "bottom" } }; KonfiguratorComboBox *cmb = createComboBox("Look&Feel", "Tab Bar Position", "bottom", positions, 2, miscGrp, true, false, PAGE_MISC); hbox->addWidget(cmb); hbox->addWidget(createSpacer(miscGrp)); miscGrid->addLayout(hbox, 1, 0); miscLayout->addWidget(miscGrp); // --------------------------------------------------------------------------------------- // ----------------------------- Search bar -------------------------------------------- // --------------------------------------------------------------------------------------- miscGrp = createFrame(i18n("Search bar"), tab); miscGrid = createGridLayout(miscGrp); KONFIGURATOR_CHECKBOX_PARAM quicksearch[] = { // cfg_class cfg_name default text restart tooltip {"Look&Feel", "New Style Quicksearch", _NewStyleQuicksearch, i18n("Start by typing"), false, i18n("Open search bar and start searching by typing in panel.") }, {"Look&Feel", "Case Sensitive Quicksearch", _CaseSensitiveQuicksearch, i18n("Case sensitive"), false, i18n("Search must match case.") }, {"Look&Feel", "Up/Down Cancels Quicksearch", false, i18n("Up/Down cancels search"), false, i18n("Pressing the Up/Down buttons closes the search bar (only in search mode).") }, }; quicksearchCheckboxes = createCheckBoxGroup(2, 0, quicksearch, 3 /*count*/, miscGrp, PAGE_MISC); miscGrid->addWidget(quicksearchCheckboxes, 0, 0, 1, -1); connect(quicksearchCheckboxes->find("New Style Quicksearch"), SIGNAL(stateChanged(int)), this, SLOT(slotDisable())); slotDisable(); // -------------- Search bar position ----------------------- hbox = new QHBoxLayout(); hbox->addWidget(new QLabel(i18n("Position:"), miscGrp)); cmb = createComboBox("Look&Feel", "Quicksearch Position", "bottom", positions, 2, miscGrp, true, false, PAGE_MISC); hbox->addWidget(cmb); hbox->addWidget(createSpacer(miscGrp)); miscGrid->addLayout(hbox, 1, 0); miscLayout->addWidget(miscGrp); // -------------- Default search mode ----------------------- hbox = new QHBoxLayout(); hbox->addWidget(new QLabel(i18n("Default mode:"), miscGrp)); KONFIGURATOR_NAME_VALUE_PAIR modes[] = { { i18n("Search"), QString::number(KrSearchBar::MODE_SEARCH) }, { i18n("Select"), QString::number(KrSearchBar::MODE_SELECT) }, { i18n("Filter"), QString::number(KrSearchBar::MODE_FILTER) } }; cmb = createComboBox("Look&Feel", "Default Search Mode", QString::number(KrSearchBar::MODE_SEARCH), modes, 3, miscGrp, true, false, PAGE_MISC); cmb->setToolTip(i18n("Set the default mode on first usage")); hbox->addWidget(cmb); hbox->addWidget(createSpacer(miscGrp)); miscGrid->addLayout(hbox, 1, 1); miscLayout->addWidget(miscGrp); // -------------------------------------------------------------------------------------------- // ------------------------------- Status/Totalsbar settings ---------------------------------- // -------------------------------------------------------------------------------------------- miscGrp = createFrame(i18n("Status/Totalsbar"), tab); miscGrid = createGridLayout(miscGrp); KONFIGURATOR_CHECKBOX_PARAM barSettings[] = { {"Look&Feel", "Show Size In Bytes", false, i18n("Show size in bytes too"), true, i18n("Show size in bytes too") }, {"Look&Feel", "ShowSpaceInformation", true, i18n("Show space information"), true, i18n("Show free/total space on the device") }, }; KonfiguratorCheckBoxGroup *barSett = createCheckBoxGroup(2, 0, barSettings, 2 /*count*/, miscGrp, PAGE_MISC); miscGrid->addWidget(barSett, 1, 0, 1, 2); miscLayout->addWidget(miscGrp); } // -------------------------------------------------------------------------------------------- // ------------------------------------ Layout Tab -------------------------------------------- // -------------------------------------------------------------------------------------------- void KgPanel::setupLayoutTab() { QScrollArea *scrollArea = new QScrollArea(tabWidget); QWidget *tab = new QWidget(scrollArea); scrollArea->setFrameStyle(QFrame::NoFrame); scrollArea->setWidget(tab); scrollArea->setWidgetResizable(true); tabWidget->addTab(scrollArea, i18n("Layout")); QGridLayout *grid = createGridLayout(tab); QStringList layoutNames = KrLayoutFactory::layoutNames(); int numLayouts = layoutNames.count(); grid->addWidget(createSpacer(tab), 0, 2); QLabel *l = new QLabel(i18n("Layout:"), tab); l->setAlignment(Qt::AlignRight | Qt::AlignVCenter); grid->addWidget(l, 0, 0); KONFIGURATOR_NAME_VALUE_PAIR *layouts = new KONFIGURATOR_NAME_VALUE_PAIR[numLayouts]; for (int i = 0; i != numLayouts; i++) { layouts[ i ].text = KrLayoutFactory::layoutDescription(layoutNames[i]); layouts[ i ].value = layoutNames[i]; } KonfiguratorComboBox *cmb = createComboBox("PanelLayout", "Layout", "default", layouts, numLayouts, tab, true, false, PAGE_LAYOUT); grid->addWidget(cmb, 0, 1); delete [] layouts; l = new QLabel(i18n("Frame Color:"), tab); l->setAlignment(Qt::AlignRight | Qt::AlignVCenter); grid->addWidget(l, 1, 0); KONFIGURATOR_NAME_VALUE_PAIR frameColor[] = { { i18nc("Frame color", "Defined by Layout"), "default" }, { i18nc("Frame color", "None"), "none" }, { i18nc("Frame color", "Statusbar"), "Statusbar" } }; cmb = createComboBox("PanelLayout", "FrameColor", "default", frameColor, 3, tab, true, false, PAGE_LAYOUT); grid->addWidget(cmb, 1, 1); l = new QLabel(i18n("Frame Shape:"), tab); l->setAlignment(Qt::AlignRight | Qt::AlignVCenter); grid->addWidget(l, 2, 0); KONFIGURATOR_NAME_VALUE_PAIR frameShape[] = { { i18nc("Frame shape", "Defined by Layout"), "default" }, { i18nc("Frame shape", "None"), "NoFrame" }, { i18nc("Frame shape", "Box"), "Box" }, { i18nc("Frame shape", "Panel"), "Panel" }, }; cmb = createComboBox("PanelLayout", "FrameShape", "default", frameShape, 4, tab, true, false, PAGE_LAYOUT); grid->addWidget(cmb, 2, 1); l = new QLabel(i18n("Frame Shadow:"), tab); l->setAlignment(Qt::AlignRight | Qt::AlignVCenter); grid->addWidget(l, 3, 0); KONFIGURATOR_NAME_VALUE_PAIR frameShadow[] = { { i18nc("Frame shadow", "Defined by Layout"), "default" }, { i18nc("Frame shadow", "None"), "Plain" }, { i18nc("Frame shadow", "Raised"), "Raised" }, { i18nc("Frame shadow", "Sunken"), "Sunken" }, }; cmb = createComboBox("PanelLayout", "FrameShadow", "default", frameShadow, 4, tab, true, false, PAGE_LAYOUT); grid->addWidget(cmb, 3, 1); } void KgPanel::setupView(KrViewInstance *instance, QWidget *parent) { QGridLayout *grid = createGridLayout(parent); // -------------------- Filelist icon size ---------------------------------- QHBoxLayout *hbox = new QHBoxLayout(); hbox->addWidget(new QLabel(i18n("Default icon size:"), parent)); KONFIGURATOR_NAME_VALUE_PAIR *iconSizes = new KONFIGURATOR_NAME_VALUE_PAIR[KrView::iconSizes.count()]; for(int i = 0; i < KrView::iconSizes.count(); i++) iconSizes[i].text = iconSizes[i].value = QString::number(KrView::iconSizes[i]); KonfiguratorComboBox *cmb = createComboBox(instance->name(), "IconSize", _FilelistIconSize, iconSizes, KrView::iconSizes.count(), parent, true, true, PAGE_VIEW); delete [] iconSizes; cmb->lineEdit()->setValidator(new QRegExpValidator(QRegExp("[1-9]\\d{0,1}"), cmb)); hbox->addWidget(cmb); hbox->addWidget(createSpacer(parent)); grid->addLayout(hbox, 1, 0); //-------------------------------------------------------------------- KONFIGURATOR_CHECKBOX_PARAM iconSettings[] = // cfg_class cfg_name default text restart tooltip { {instance->name(), "With Icons", _WithIcons, i18n("Use icons in the filenames"), true, i18n("Show the icons for filenames and folders.") }, {instance->name(), "ShowPreviews", false, i18n("Show previews by default"), false, i18n("Show previews of files and folders.") }, }; KonfiguratorCheckBoxGroup *iconSett = createCheckBoxGroup(2, 0, iconSettings, 2 /*count*/, parent, PAGE_VIEW); grid->addWidget(iconSett, 2, 0, 1, 2); } // ---------------------------------------------------------------------------------- // ---------------------------- VIEW TAB ------------------------------------------- // ---------------------------------------------------------------------------------- void KgPanel::setupPanelTab() { QScrollArea *scrollArea = new QScrollArea(tabWidget); QWidget *tab_panel = new QWidget(scrollArea); scrollArea->setFrameStyle(QFrame::NoFrame); scrollArea->setWidget(tab_panel); scrollArea->setWidgetResizable(true); tabWidget->addTab(scrollArea, i18n("View")); QGridLayout *panelLayout = new QGridLayout(tab_panel); panelLayout->setSpacing(6); panelLayout->setContentsMargins(11, 11, 11, 11); QGroupBox *panelGrp = createFrame(i18n("General"), tab_panel); panelLayout->addWidget(panelGrp, 0, 0); QGridLayout *panelGrid = createGridLayout(panelGrp); // ---------------------------------------------------------------------------------- // ---------------------------- General settings ----------------------------------- // ---------------------------------------------------------------------------------- // -------------------- Panel Font ---------------------------------- QHBoxLayout *hbox = new QHBoxLayout(); hbox->addWidget(new QLabel(i18n("View font:"), panelGrp)); KonfiguratorFontChooser * chsr = createFontChooser("Look&Feel", "Filelist Font", _FilelistFont, panelGrp, true, PAGE_VIEW); hbox->addWidget(chsr); hbox->addWidget(createSpacer(panelGrp)); panelGrid->addLayout(hbox, 1, 0); // -------------------- Misc options ---------------------------------- KONFIGURATOR_CHECKBOX_PARAM panelSettings[] = // cfg_class cfg_name default text restart tooltip { {"Look&Feel", "Human Readable Size", _HumanReadableSize, i18n("Use human-readable file size"), true , i18n("File sizes are displayed in B, KB, MB and GB, not just in bytes.") }, {"Look&Feel", "Show Hidden", _ShowHidden, i18n("Show hidden files"), false, i18n("Display files beginning with a dot.") }, {"Look&Feel", "Numeric permissions", _NumericPermissions, i18n("Numeric Permissions"), true, i18n("Show octal numbers (0755) instead of the standard permissions (rwxr-xr-x) in the permission column.") }, {"Look&Feel", "Load User Defined Folder Icons", _UserDefinedFolderIcons, i18n("Load the user defined folder icons"), true , i18n("Load the user defined folder icons (can cause decrease in performance).") }, }; KonfiguratorCheckBoxGroup *panelSett = createCheckBoxGroup(2, 0, panelSettings, 4 /*count*/, panelGrp, PAGE_VIEW); panelGrid->addWidget(panelSett, 3, 0, 1, 2); // ========================================================= panelGrid->addWidget(createLine(panelGrp), 4, 0); // ------------------------ Sort Method ---------------------------------- hbox = new QHBoxLayout(); hbox->addWidget(new QLabel(i18n("Sort method:"), panelGrp)); KONFIGURATOR_NAME_VALUE_PAIR sortMethods[] = {{ i18n("Alphabetical"), QString::number(KrViewProperties::Alphabetical) }, { i18n("Alphabetical and numbers"), QString::number(KrViewProperties::AlphabeticalNumbers) }, { i18n("Character code"), QString::number(KrViewProperties::CharacterCode) }, { i18n("Character code and numbers"), QString::number(KrViewProperties::CharacterCodeNumbers) }, { i18nc("Krusader sort", "Krusader"), QString::number(KrViewProperties::Krusader) } }; KonfiguratorComboBox *cmb = createComboBox("Look&Feel", "Sort method", QString::number(_DefaultSortMethod), sortMethods, 5, panelGrp, true, false, PAGE_VIEW); hbox->addWidget(cmb); hbox->addWidget(createSpacer(panelGrp)); panelGrid->addLayout(hbox, 5, 0); // ------------------------ Sort Options ---------------------------------- KONFIGURATOR_CHECKBOX_PARAM sortSettings[] = // cfg_class, cfg_name, default, text, restart, tooltip { {"Look&Feel", "Case Sensative Sort", _CaseSensativeSort, i18n("Case sensitive sorting"), true, i18n("All files beginning with capital letters appear before files beginning with non-capital letters (UNIX default).") }, {"Look&Feel", "Show Directories First", true, i18n("Show folders first"), true, 0 }, {"Look&Feel", "Always sort dirs by name", false, i18n("Always sort dirs by name"), true, i18n("Folders are sorted by name, regardless of the sort column.") }, {"Look&Feel", "Locale Aware Sort", true, i18n("Locale aware sorting"), true, i18n("The sorting is performed in a locale- and also platform-dependent manner. Can be slow.") }, }; KonfiguratorCheckBoxGroup *sortSett = createCheckBoxGroup(2, 0, sortSettings, 4 /*count*/, panelGrp, PAGE_VIEW); sortSett->find("Show Directories First")->addDep(sortSett->find("Always sort dirs by name")); panelGrid->addWidget(sortSett, 6, 0, 1, 2); // ---------------------------------------------------------------------------------- // ---------------------------- View modes ----------------------------------------- // ---------------------------------------------------------------------------------- panelGrp = createFrame(i18n("View modes"), tab_panel); panelLayout->addWidget(panelGrp, 1, 0); panelGrid = createGridLayout(panelGrp); // -------------------- Default Panel Type ---------------------------------- hbox = new QHBoxLayout(); hbox->addWidget(new QLabel(i18n("Default view mode:"), panelGrp)); QList views = KrViewFactory::registeredViews(); const int viewsSize = views.size(); KONFIGURATOR_NAME_VALUE_PAIR *panelTypes = new KONFIGURATOR_NAME_VALUE_PAIR[ viewsSize ]; QString defType = "0"; for (int i = 0; i != viewsSize; i++) { KrViewInstance * inst = views[ i ]; panelTypes[ i ].text = inst->description(); panelTypes[ i ].text.remove('&'); panelTypes[ i ].value = QString("%1").arg(inst->id()); if (inst->id() == KrViewFactory::defaultViewId()) defType = QString("%1").arg(inst->id()); } cmb = createComboBox("Look&Feel", "Default Panel Type", defType, panelTypes, viewsSize, panelGrp, false, false, PAGE_VIEW); hbox->addWidget(cmb); hbox->addWidget(createSpacer(panelGrp)); delete [] panelTypes; panelGrid->addLayout(hbox, 0, 0); // ----- Individual Settings Per View Type ------------------------ QTabWidget *tabs_view = new QTabWidget(panelGrp); panelGrid->addWidget(tabs_view, 11, 0); for(int i = 0; i < views.count(); i++) { QWidget *tab = new QWidget(tabs_view); tabs_view->addTab(tab, views[i]->description()); setupView(views[i], tab); } } // ----------------------------------------------------------------------------------- // -------------------------- Panel Toolbar TAB ---------------------------------- // ----------------------------------------------------------------------------------- void KgPanel::setupButtonsTab() { QScrollArea *scrollArea = new QScrollArea(tabWidget); QWidget *tab = new QWidget(scrollArea); scrollArea->setFrameStyle(QFrame::NoFrame); scrollArea->setWidget(tab); scrollArea->setWidgetResizable(true); tabWidget->addTab(scrollArea, i18n("Buttons")); QBoxLayout * tabLayout = new QVBoxLayout(tab); tabLayout->setSpacing(6); tabLayout->setContentsMargins(11, 11, 11, 11); KONFIGURATOR_CHECKBOX_PARAM buttonsParams[] = // cfg_class cfg_name default text restart tooltip { {"ListPanelButtons", "Icons", false, i18n("Toolbar buttons have icons"), true, "" }, {"Look&Feel", "Media Button Visible", true, i18n("Show Media Button"), true , i18n("The media button will be visible.") }, {"Look&Feel", "Back Button Visible", false, i18n("Show Back Button"), true , "Goes back in history." }, {"Look&Feel", "Forward Button Visible", false, i18n("Show Forward Button"), true , "Goes forward in history." }, {"Look&Feel", "History Button Visible", true, i18n("Show History Button"), true , i18n("The history button will be visible.") }, {"Look&Feel", "Bookmarks Button Visible", true, i18n("Show Bookmarks Button"), true , i18n("The bookmarks button will be visible.") }, {"Look&Feel", "Panel Toolbar visible", _PanelToolBar, i18n("Show Panel Toolbar"), true, i18n("The panel toolbar will be visible.") }, }; buttonsCheckboxes = createCheckBoxGroup(1, 0, buttonsParams, 7/*count*/, tab, PAGE_PANELTOOLBAR); connect(buttonsCheckboxes->find("Panel Toolbar visible"), SIGNAL(stateChanged(int)), this, SLOT(slotEnablePanelToolbar())); tabLayout->addWidget(buttonsCheckboxes, 0, 0); QGroupBox * panelToolbarGrp = createFrame(i18n("Visible Panel Toolbar buttons"), tab); QGridLayout * panelToolbarGrid = createGridLayout(panelToolbarGrp); KONFIGURATOR_CHECKBOX_PARAM panelToolbarButtonsParams[] = { // cfg_class cfg_name default text restart tooltip {"Look&Feel", "Equal Button Visible", _cdOther, i18n("Equal button (=)"), true , i18n("Changes the panel folder to the other panel folder.") }, {"Look&Feel", "Up Button Visible", _cdUp, i18n("Up button (..)"), true , i18n("Changes the panel folder to the parent folder.") }, {"Look&Feel", "Home Button Visible", _cdHome, i18n("Home button (~)"), true , i18n("Changes the panel folder to the home folder.") }, {"Look&Feel", "Root Button Visible", _cdRoot, i18n("Root button (/)"), true , i18n("Changes the panel folder to the root folder.") }, {"Look&Feel", "SyncBrowse Button Visible", _syncBrowseButton, i18n("Toggle-button for sync-browsing"), true , i18n("Each folder change in the panel is also performed in the other panel.") }, }; panelToolbarButtonsCheckboxes = createCheckBoxGroup(1, 0, panelToolbarButtonsParams, sizeof(panelToolbarButtonsParams) / sizeof(*panelToolbarButtonsParams), panelToolbarGrp, PAGE_PANELTOOLBAR); panelToolbarGrid->addWidget(panelToolbarButtonsCheckboxes, 0, 0); tabLayout->addWidget(panelToolbarGrp, 1, 0); // Enable panel toolbar checkboxes slotEnablePanelToolbar(); } // --------------------------------------------------------------------------- // -------------------------- Mouse TAB ---------------------------------- // --------------------------------------------------------------------------- void KgPanel::setupMouseModeTab() { QScrollArea *scrollArea = new QScrollArea(tabWidget); QWidget *tab_mouse = new QWidget(scrollArea); scrollArea->setFrameStyle(QFrame::NoFrame); scrollArea->setWidget(tab_mouse); scrollArea->setWidgetResizable(true); tabWidget->addTab(scrollArea, i18n("Selection Mode")); QGridLayout *mouseLayout = new QGridLayout(tab_mouse); mouseLayout->setSpacing(6); mouseLayout->setContentsMargins(11, 11, 11, 11); // -------------- General ----------------- QGroupBox *mouseGeneralGroup = createFrame(i18n("General"), tab_mouse); QGridLayout *mouseGeneralGrid = createGridLayout(mouseGeneralGroup); mouseGeneralGrid->setSpacing(0); mouseGeneralGrid->setContentsMargins(5, 5, 5, 5); KONFIGURATOR_NAME_VALUE_TIP mouseSelection[] = { // name value tooltip { i18n("Krusader Mode"), "0", i18n("Both keys allow selecting files. To select more than one file, hold the Ctrl key and click the left mouse button. Right-click menu is invoked using a short click on the right mouse button.") }, { i18n("Konqueror Mode"), "1", i18n("Pressing the left mouse button selects files - you can click and select multiple files. Right-click menu is invoked using a short click on the right mouse button.") }, { i18n("Total-Commander Mode"), "2", i18n("The left mouse button does not select, but sets the current file without affecting the current selection. The right mouse button selects multiple files and the right-click menu is invoked by pressing and holding the right mouse button.") }, { i18n("Ergonomic Mode"), "4", i18n("The left mouse button does not select, but sets the current file without affecting the current selection. The right mouse button invokes the context-menu. You can select with Ctrl key and the left button.") }, { i18n("Custom Selection Mode"), "3", i18n("Design your own selection mode.") } }; mouseRadio = createRadioButtonGroup("Look&Feel", "Mouse Selection", "0", 1, 5, mouseSelection, 5, mouseGeneralGroup, true, PAGE_MOUSE); mouseRadio->layout()->setContentsMargins(0, 0, 0, 0); mouseGeneralGrid->addWidget(mouseRadio, 0, 0); for (int i = 0; i != mouseRadio->count(); i++) connect(mouseRadio->find(i), SIGNAL(clicked()), SLOT(slotSelectionModeChanged())); mouseLayout->addWidget(mouseGeneralGroup, 0, 0); // -------------- Details ----------------- QGroupBox *mouseDetailGroup = createFrame(i18n("Details"), tab_mouse); QGridLayout *mouseDetailGrid = createGridLayout(mouseDetailGroup); mouseDetailGrid->setSpacing(0); mouseDetailGrid->setContentsMargins(5, 5, 5, 5); KONFIGURATOR_NAME_VALUE_TIP singleOrDoubleClick[] = { // name value tooltip { i18n("Double-click selects (classic)"), "0", i18n("A single click on a file will select and focus, a double click opens the file or steps into the folder.") }, { i18n("Obey global selection policy"), "1", i18n("

Use global setting:

Plasma System Settings -> Input Devices -> Mouse

") } }; KonfiguratorRadioButtons *clickRadio = createRadioButtonGroup("Look&Feel", "Single Click Selects", "0", 1, 0, singleOrDoubleClick, 2, mouseDetailGroup, true, PAGE_MOUSE); clickRadio->layout()->setContentsMargins(0, 0, 0, 0); mouseDetailGrid->addWidget(clickRadio, 0, 0); KONFIGURATOR_CHECKBOX_PARAM mouseCheckboxesParam[] = { // {cfg_class, cfg_name, default // text, restart, // tooltip } {"Custom Selection Mode", "QT Selection", _QtSelection, i18n("Based on KDE's selection mode"), true, i18n("If checked, use a mode based on KDE's style.") }, {"Custom Selection Mode", "Left Selects", _LeftSelects, i18n("Left mouse button selects"), true, i18n("If checked, left clicking an item will select it.") }, {"Custom Selection Mode", "Left Preserves", _LeftPreserves, i18n("Left mouse button preserves selection"), true, i18n("If checked, left clicking an item will select it, but will not unselect other, already selected items.") }, {"Custom Selection Mode", "ShiftCtrl Left Selects", _ShiftCtrlLeft, i18n("Shift/Ctrl-Left mouse button selects"), true, i18n("If checked, Shift/Ctrl left clicking will select items.\nNote: this is meaningless if 'Left Button Selects' is checked.") }, {"Custom Selection Mode", "Right Selects", _RightSelects, i18n("Right mouse button selects"), true, i18n("If checked, right clicking an item will select it.") }, {"Custom Selection Mode", "Right Preserves", _RightPreserves, i18n("Right mouse button preserves selection"), true, i18n("If checked, right clicking an item will select it, but will not unselect other, already selected items.") }, {"Custom Selection Mode", "ShiftCtrl Right Selects", _ShiftCtrlRight, i18n("Shift/Ctrl-Right mouse button selects"), true, i18n("If checked, Shift/Ctrl right clicking will select items.\nNote: this is meaningless if 'Right Button Selects' is checked.") }, {"Custom Selection Mode", "Space Moves Down", _SpaceMovesDown, i18n("Spacebar moves down"), true, i18n("If checked, pressing the spacebar will select the current item and move down.\nOtherwise, current item is selected, but remains the current item.") }, - {"Custom Selection Mode", "Space Calc Space", _SpaceCalcSpace, - i18n("Spacebar calculates disk space"), true, - i18n("If checked, pressing the spacebar while the current item is a folder, will (except from selecting the folder)\ncalculate space occupied of the folder (recursively).") }, {"Custom Selection Mode", "Insert Moves Down", _InsertMovesDown, i18n("Insert moves down"), true, i18n("If checked, pressing Insert will select the current item, and move down to the next item.\nOtherwise, current item is not changed.") }, {"Custom Selection Mode", "Immediate Context Menu", _ImmediateContextMenu, i18n("Right clicking pops context menu immediately"), true, i18n("If checked, right clicking will result in an immediate showing of the context menu.\nOtherwise, user needs to click and hold the right mouse button for 500ms.") }, }; - mouseCheckboxes = createCheckBoxGroup(1, 0, mouseCheckboxesParam, 11 /*count*/, mouseDetailGroup, PAGE_MOUSE); + mouseCheckboxes = createCheckBoxGroup(1, 0, mouseCheckboxesParam, 10 /*count*/, mouseDetailGroup, PAGE_MOUSE); mouseDetailGrid->addWidget(mouseCheckboxes, 1, 0); for (int i = 0; i < mouseCheckboxes->count(); i++) connect(mouseCheckboxes->find(i), SIGNAL(clicked()), SLOT(slotMouseCheckBoxChanged())); mouseLayout->addWidget(mouseDetailGroup, 0, 1, 2, 1); // Disable the details-button if not in custom-mode slotSelectionModeChanged(); // -------------- Preview ----------------- QGroupBox *mousePreviewGroup = createFrame(i18n("Preview"), tab_mouse); QGridLayout *mousePreviewGrid = createGridLayout(mousePreviewGroup); // TODO preview mousePreview = new KrTreeWidget(mousePreviewGroup); mousePreviewGrid->addWidget(mousePreview, 0 , 0); mousePreviewGroup->setEnabled(false); // TODO re-enable once the preview is implemented // ------------------------------------------ mouseLayout->addWidget(mousePreviewGroup, 1, 0); } // --------------------------------------------------------------------------- // -------------------------- Media Menu TAB ---------------------------------- // --------------------------------------------------------------------------- void KgPanel::setupMediaMenuTab() { QScrollArea *scrollArea = new QScrollArea(tabWidget); QWidget *tab = new QWidget(scrollArea); scrollArea->setFrameStyle(QFrame::NoFrame); scrollArea->setWidget(tab); scrollArea->setWidgetResizable(true); tabWidget->addTab(scrollArea, i18n("Media Menu")); QBoxLayout * tabLayout = new QVBoxLayout(tab); tabLayout->setSpacing(6); tabLayout->setContentsMargins(11, 11, 11, 11); KONFIGURATOR_CHECKBOX_PARAM mediaMenuParams[] = { // cfg_class cfg_name default text restart tooltip {"MediaMenu", "ShowPath", true, i18n("Show Mount Path"), false, 0 }, {"MediaMenu", "ShowFSType", true, i18n("Show File System Type"), false, 0 }, }; KonfiguratorCheckBoxGroup *mediaMenuCheckBoxes = createCheckBoxGroup(1, 0, mediaMenuParams, sizeof(mediaMenuParams) / sizeof(*mediaMenuParams), tab, PAGE_MEDIA_MENU); tabLayout->addWidget(mediaMenuCheckBoxes, 0, 0); QHBoxLayout *showSizeHBox = new QHBoxLayout(); showSizeHBox->addWidget(new QLabel(i18n("Show Size:"), tab)); KONFIGURATOR_NAME_VALUE_PAIR showSizeValues[] = { { i18nc("setting 'show size'", "Always"), "Always" }, { i18nc("setting 'show size'", "When Device has no Label"), "WhenNoLabel" }, { i18nc("setting 'show size'", "Never"), "Never" }, }; KonfiguratorComboBox *showSizeCmb = createComboBox("MediaMenu", "ShowSize", "Always", showSizeValues, sizeof(showSizeValues) / sizeof(*showSizeValues), tab, false, false, PAGE_MEDIA_MENU); showSizeHBox->addWidget(showSizeCmb); showSizeHBox->addStretch(); tabLayout->addLayout(showSizeHBox); tabLayout->addStretch(); } void KgPanel::slotDisable() { bool isNewStyleQuickSearch = quicksearchCheckboxes->find("New Style Quicksearch")->isChecked(); quicksearchCheckboxes->find("Case Sensitive Quicksearch")->setEnabled(isNewStyleQuickSearch); } void KgPanel::slotEnablePanelToolbar() { bool enableTB = buttonsCheckboxes->find("Panel Toolbar visible")->isChecked(); panelToolbarButtonsCheckboxes->find("Root Button Visible")->setEnabled(enableTB); panelToolbarButtonsCheckboxes->find("Home Button Visible")->setEnabled(enableTB); panelToolbarButtonsCheckboxes->find("Up Button Visible")->setEnabled(enableTB); panelToolbarButtonsCheckboxes->find("Equal Button Visible")->setEnabled(enableTB); panelToolbarButtonsCheckboxes->find("SyncBrowse Button Visible")->setEnabled(enableTB); } void KgPanel::slotSelectionModeChanged() { KrSelectionMode *selectionMode = KrSelectionMode::getSelectionHandlerForMode(mouseRadio->selectedValue()); if (selectionMode == NULL) //User mode return; selectionMode->init(); mouseCheckboxes->find("QT Selection")->setChecked(selectionMode->useQTSelection()); mouseCheckboxes->find("Left Selects")->setChecked(selectionMode->leftButtonSelects()); mouseCheckboxes->find("Left Preserves")->setChecked(selectionMode->leftButtonPreservesSelection()); mouseCheckboxes->find("ShiftCtrl Left Selects")->setChecked(selectionMode->shiftCtrlLeftButtonSelects()); mouseCheckboxes->find("Right Selects")->setChecked(selectionMode->rightButtonSelects()); mouseCheckboxes->find("Right Preserves")->setChecked(selectionMode->rightButtonPreservesSelection()); mouseCheckboxes->find("ShiftCtrl Right Selects")->setChecked(selectionMode->shiftCtrlRightButtonSelects()); mouseCheckboxes->find("Space Moves Down")->setChecked(selectionMode->spaceMovesDown()); - mouseCheckboxes->find("Space Calc Space")->setChecked(selectionMode->spaceCalculatesDiskSpace()); mouseCheckboxes->find("Insert Moves Down")->setChecked(selectionMode->insertMovesDown()); mouseCheckboxes->find("Immediate Context Menu")->setChecked(selectionMode->showContextMenu() == -1); } void KgPanel::slotMouseCheckBoxChanged() { mouseRadio->selectButton("3"); //custom selection mode } int KgPanel::activeSubPage() { return tabWidget->currentIndex(); } diff --git a/krusader/Panel/krcalcspacedialog.cpp b/krusader/Panel/krcalcspacedialog.cpp index 017e75b8..0f2d0667 100644 --- a/krusader/Panel/krcalcspacedialog.cpp +++ b/krusader/Panel/krcalcspacedialog.cpp @@ -1,234 +1,117 @@ /*************************************************************************** krcalcspacedialog.cpp - description ------------------- begin : Fri Jan 2 2004 copyright : (C) 2004 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 "krcalcspacedialog.h" // QtCore #include -#include // QtWidgets -#include +#include #include #include #include #include -#include -#include "krpanel.h" -#include "panelfunc.h" #include "../krglobal.h" -#include "../FileSystem/krpermhandler.h" -#include "../FileSystem/filesystemprovider.h" +#include "../FileSystem/sizecalculator.h" -/* --=={ Patch by Heiner }==-- */ -KrCalcSpaceDialog::CalcThread::CalcThread(QUrl url, const QStringList & items) - : m_totalSize(0), m_currentSize(0), m_totalFiles(0), m_totalDirs(0), m_items(items), m_url(url), - m_stop(false) {} +KrCalcSpaceDialog::KrCalcSpaceDialog(QWidget *parent, SizeCalculator *calculator) + : QDialog(parent), m_calculator(calculator) +{ + setWindowTitle(i18n("Calculate Occupied Space")); + QVBoxLayout *layout = new QVBoxLayout; + setLayout(layout); + layout->setSizeConstraint(QLayout::SetFixedSize); -void KrCalcSpaceDialog::CalcThread::getStats(KIO::filesize_t &totalSize, - unsigned long &totalFiles, - unsigned long &totalDirs) const -{ - QMutexLocker locker(&m_mutex); - totalSize = m_totalSize + m_currentSize; - totalFiles = m_totalFiles; - totalDirs = m_totalDirs; -} + m_label = new QLabel(this); + layout->addWidget(m_label); + layout->addStretch(10); -void KrCalcSpaceDialog::CalcThread::updateItems(KrView *view) const -{ - QMutexLocker locker(&m_mutex); - for (QStringList::const_iterator it = m_items.constBegin(); it != m_items.constEnd(); ++it) { - KrViewItem *viewItem = view->findItemByName(*it); - if (viewItem) { - viewItem->setSize(m_sizes[*it]); - viewItem->redraw(); - } - } -} + // buttons: Cancel is replaced with Ok when calculator is finished + m_buttonBox = new QDialogButtonBox(QDialogButtonBox::Cancel); + layout->addWidget(m_buttonBox); + connect(m_buttonBox, &QDialogButtonBox::rejected, this, &KrCalcSpaceDialog::slotCancel); + connect(m_buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); -void KrCalcSpaceDialog::CalcThread::run() -{ - if (!m_items.isEmpty()) { // if something to do: do the calculation - FileSystem *files = FileSystemProvider::instance().getFilesystem(m_url); - if(!files->refresh(m_url)) - return; - - for (QStringList::ConstIterator it = m_items.begin(); it != m_items.end(); ++it) { - files->calcSpace(*it, &m_currentSize, &m_totalFiles, &m_totalDirs , & m_stop); - - if (m_stop) - break; - - m_mutex.lock(); - m_sizes[*it] = m_currentSize; - m_totalSize += m_currentSize; - m_currentSize = 0; - m_mutex.unlock(); - } - delete files; - } + connect(m_calculator, &SizeCalculator::finished, this, &KrCalcSpaceDialog::slotCalculatorFinished); + + m_updateTimer = new QTimer(this); + connect(m_updateTimer, &QTimer::timeout, this, &KrCalcSpaceDialog::updateResult); + m_updateTimer->start(1000); + + updateResult(); } -void KrCalcSpaceDialog::CalcThread::stop() +void KrCalcSpaceDialog::showDialog(QWidget *parent, SizeCalculator *calculator) { - // cancel was pressed - m_stop = true; + KrCalcSpaceDialog *dialog = new KrCalcSpaceDialog(parent, calculator); + dialog->show(); } - -KrCalcSpaceDialog::KrCalcSpaceDialog(QWidget *parent, KrPanel * panel, const QStringList & items, bool autoclose) : - QDialog(parent), m_autoClose(autoclose), m_canceled(false), - m_timerCounter(0), m_items(items), m_view(panel->view) +void KrCalcSpaceDialog::slotCancel() { - setWindowTitle(i18n("Calculate Occupied Space")); - setWindowModality(Qt::WindowModal); + m_updateTimer->stop(); + m_calculator->cancel(); - QVBoxLayout *mainLayout = new QVBoxLayout; - setLayout(mainLayout); - - m_thread = new CalcThread(panel->virtualPath(), items); - m_pollTimer = new QTimer(this); - m_label = new QLabel("", this); - mainLayout->addWidget(m_label); - showResult(); // fill m_label with something useful - mainLayout->addStretch(10); - - 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); - // the dialog: The Ok button is hidden until it is needed - okButton->setVisible(false); - cancelButton = buttonBox->button(QDialogButtonBox::Cancel); - - connect(buttonBox, SIGNAL(accepted()), SLOT(accept())); - connect(buttonBox, SIGNAL(rejected()), SLOT(slotCancel())); + reject(); // close and delete this dialog } -void KrCalcSpaceDialog::calculationFinished() +void KrCalcSpaceDialog::slotCalculatorFinished() { - m_thread->updateItems(m_view); - // close dialog if auto close is true - if (m_autoClose) { - done(0); - return; - } - // otherwise hide cancel and show ok button - cancelButton->setVisible(false); - okButton->setVisible(true); - showResult(); // and show final result -} + m_buttonBox->clear(); + QPushButton *okButton = m_buttonBox->addButton(QDialogButtonBox::Ok); + okButton->setDefault(true); -/* This timer has two jobs: it polls the thread if it is finished. Polling is - better here as it might finish while the dialog builds up. Secondly it refreshes - the displayed result. - */ -void KrCalcSpaceDialog::timer() -{ - // thread finished? - if (m_thread->isFinished()) { - // close dialog or switch buttons - calculationFinished(); - m_pollTimer->stop(); // stop the polling. No longer needed - return; - } - - // Every 10 pollings (1 second) refresh the displayed result - if (++m_timerCounter > 10) { - m_timerCounter = 0; - showResult(); - m_thread->updateItems(m_view); - } + m_updateTimer->stop(); + updateResult(); } -void KrCalcSpaceDialog::showResult() +void KrCalcSpaceDialog::updateResult() { - if (!m_thread) - return; - KIO::filesize_t totalSize; - unsigned long totalFiles, totalDirs; + const KIO::filesize_t totalSize = m_calculator->totalSize(); + const unsigned long totalFiles = m_calculator->totalFiles(); + const unsigned long totalDirs = m_calculator->totalDirs(); - m_thread->getStats(totalSize, totalFiles, totalDirs); + const QList urls = m_calculator->urls(); + const QString fileName = + urls.count() == 1 ? i18n("Name: %1\n", urls.first().fileName()) : QString(""); - QString msg; - QString fileName = (m_items.count() == 1) ? i18n("Name: %1\n", m_items.first()) : QString(""); - msg = fileName + i18n("Total occupied space: %1", KIO::convertSize(totalSize)); + QString msg = fileName + i18n("Total occupied space: %1", KIO::convertSize(totalSize)); if (totalSize >= 1024) - msg += i18np(" (%1 byte)", " (%1 bytes)", KRpermHandler::parseSize(totalSize)); + msg += i18np(" (%2 byte)", " (%2 bytes)", totalSize, QLocale().toString(totalSize)); msg += '\n'; msg += i18np("in %1 folder", "in %1 folders", totalDirs); msg += ' '; msg += i18np("and %1 file", "and %1 files", totalFiles); m_label->setText(msg); } - -void KrCalcSpaceDialog::slotCancel() -{ - m_thread->stop(); // notify the thread to stop - m_canceled = true; // set the cancel flag - reject(); // close the dialog -} - -KrCalcSpaceDialog::~KrCalcSpaceDialog() -{ - if(m_thread->isFinished()) - delete m_thread; - else { - m_thread->stop(); - connect(m_thread, SIGNAL(finished()), m_thread, SLOT(deleteLater())); - } -} - -int KrCalcSpaceDialog::exec() -{ - m_thread->start(); // start the thread - if (m_autoClose) { // autoclose - // set the cursor to busy mode and wait 1 second or until the thread finishes - krMainWindow->setCursor(Qt::WaitCursor); - m_thread->wait(1000); - krMainWindow->setCursor(Qt::ArrowCursor); // return the cursor to normal mode - m_thread->updateItems(m_view); - if(m_thread->isFinished()) - return -1; // thread finished: do not show the dialog - showResult(); // fill the invisible dialog with useful data - } - // prepare and start the poll timer - connect(m_pollTimer, SIGNAL(timeout()), this, SLOT(timer())); - m_pollTimer->start(100); - return QDialog::exec(); // show the dialog -} -/* --=={ End of patch by Heiner }==-- */ - diff --git a/krusader/Panel/krcalcspacedialog.h b/krusader/Panel/krcalcspacedialog.h index 099d04db..16a5c06c 100644 --- a/krusader/Panel/krcalcspacedialog.h +++ b/krusader/Panel/krcalcspacedialog.h @@ -1,121 +1,74 @@ /*************************************************************************** krcalcspacedialog.h - description ------------------- begin : Fri Jan 2 2004 copyright : (C) 2004 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 KRCALCSPACEDIALOG_H #define KRCALCSPACEDIALOG_H -/* --=={ Patch by Heiner }==-- */ - // QtCore #include #include // QtWidgets #include +#include #include -#include "../FileSystem/filesystem.h" -class KrPanel; -class KrView; - +class SizeCalculator; /** - * Dialog calculating showing the number of files and directories and its total - * size in a dialog. If wanted, the dialog appears after 3 seconds of - * calculation, to avoid a short appearance if the result was found quickly. - * Computes the result in a different thread. + * Dialog showing the number of files and directories and its total size for a calculation. + * */ class KrCalcSpaceDialog : public QDialog { Q_OBJECT +public: + /** + * Create and show a dialog. If delayed is true the dialog is shown with a delay of 2 seconds + * to avoid a short appearance and is autoclosed when the calculation finished. + */ + static void showDialog(QWidget *parent, SizeCalculator *calculator); - friend class CalcThread; - class QTimer * m_pollTimer; - - class CalcThread : public QThread - { - KIO::filesize_t m_totalSize; - KIO::filesize_t m_currentSize; - unsigned long m_totalFiles; - unsigned long m_totalDirs; - const QStringList m_items; - QHash m_sizes; - QUrl m_url; - mutable QMutex m_mutex; - bool m_stop; - - public: - CalcThread(QUrl url, const QStringList & items); - - KIO::filesize_t getItemSize(QString item) const; - void updateItems(KrView *view) const; - void getStats(KIO::filesize_t &totalSize, - unsigned long &totalFiles, - unsigned long &totalDirs) const; - void run(); // start calculation - void stop(); // stop it. Thread continues until filesystem_calcSpace returns - } * m_thread; - - QLabel *m_label; - QPushButton *okButton; - QPushButton *cancelButton; - bool m_autoClose; // true: wait 3 sec. before showing the dialog. Close it, when done - bool m_canceled; // true: cancel was pressed - int m_timerCounter; // internal counter. The timer runs faster as the rehresh (see comment there) - const QStringList m_items; - KrView *m_view; - - void calculationFinished(); // called if the calculation is done - void showResult(); // show the current result in teh dialog - -protected slots: - void timer(); // poll timer was fired +private slots: void slotCancel(); // cancel was pressed + void slotCalculatorFinished(); + void updateResult(); // show the current result in the dialog -public: - // autoclose: wait 3 sec. before showing the dialog. Close it, when done - KrCalcSpaceDialog(QWidget *parent, KrPanel * panel, const QStringList & items, bool autoclose); - ~KrCalcSpaceDialog(); +private: + KrCalcSpaceDialog(QWidget *parent, SizeCalculator *calculator); + SizeCalculator *const m_calculator; - void getStats(KIO::filesize_t &totalSize, - unsigned long &totalFiles, - unsigned long &totalDirs) const { - m_thread->getStats(totalSize, totalFiles, totalDirs); - } - bool wasCanceled() const { - return m_canceled; - } // cancel was pressed; result is probably wrong + QLabel *m_label; + QDialogButtonBox *m_buttonBox; -public slots: - int exec() Q_DECL_OVERRIDE; // start calculation + QTimer *m_updateTimer; }; -/* End of patch by Heiner */ #endif diff --git a/krusader/Panel/krinterview.cpp b/krusader/Panel/krinterview.cpp index bb386362..d019d0c1 100644 --- a/krusader/Panel/krinterview.cpp +++ b/krusader/Panel/krinterview.cpp @@ -1,383 +1,395 @@ /***************************************************************************** * Copyright (C) 2002 Shie Erlich * * Copyright (C) 2002 Rafi Yanai * * 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 "krinterview.h" #include "krcolorcache.h" #include "krmousehandler.h" #include "krpreviews.h" #include "krvfsmodel.h" #include "krviewitem.h" #include "../FileSystem/dirlisterinterface.h" KrInterView::KrInterView(KrViewInstance &instance, KConfig *cfg, QAbstractItemView *itemView) : KrView(instance, cfg), _itemView(itemView), _mouseHandler(0) { _model = new KrVfsModel(this); // fix the context menu problem int j = QFontMetrics(_itemView->font()).height() * 2; _mouseHandler = new KrMouseHandler(this, j); } KrInterView::~KrInterView() { // any references to the model should be cleared ar this point, // but sometimes for some reason it is still referenced by // QPersistentModelIndex instances held by QAbstractItemView and/or QItemSelectionModel(child object) - // so schedule _model for later deletion _model->clear(); _model->deleteLater(); _model = 0; delete _mouseHandler; _mouseHandler = 0; QHashIterator< FileItem *, KrViewItem *> it(_itemHash); while (it.hasNext()) delete it.next().value(); _itemHash.clear(); } void KrInterView::selectRegion(KrViewItem *i1, KrViewItem *i2, bool select) { FileItem* file1 = (FileItem *)i1->getFileItem(); QModelIndex mi1 = _model->fileItemIndex(file1); FileItem* file2 = (FileItem *)i2->getFileItem(); QModelIndex mi2 = _model->fileItemIndex(file2); if (mi1.isValid() && mi2.isValid()) { int r1 = mi1.row(); int r2 = mi2.row(); if (r1 > r2) { int t = r1; r1 = r2; r2 = t; } op()->setMassSelectionUpdate(true); for (int row = r1; row <= r2; row++) setSelected(_model->fileItemAt(_model->index(row, 0)), select); op()->setMassSelectionUpdate(false); redraw(); } else if (mi1.isValid() && !mi2.isValid()) i1->setSelected(select); else if (mi2.isValid() && !mi1.isValid()) i2->setSelected(select); } void KrInterView::intSetSelected(const FileItem* item, bool select) { if(select) _selection.insert(item); else _selection.remove(item); } bool KrInterView::isSelected(const QModelIndex &ndx) { return isSelected(_model->fileItemAt(ndx)); } KrViewItem* KrInterView::findItemByName(const QString &name) { if (!_model->ready()) return 0; QModelIndex ndx = _model->nameIndex(name); if (!ndx.isValid()) return 0; return getKrViewItem(ndx); } +KrViewItem *KrInterView::findItemByUrl(const QUrl &url) +{ + if (!_model->ready()) + return 0; + + const QModelIndex ndx = _model->indexFromUrl(url); + if (!ndx.isValid()) + return 0; + + return getKrViewItem(ndx); +} + QString KrInterView::getCurrentItem() const { if (!_model->ready()) return QString(); FileItem *fileitem = _model->fileItemAt(_itemView->currentIndex()); if (fileitem == 0) return QString(); return fileitem->getName(); } KrViewItem* KrInterView::getCurrentKrViewItem() { if (!_model->ready()) return 0; return getKrViewItem(_itemView->currentIndex()); } KrViewItem* KrInterView::getFirst() { if (!_model->ready()) return 0; return getKrViewItem(_model->index(0, 0, QModelIndex())); } KrViewItem* KrInterView::getLast() { if (!_model->ready()) return 0; return getKrViewItem(_model->index(_model->rowCount() - 1, 0, QModelIndex())); } KrViewItem* KrInterView::getNext(KrViewItem *current) { FileItem* fileItem = (FileItem *)current->getFileItem(); QModelIndex ndx = _model->fileItemIndex(fileItem); if (ndx.row() >= _model->rowCount() - 1) return 0; return getKrViewItem(_model->index(ndx.row() + 1, 0, QModelIndex())); } KrViewItem* KrInterView::getPrev(KrViewItem *current) { FileItem* fileItem = (FileItem *)current->getFileItem(); QModelIndex ndx = _model->fileItemIndex(fileItem); if (ndx.row() <= 0) return 0; return getKrViewItem(_model->index(ndx.row() - 1, 0, QModelIndex())); } KrViewItem* KrInterView::getKrViewItemAt(const QPoint &vp) { if (!_model->ready()) return 0; return getKrViewItem(_itemView->indexAt(vp)); } KrViewItem *KrInterView::findItemByFileItem(FileItem *fileItem) { return getKrViewItem(fileItem); } KrViewItem * KrInterView::getKrViewItem(FileItem *fileItem) { QHash::iterator it = _itemHash.find(fileItem); if (it == _itemHash.end()) { KrViewItem * newItem = new KrViewItem(fileItem, this); _itemHash[ fileItem ] = newItem; return newItem; } return *it; } KrViewItem * KrInterView::getKrViewItem(const QModelIndex & ndx) { if (!ndx.isValid()) return 0; FileItem * fileitem = _model->fileItemAt(ndx); if (fileitem == 0) return 0; else return getKrViewItem(fileitem); } void KrInterView::makeCurrentVisible() { _itemView->scrollTo(_itemView->currentIndex()); } void KrInterView::makeItemVisible(const KrViewItem *item) { if (item == 0) return; FileItem* fileitem = (FileItem *)item->getFileItem(); QModelIndex ndx = _model->fileItemIndex(fileitem); if (ndx.isValid()) _itemView->scrollTo(ndx); } bool KrInterView::isItemVisible(const KrViewItem *item) { return _itemView->viewport()->rect().contains(item->itemRect()); } void KrInterView::setCurrentItem(const QString& name, const QModelIndex &fallbackToIndex) { // find index by given name and set it as current QModelIndex ndx = _model->nameIndex(name); if (ndx.isValid()) { // also sets the scrolling position _itemView->setCurrentIndex(ndx); } else if (fallbackToIndex.isValid()) { // set fallback index as current index // when fallback index is too big, set the last item as current if (fallbackToIndex.row() >= _itemView->model()->rowCount()) { setCurrentKrViewItem(getLast()); } else { _itemView->setCurrentIndex(fallbackToIndex); } } else { // when given parameters fail, set the first item as current setCurrentKrViewItem(getFirst()); } } void KrInterView::setCurrentKrViewItem(KrViewItem *item) { if (item == 0) { _itemView->setCurrentIndex(QModelIndex()); return; } FileItem* fileitem = (FileItem *)item->getFileItem(); QModelIndex ndx = _model->fileItemIndex(fileitem); if (ndx.isValid() && ndx.row() != _itemView->currentIndex().row()) { _mouseHandler->cancelTwoClickRename(); _itemView->setCurrentIndex(ndx); } } void KrInterView::sort() { _model->sort(); } void KrInterView::clear() { _selection.clear(); _itemView->clearSelection(); _itemView->setCurrentIndex(QModelIndex()); _model->clear(); QHashIterator< FileItem *, KrViewItem *> it(_itemHash); while (it.hasNext()) delete it.next().value(); _itemHash.clear(); KrView::clear(); } void KrInterView::populate(const QList &fileItems, FileItem *dummy) { _model->populate(fileItems, dummy); } KrViewItem* KrInterView::preAddItem(FileItem *fileitem) { QModelIndex idx = _model->addItem(fileitem); if(_model->rowCount() == 1) // if this is the fist item to be added, make it current _itemView->setCurrentIndex(idx); return getKrViewItem(idx); } void KrInterView::preDelItem(KrViewItem *item) { setSelected(item->getFileItem(), false); QModelIndex ndx = _model->removeItem((FileItem *)item->getFileItem()); if (ndx.isValid()) _itemView->setCurrentIndex(ndx); _itemHash.remove((FileItem *)item->getFileItem()); } void KrInterView::preUpdateItem(FileItem *fileitem) { _model->updateItem(fileitem); } void KrInterView::prepareForActive() { _focused = true; _itemView->setFocus(); } void KrInterView::prepareForPassive() { _focused = false; _mouseHandler->cancelTwoClickRename(); //if ( renameLineEdit() ->isVisible() ) //renameLineEdit() ->clearFocus(); } void KrInterView::redraw() { _itemView->viewport()->update(); } void KrInterView::refreshColors() { QPalette p(_itemView->palette()); KrColorGroup cg; KrColorCache::getColorCache().getColors(cg, KrColorItemType(KrColorItemType::File, false, _focused, false, false)); p.setColor(QPalette::Text, cg.text()); p.setColor(QPalette::Base, cg.background()); _itemView->setPalette(p); redraw(); } void KrInterView::showContextMenu(const QPoint &point) { showContextMenu(_itemView->viewport()->mapToGlobal(point)); } void KrInterView::sortModeUpdated(int column, Qt::SortOrder order) { KrView::sortModeUpdated(static_cast(column), order == Qt::DescendingOrder); } KIO::filesize_t KrInterView::calcSize() { KIO::filesize_t size = 0; foreach(FileItem *fileitem, _model->fileItems()) { size += fileitem->getSize(); } return size; } KIO::filesize_t KrInterView::calcSelectedSize() { KIO::filesize_t size = 0; foreach(const FileItem *fileitem, _selection) { size += fileitem->getSize(); } return size; } QList KrInterView::selectedUrls() { QList list; foreach(const FileItem *fileitem, _selection) { list << fileitem->getUrl(); } return list; } void KrInterView::setSelectionUrls(const QList urls) { op()->setMassSelectionUpdate(true); _selection.clear(); foreach(const QUrl &url, urls) { const QModelIndex idx = _model->indexFromUrl(url); if(idx.isValid()) setSelected(_model->fileItemAt(idx), true); } op()->setMassSelectionUpdate(false); } diff --git a/krusader/Panel/krinterview.h b/krusader/Panel/krinterview.h index 067837d5..2c938ea6 100644 --- a/krusader/Panel/krinterview.h +++ b/krusader/Panel/krinterview.h @@ -1,118 +1,119 @@ /***************************************************************************** * Copyright (C) 2002 Shie Erlich * * Copyright (C) 2002 Rafi Yanai * * 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 * *****************************************************************************/ #ifndef KRINTERVIEW_H #define KRINTERVIEW_H // QtCore #include // QtWidgets #include #include "krview.h" class KrVfsModel; class KrMouseHandler; class KrViewItem; /** * @brief Abstract intermediate class between KrView and full view implementations. * * It contains the methods common to all implementing subclasses of KrView. */ class KrInterView : public KrView { friend class KrViewItem; public: KrInterView(KrViewInstance &instance, KConfig *cfg, QAbstractItemView *itemView); virtual ~KrInterView(); QModelIndex getCurrentIndex() Q_DECL_OVERRIDE { return _itemView->currentIndex(); } bool isSelected(const QModelIndex &ndx) Q_DECL_OVERRIDE; uint numSelected() const Q_DECL_OVERRIDE { return _selection.count(); } QList selectedUrls() Q_DECL_OVERRIDE; void setSelectionUrls(const QList urls) Q_DECL_OVERRIDE; KrViewItem* getFirst() Q_DECL_OVERRIDE; KrViewItem* getLast() Q_DECL_OVERRIDE; KrViewItem* getNext(KrViewItem *current) Q_DECL_OVERRIDE; KrViewItem* getPrev(KrViewItem *current) Q_DECL_OVERRIDE; KrViewItem* getCurrentKrViewItem() Q_DECL_OVERRIDE; KrViewItem* findItemByName(const QString &name) Q_DECL_OVERRIDE; KrViewItem *findItemByFileItem(FileItem *fileitem) Q_DECL_OVERRIDE; + KrViewItem *findItemByUrl(const QUrl &url) Q_DECL_OVERRIDE; QString getCurrentItem() const Q_DECL_OVERRIDE; KrViewItem* getKrViewItemAt(const QPoint &vp) Q_DECL_OVERRIDE; void setCurrentItem(const QString& name, const QModelIndex &fallbackToIndex=QModelIndex()) Q_DECL_OVERRIDE; void setCurrentKrViewItem(KrViewItem *item) Q_DECL_OVERRIDE; void makeItemVisible(const KrViewItem *item) Q_DECL_OVERRIDE; bool isItemVisible(const KrViewItem *item) Q_DECL_OVERRIDE; void clear() Q_DECL_OVERRIDE; void sort() Q_DECL_OVERRIDE; void refreshColors() Q_DECL_OVERRIDE; void redraw() Q_DECL_OVERRIDE; void prepareForActive() Q_DECL_OVERRIDE; void prepareForPassive() Q_DECL_OVERRIDE; void showContextMenu(const QPoint & point = QPoint(0,0)) Q_DECL_OVERRIDE; void selectRegion(KrViewItem *i1, KrViewItem *i2, bool select) Q_DECL_OVERRIDE; void sortModeUpdated(int column, Qt::SortOrder order); void redrawItem(FileItem *fileitem) { _itemView->viewport()->update(itemRect(fileitem)); } protected: class DummySelectionModel : public QItemSelectionModel { public: DummySelectionModel(QAbstractItemModel *model, QObject *parent) : QItemSelectionModel(model, parent) {} // do nothing - selection is managed by KrInterView void select(const QModelIndex &, QItemSelectionModel::SelectionFlags) Q_DECL_OVERRIDE {} void select(const QItemSelection &, QItemSelectionModel::SelectionFlags) Q_DECL_OVERRIDE {} }; KIO::filesize_t calcSize() Q_DECL_OVERRIDE; KIO::filesize_t calcSelectedSize() Q_DECL_OVERRIDE; void populate(const QList &fileItems, FileItem *dummy) Q_DECL_OVERRIDE; KrViewItem* preAddItem(FileItem *fileitem) Q_DECL_OVERRIDE; void preDelItem(KrViewItem *item) Q_DECL_OVERRIDE; void preUpdateItem(FileItem *fileitem) Q_DECL_OVERRIDE; void intSetSelected(const FileItem* fileitem, bool select) Q_DECL_OVERRIDE; virtual QRect itemRect(const FileItem *fileitem) = 0; KrViewItem * getKrViewItem(FileItem *fileitem); KrViewItem * getKrViewItem(const QModelIndex &); bool isSelected(const FileItem *fileitem) const { return _selection.contains(fileitem); } void makeCurrentVisible(); KrVfsModel *_model; QAbstractItemView *_itemView; KrMouseHandler *_mouseHandler; QHash _itemHash; QSet _selection; }; #endif diff --git a/krusader/Panel/krselectionmode.cpp b/krusader/Panel/krselectionmode.cpp index 19c50093..344d0a42 100644 --- a/krusader/Panel/krselectionmode.cpp +++ b/krusader/Panel/krselectionmode.cpp @@ -1,99 +1,98 @@ /***************************************************************************** * 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 "krselectionmode.h" #include "../krglobal.h" #include "../defaults.h" #include static KrSelectionMode *__currentSelectionMode = 0; // uninitiated, at first KonqSelectionMode konqSelectionMode; OriginalSelectionMode originalSelectionMode; TCSelectionMode tcSelectionMode; ErgonomicSelectionMode ergonomicSelectionMode; UserSelectionMode userSelectionMode; KrSelectionMode* KrSelectionMode::getSelectionHandlerForMode(const QString &mode) { KrSelectionMode *res = NULL; bool isNum; int modenum = mode.toInt(&isNum); switch (modenum) { case 0: res = &originalSelectionMode; break; case 1: res = &konqSelectionMode; break; case 2: res = &tcSelectionMode; break; case 3: //costom mode break; case 4: res = &ergonomicSelectionMode; break; default: break; } return res; } KrSelectionMode* KrSelectionMode::getSelectionHandler() { if (__currentSelectionMode) { // don't check krConfig every time return __currentSelectionMode; } else { // nothing yet, set the correct one KConfigGroup group(krConfig, "Look&Feel"); QString mode = group.readEntry("Mouse Selection", QString("")); __currentSelectionMode = getSelectionHandlerForMode(mode); if (__currentSelectionMode == NULL) { __currentSelectionMode = &userSelectionMode; } // init and return __currentSelectionMode->init(); return __currentSelectionMode; } } void KrSelectionMode::resetSelectionHandler() { __currentSelectionMode = 0; } void UserSelectionMode::init() { KConfigGroup group(krConfig, "Custom Selection Mode"); _useQTSelection = group.readEntry("QT Selection", _QtSelection); _leftButtonSelects = group.readEntry("Left Selects", _LeftSelects); _leftButtonPreservesSelection = group.readEntry("Left Preserves", _LeftPreserves); _shiftCtrlLeftButtonSelects = group.readEntry("ShiftCtrl Left Selects", _ShiftCtrlLeft); _rightButtonSelects = group.readEntry("Right Selects", _RightSelects); _rightButtonPreservesSelection = group.readEntry("Right Preserves", _RightPreserves); _shiftCtrlRightButtonSelects = group.readEntry("ShiftCtrl Right Selects", _ShiftCtrlRight); _spaceMovesDown = group.readEntry("Space Moves Down", _SpaceMovesDown); - _spaceCalculatesDiskSpace = group.readEntry("Space Calc Space", _SpaceCalcSpace); _insertMovesDown = group.readEntry("Insert Moves Down", _InsertMovesDown); _showContextMenu = (group.readEntry("Immediate Context Menu", _ImmediateContextMenu) ? -1 : 500); } diff --git a/krusader/Panel/krselectionmode.h b/krusader/Panel/krselectionmode.h index 37dba7cb..ade896c5 100644 --- a/krusader/Panel/krselectionmode.h +++ b/krusader/Panel/krselectionmode.h @@ -1,165 +1,158 @@ /***************************************************************************** * 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 * *****************************************************************************/ #ifndef KRSELECTIONMODE_H #define KRSELECTIONMODE_H // QtCore #include /** Every selection mode inherits this class, and has to implement init(). Usage: KrSelectionMode::getSelectionHandler()->whateverFunctionYouNeed() \note You can call KrSelectionMode::resetSelectionHandler() if you want the selection mode to be re-read. This is useful after a configuration where you changed the selection mode. calling resetSelectionHandler() will cause the next call to getSelectionHandler() to (possibly) select a different mode. */ class KrSelectionMode { public: static KrSelectionMode * getSelectionHandlerForMode(const QString &mode); static KrSelectionMode * getSelectionHandler(); static void resetSelectionHandler(); virtual void init() = 0; // everyone must implement this in order to be a selection mode inline bool useQTSelection() { return _useQTSelection; } inline bool spaceMovesDown() { return _spaceMovesDown; } inline bool insertMovesDown() { return _insertMovesDown; } - inline bool spaceCalculatesDiskSpace() { - return _spaceCalculatesDiskSpace; - } inline bool rightButtonSelects() { return _rightButtonSelects; } inline bool leftButtonSelects() { return _leftButtonSelects; } inline bool rightButtonPreservesSelection() { return _rightButtonPreservesSelection; } inline bool leftButtonPreservesSelection() { return _leftButtonPreservesSelection; } inline bool shiftCtrlRightButtonSelects() { return _shiftCtrlRightButtonSelects; } inline bool shiftCtrlLeftButtonSelects() { return _shiftCtrlLeftButtonSelects; } inline int showContextMenu() { return _showContextMenu; } // 0: no, -1: yes, n>0: after n milliseconds virtual ~KrSelectionMode() {} protected: - bool _useQTSelection, _spaceMovesDown, _insertMovesDown, _spaceCalculatesDiskSpace; + bool _useQTSelection, _spaceMovesDown, _insertMovesDown; bool _rightButtonSelects, _leftButtonSelects, _rightButtonPreservesSelection; bool _leftButtonPreservesSelection, _shiftCtrlRightButtonSelects, _shiftCtrlLeftButtonSelects; int _showContextMenu; }; class KonqSelectionMode : public KrSelectionMode { public: void init() Q_DECL_OVERRIDE { _useQTSelection = true; _spaceMovesDown = false; _insertMovesDown = true; - _spaceCalculatesDiskSpace = false; _rightButtonSelects = true; _leftButtonSelects = true; _rightButtonPreservesSelection = false; _leftButtonPreservesSelection = false; _shiftCtrlRightButtonSelects = false; _shiftCtrlLeftButtonSelects = false; _showContextMenu = -1; } }; class OriginalSelectionMode : public KrSelectionMode { public: void init() Q_DECL_OVERRIDE { _useQTSelection = false; _spaceMovesDown = true; _insertMovesDown = true; - _spaceCalculatesDiskSpace = true; _rightButtonSelects = true; _leftButtonSelects = true; _rightButtonPreservesSelection = false; _leftButtonPreservesSelection = false; _shiftCtrlRightButtonSelects = false; _shiftCtrlLeftButtonSelects = false; _showContextMenu = -1; } }; class TCSelectionMode : public KrSelectionMode { public: void init() Q_DECL_OVERRIDE { _useQTSelection = false; _spaceMovesDown = false; _insertMovesDown = true; - _spaceCalculatesDiskSpace = true; _rightButtonSelects = true; _leftButtonSelects = false; _rightButtonPreservesSelection = true; _leftButtonPreservesSelection = false; _shiftCtrlRightButtonSelects = false; _shiftCtrlLeftButtonSelects = true; _showContextMenu = 500; } }; class ErgonomicSelectionMode : public KrSelectionMode { public: void init() Q_DECL_OVERRIDE { _useQTSelection = false; _spaceMovesDown = false; _insertMovesDown = true; - _spaceCalculatesDiskSpace = true; _rightButtonSelects = false; _leftButtonSelects = false; _rightButtonPreservesSelection = true; _leftButtonPreservesSelection = true; _shiftCtrlRightButtonSelects = false; _shiftCtrlLeftButtonSelects = true; _showContextMenu = -1; } }; class UserSelectionMode: public KrSelectionMode { public: void init() Q_DECL_OVERRIDE; }; #endif // KR_SELECTION_MODE_H diff --git a/krusader/Panel/krview.cpp b/krusader/Panel/krview.cpp index fe00ceb1..4408f18a 100644 --- a/krusader/Panel/krview.cpp +++ b/krusader/Panel/krview.cpp @@ -1,1161 +1,1157 @@ /*************************************************************************** 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 "viewactions.h" #include "krviewfactory.h" #include "krviewitem.h" #include "krselectionmode.h" #include "krcolorcache.h" #include "krpreviews.h" #include "../kicons.h" #include "../krglobal.h" #include "../defaults.h" #include "../FileSystem/krpermhandler.h" #include "../FileSystem/dirlisterinterface.h" #include "../Filter/filterdialog.h" // QtCore #include // QtGui #include #include #include #include // QtWidgets #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 *fileitem) { _view->updateItem(fileitem); } 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() { _properties = createViewProperties(); KConfigGroup grpSvr(_config, "Look&Feel"); KConfigGroup grpInstance(_config, _instance.name()); _properties->displayIcons = grpInstance.readEntry("With Icons", _WithIcons); _properties->numericPermissions = grpSvr.readEntry("Numeric permissions", _NumericPermissions); int sortOptions = _properties->sortOptions; if (grpSvr.readEntry("Show Directories First", true)) sortOptions |= KrViewProperties::DirsFirst; if(grpSvr.readEntry("Always sort dirs by name", false)) sortOptions |= KrViewProperties::AlwaysSortDirsByName; if (!grpSvr.readEntry("Case Sensative Sort", _CaseSensativeSort)) sortOptions |= KrViewProperties::IgnoreCase; if (grpSvr.readEntry("Locale Aware Sort", true)) sortOptions |= KrViewProperties::LocaleAwareSort; _properties->sortOptions = static_cast(sortOptions); _properties->sortMethod = static_cast( grpSvr.readEntry("Sort method", (int) _DefaultSortMethod)); _properties->humanReadableSize = grpSvr.readEntry("Human Readable Size", _HumanReadableSize); _properties->localeAwareCompareIsCaseSensitive = QString("a").localeAwareCompare("B") > 0; // see KDE bug #40131 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->atomicExtensions = 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 ignoreJustFocused) { for (KrViewItem * it = getFirst(); it != 0; it = getNext(it)) if (it->isSelected() && (it->name() != "..")) names->append(it->name()); // if all else fails, take the current item if (!ignoreJustFocused) { 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 *fileitem) { if (isFiltered(fileitem)) delItem(fileitem->getName()); else { preUpdateItem(fileitem); if(_previews) _previews->updatePreview(findItemByFileItem(fileitem)); } op()->emitSelectionChanged(); } void KrView::clear() { if(_previews) _previews->clear(); _count = _numDirs = 0; delete _dummyFileItem; _dummyFileItem = 0; redraw(); } bool KrView::handleKeyEvent(QKeyEvent *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 : // kill file op()->emitDeleteFiles(e->modifiers() == Qt::ShiftModifier || e->modifiers() == Qt::ControlModifier); 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->name() != ".." && viewItem->getFileItem()->isDir() && viewItem->getFileItem()->getSize() <= 0 && - KrSelectionMode::getSelectionHandler()->spaceCalculatesDiskSpace()) { - op()->emitCalcSpace(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); } 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::krPermissionString(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; } 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, SIGNAL(refreshDone(bool)), op(), SLOT(startUpdate())); QObject::connect(_files, SIGNAL(cleared()), op(), SLOT(cleared())); QObject::connect(_files, SIGNAL(addedFileItem(FileItem*)), op(), SLOT(fileAdded(FileItem*))); QObject::connect(_files, SIGNAL(updatedFileItem(FileItem*)), op(), SLOT(fileUpdated(FileItem*))); } 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/krview.h b/krusader/Panel/krview.h index 56591ea5..0faf7888 100644 --- a/krusader/Panel/krview.h +++ b/krusader/Panel/krview.h @@ -1,445 +1,444 @@ /*************************************************************************** krview.h ------------------- 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 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 KRVIEW_H #define KRVIEW_H // QtCore #include #include #include #include #include #include // QtGui #include #include #include "../Filter/filtersettings.h" #include "../FileSystem/krquery.h" #define MAX_BRIEF_COLS 5 class KrView; class KrViewItem; class KrPreviews; class KrViewInstance; class DirListerInterface; typedef QList KrViewItemList; // KrViewProperties // This class is an interface class between KrView and KrViewItem // In order for KrViewItem to be as independent as possible, KrView holds // an instance of this class, and fills it with the correct data. A reference // to this should be given to each KrViewItem, which then queries it for // information regarding how things should be displayed in the current view. // // Every property that the item needs to know about the view must be here! class KrViewProperties { public: KrViewProperties() : numericPermissions(false), displayIcons(false), sortColumn(Name), sortOptions(static_cast(0)), sortMethod(Alphabetical), filter(KrViewProperties::All), filterMask(KRQuery("*")), filterApplysToDirs(false), localeAwareCompareIsCaseSensitive(false), humanReadableSize(), numberOfColumns(1) { } enum PropertyType { NoProperty = 0x0, PropIconSize = 0x1, PropShowPreviews = 0x2, PropSortMode = 0x4, PropColumns = 0x8, PropFilter = 0x10, AllProperties = PropIconSize | PropShowPreviews | PropSortMode | PropColumns | PropFilter }; enum ColumnType { NoColumn = -1, Name = 0x0, Ext = 0x1, Size = 0x2, Type = 0x3, Modified = 0x4, Permissions = 0x5, KrPermissions = 0x6, Owner = 0x7, Group = 0x8, MAX_COLUMNS = 0x09 }; enum SortOptions { Descending = 0x200, DirsFirst = 0x400, IgnoreCase = 0x800, AlwaysSortDirsByName = 0x1000, LocaleAwareSort = 0x2000 }; enum SortMethod { Alphabetical = 0x1, AlphabeticalNumbers = 0x2, CharacterCode = 0x4, CharacterCodeNumbers = 0x8, Krusader = 0x10 }; enum FilterSpec { Dirs = 0x1, Files = 0x2, All = 0x3, Custom = 0x4 }; bool numericPermissions; // show full permission column as octal numbers bool displayIcons; // true if icons should be displayed in this view ColumnType sortColumn; SortOptions sortOptions; SortMethod sortMethod; // sort method for names and extensions FilterSpec filter; // what items to show (all, custom, exec) KRQuery filterMask; // what items to show (*.cpp, *.h etc) FilterSettings filterSettings; bool filterApplysToDirs; bool localeAwareCompareIsCaseSensitive; // mostly, it is not! depends on LC_COLLATE bool humanReadableSize; // display size as KB, MB or just as a long number QStringList atomicExtensions; // list of strings, which will be treated as one extension. Must // start with a dot. int numberOfColumns; // the number of columns in the brief view }; // operator can handle two ways of doing things: // 1. if the view is a widget (inherits krview and klistview for example) // 2. if the view HAS A widget (a krview-son has a member of klistview) // this is done by specifying the view and the widget in the constructor, // even if they are actually the same object (specify it twice in that case) class KrViewOperator : public QObject { Q_OBJECT public: KrViewOperator(KrView *view, QWidget *widget); ~KrViewOperator(); KrView *view() const { return _view; } QWidget *widget() const { return _widget; } void startDrag(); void emitGotDrop(QDropEvent *e) { emit gotDrop(e); } void emitLetsDrag(QStringList items, QPixmap icon) { emit letsDrag(items, icon); } void emitItemDescription(const QString &desc) { emit itemDescription(desc); } void emitContextMenu(const QPoint &point) { emit contextMenu(point); } void emitEmptyContextMenu(const QPoint &point) { emit emptyContextMenu(point); } void emitRenameItem(const QString &oldName, const QString &newName) { emit renameItem(oldName, newName); } void emitExecuted(const QString &name) { emit executed(name); } void emitGoInside(const QString &name) { emit goInside(name); } void emitNeedFocus() { emit needFocus(); } void emitMiddleButtonClicked(KrViewItem *item) { emit middleButtonClicked(item); } void emitCurrentChanged(KrViewItem *item) { emit currentChanged(item); } void emitPreviewJobStarted(KJob *job) { emit previewJobStarted(job); } void emitGoHome() { emit goHome(); } void emitDirUp() { emit dirUp(); } void emitDeleteFiles(bool reallyDelete) { emit deleteFiles(reallyDelete); } - void emitCalcSpace(KrViewItem *item) { emit calcSpace(item); } void emitRefreshActions() { emit refreshActions(); } void emitGoBack() { emit goBack(); } void emitGoForward() { emit goForward(); } bool searchItem(const QString &, bool, int = 0); // search for item and set cursor bool filterSearch(const QString &, bool); // filter view items void setMassSelectionUpdate(bool upd); bool isMassSelectionUpdate() { return _massSelectionUpdate; } void settingsChanged(KrViewProperties::PropertyType properties); public slots: void emitSelectionChanged() { if (!_massSelectionUpdate) emit selectionChanged(); } signals: void selectionChanged(); void gotDrop(QDropEvent *e); void letsDrag(QStringList items, QPixmap icon); void itemDescription(const QString &desc); void contextMenu(const QPoint &point); void emptyContextMenu(const QPoint &point); void renameItem(const QString &oldName, const QString &newName); void executed(const QString &name); void goInside(const QString &name); void needFocus(); void middleButtonClicked(KrViewItem *item); void currentChanged(KrViewItem *item); void previewJobStarted(KJob *job); void goHome(); void deleteFiles(bool reallyDelete); void dirUp(); - void calcSpace(KrViewItem *item); void refreshActions(); void goBack(); void goForward(); protected slots: void saveDefaultSettings(); void startUpdate(); void cleared(); void fileAdded(FileItem *fileitem); void fileUpdated(FileItem *fileitem); protected: // never delete those KrView *_view; QWidget *_widget; private: bool _massSelectionUpdate; QTimer _saveDefaultSettingsTimer; static KrViewProperties::PropertyType _changedProperties; static KrView *_changedView; }; /**************************************************************************** * READ THIS FIRST: Using the view * * You always hold a pointer to KrView, thus you can only use functions declared * in this class. If you need something else, either this class is missing something * or you are ;-) * * The functions you'd usually want: * 1) getSelectedItems - returns all selected items, or (if none) the current item. * it never returns anything which includes the "..", and thus can return an empty list! * 2) getSelectedKrViewItems - the same as (1), but returns a QValueList with KrViewItems * 3) getCurrentItem, setCurrentItem - work with QString * 4) getFirst, getNext, getPrev, getCurrentKrViewItem - all work with KrViewItems, and * used to iterate through a list of items. note that getNext and getPrev accept a pointer * to the current item (used in detailedview for safe iterating), thus your loop should be: * for (KrViewItem *it = view->getFirst(); it!=0; it = view->getNext(it)) { blah; } * 5) nameToMakeCurrent(), setNameToMakeCurrent() - work with QString * * IMPORTANT NOTE: every one who subclasses this must call initProperties() in the constructor !!! */ class KrView { friend class KrViewItem; friend class KrViewOperator; public: class IconSizes : public QVector { public: IconSizes() : QVector() { *this << 12 << 16 << 22 << 32 << 48 << 64 << 128 << 256; } }; // instantiating a new view // 1. new KrView // 2. view->init() // notes: constructor does as little as possible, setup() does the rest. esp, note that // if you need something from operator or properties, move it into setup() void init(bool enableUpdateDefaultSettings = true); KrViewInstance *instance() { return &_instance; } static const IconSizes iconSizes; protected: void initProperties(); KrViewProperties *createViewProperties() { return new KrViewProperties(); } KrViewOperator *createOperator() { return new KrViewOperator(this, _widget); } virtual void setup() = 0; /////////////////////////////////////////////////////// // Every view must implement the following functions // /////////////////////////////////////////////////////// public: // interview related functions virtual QModelIndex getCurrentIndex() = 0; virtual bool isSelected(const QModelIndex &) = 0; virtual bool ensureVisibilityAfterSelect() = 0; virtual void selectRegion(KrViewItem *, KrViewItem *, bool) = 0; virtual uint numSelected() const = 0; virtual QList selectedUrls() = 0; virtual void setSelectionUrls(const QList urls) = 0; virtual KrViewItem *getFirst() = 0; virtual KrViewItem *getLast() = 0; virtual KrViewItem *getNext(KrViewItem *current) = 0; virtual KrViewItem *getPrev(KrViewItem *current) = 0; virtual KrViewItem *getCurrentKrViewItem() = 0; virtual KrViewItem *getKrViewItemAt(const QPoint &vp) = 0; virtual KrViewItem *findItemByName(const QString &name) = 0; virtual KrViewItem *findItemByFileItem(FileItem *vf) = 0; + virtual KrViewItem *findItemByUrl(const QUrl &url) = 0; virtual QString getCurrentItem() const = 0; virtual void setCurrentItem(const QString &name, const QModelIndex &fallbackToIndex = QModelIndex()) = 0; virtual void setCurrentKrViewItem(KrViewItem *item) = 0; virtual void makeItemVisible(const KrViewItem *item) = 0; virtual bool isItemVisible(const KrViewItem *item) = 0; virtual void updateView() = 0; virtual void sort() = 0; virtual void refreshColors() = 0; virtual void redraw() = 0; virtual bool handleKeyEvent(QKeyEvent *e); virtual void prepareForActive() = 0; virtual void prepareForPassive() = 0; virtual void renameCurrentItem() = 0; // Rename current item. returns immediately virtual int itemsPerPage() = 0; virtual void showContextMenu(const QPoint &point = QPoint(0, 0)) = 0; protected: virtual KrViewItem *preAddItem(FileItem *fileitem) = 0; virtual void preDelItem(KrViewItem *item) = 0; virtual void preUpdateItem(FileItem *fileitem) = 0; virtual void copySettingsFrom(KrView *other) = 0; virtual void populate(const QList &fileItems, FileItem *dummy) = 0; virtual void intSetSelected(const FileItem *fileitem, bool select) = 0; virtual void clear(); void addItem(FileItem *fileitem); void updateItem(FileItem *fileitem); void delItem(const QString &name); public: ////////////////////////////////////////////////////// // the following functions are already implemented, // // and normally - should NOT be re-implemented. // ////////////////////////////////////////////////////// uint numFiles() const { return _count - _numDirs; } uint numDirs() const { return _numDirs; } uint count() const { return _count; } void getSelectedItems(QStringList *names, bool ignoreJustFocused = false); void getItemsByMask(QString mask, QStringList *names, bool dirs = true, bool files = true); void getSelectedKrViewItems(KrViewItemList *items); void selectAllIncludingDirs() { changeSelection(KRQuery("*"), true, true); } void select(const KRQuery &filter = KRQuery("*")) { changeSelection(filter, true); } void unselect(const KRQuery &filter = KRQuery("*")) { changeSelection(filter, false); } void unselectAll() { changeSelection(KRQuery("*"), false, true); } void invertSelection(); QString nameToMakeCurrent() const { return _nameToMakeCurrent; } void setNameToMakeCurrent(const QString name) { _nameToMakeCurrent = name; } QString firstUnmarkedBelowCurrent(); QString statistics(); const KrViewProperties *properties() const { return _properties; } KrViewOperator *op() const { return _operator; } void showPreviews(bool show); bool previewsShown() { return _previews != 0; } void applySettingsToOthers(); void setFiles(DirListerInterface *files); void refresh(); bool changeSelection(const KRQuery &filter, bool select); bool changeSelection(const KRQuery &filter, bool select, bool includeDirs, bool makeVisible = false); bool isFiltered(FileItem *fileitem); void setSelected(const FileItem *fileitem, bool select); ///////////////////////////////////////////////////////////// // the following functions have a default and minimalistic // // implementation, and may be re-implemented if needed // ///////////////////////////////////////////////////////////// virtual void setSortMode(KrViewProperties::ColumnType sortColumn, bool descending) { sortModeUpdated(sortColumn, descending); } const KRQuery &filterMask() const { return _properties->filterMask; } KrViewProperties::FilterSpec filter() const { return _properties->filter; } void setFilter(KrViewProperties::FilterSpec filter); void setFilter(KrViewProperties::FilterSpec filter, FilterSettings customFilter, bool applyToDirs); void customSelection(bool select); int defaultFileIconSize(); virtual void setFileIconSize(int size); void setDefaultFileIconSize() { setFileIconSize(defaultFileIconSize()); } void zoomIn(); void zoomOut(); // save this view's settings to be restored after restart virtual void saveSettings(KConfigGroup grp, KrViewProperties::PropertyType properties = KrViewProperties::AllProperties); inline QWidget *widget() { return _widget; } inline int fileIconSize() const { return _fileIconSize; } inline bool isFocused() const { return _focused; } QPixmap getIcon(FileItem *fileitem); void setMainWindow(QWidget *mainWindow) { _mainWindow = mainWindow; } // save this view's settings as default for new views of this type void saveDefaultSettings( KrViewProperties::PropertyType properties = KrViewProperties::AllProperties); // restore the default settings for this view type void restoreDefaultSettings(); // call this to restore this view's settings after restart void restoreSettings(KConfigGroup grp); void saveSelection(); void restoreSelection(); bool canRestoreSelection() { return !_savedSelection.isEmpty(); } void clearSavedSelection(); void markSameBaseName(); void markSameExtension(); // todo: what about selection modes ??? virtual ~KrView(); static QPixmap getIcon(FileItem *fileitem, bool active, int size = 0); static QPixmap processIcon(const QPixmap &icon, bool dim, const QColor &dimColor, int dimFactor, bool symlink); static QString krPermissionString(const FileItem *fileitem); protected: KrView(KrViewInstance &instance, KConfig *cfg); virtual void doRestoreSettings(KConfigGroup grp); virtual KIO::filesize_t calcSize() = 0; virtual KIO::filesize_t calcSelectedSize() = 0; void sortModeUpdated(KrViewProperties::ColumnType sortColumn, bool descending); inline void setWidget(QWidget *w) { _widget = w; } KConfig *_config; KrViewProperties *_properties; KrViewOperator *_operator; bool _focused; int _fileIconSize; private: void updatePreviews(); void saveSortMode(KConfigGroup &group); void restoreSortMode(KConfigGroup &group); KrViewInstance &_instance; DirListerInterface *_files; QWidget *_mainWindow; QWidget *_widget; QList _savedSelection; QString _nameToMakeCurrent; KrPreviews *_previews; bool _updateDefaultSettings; bool _ignoreSettingsChange; QRegExp _quickFilterMask; uint _count, _numDirs; FileItem *_dummyFileItem; }; #endif /* KRVIEW_H */ diff --git a/krusader/Panel/krviewitem.h b/krusader/Panel/krviewitem.h index 3b513d0e..0c5a6ca4 100644 --- a/krusader/Panel/krviewitem.h +++ b/krusader/Panel/krviewitem.h @@ -1,97 +1,96 @@ /***************************************************************************** * 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 * *****************************************************************************/ #ifndef KRVIEWITEM_H #define KRVIEWITEM_H #include "../FileSystem/fileitem.h" #include "krview.h" // QtCore #include #include // QtGui #include #include class KrInterView; /** * @brief A view item representing a file inside a KrView */ class KrViewItem { friend class KrView; - friend class KrCalcSpaceDialog; public: KrViewItem(FileItem *fileitem, KrInterView *parentView); virtual ~KrViewItem() {} const QString& name(bool withExtension = true) const; inline bool hasExtension() const { return _hasExtension; } inline const QString& extension() const { return _extension; } QString description() const; QPixmap icon(); bool isSelected() const; void setSelected(bool s); QRect itemRect() const; void redraw(); // DON'T USE THOSE OUTSIDE THE VIEWS!!! inline const FileItem* getFileItem() const { return _fileitem; } inline void setFileItem(FileItem *fileitem) { _fileitem = fileitem; } inline FileItem* getMutableFileItem() { return _fileitem; } inline bool isDummy() const { return dummyFileItem; } inline bool isHidden() const { return _hidden; } // used INTERNALLY when calculation of dir size changes the displayed size of the item inline void setSize(KIO::filesize_t size) { _fileitem->setSize(size); } protected: FileItem* _fileitem; // each view item holds a pointer to a corresponding file item for fast access KrInterView * _view; // the parent view this item belongs to bool dummyFileItem; // used in case our item represents the ".." (updir) item const KrViewProperties* _viewProperties; bool _hasExtension; bool _hidden; QString _name; QString _extension; }; #endif diff --git a/krusader/Panel/listpanel.cpp b/krusader/Panel/listpanel.cpp index 88f03998..986d2c37 100644 --- a/krusader/Panel/listpanel.cpp +++ b/krusader/Panel/listpanel.cpp @@ -1,1291 +1,1290 @@ /*************************************************************************** listpanel.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 "listpanel.h" // QtCore #include #include #include #include #include #include #include // QtGui #include #include #include #include #include #include #include #include // QtWidgets #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../defaults.h" #include "../krusader.h" #include "../krslots.h" #include "../kicons.h" #include "../krusaderview.h" #include "../krservices.h" #include "../FileSystem/krpermhandler.h" #include "../Archive/krarchandler.h" #include "../MountMan/kmountman.h" #include "../BookMan/krbookmarkbutton.h" #include "../Dialogs/krdialogs.h" #include "../Dialogs/krspwidgets.h" #include "../Dialogs/percentalsplitter.h" #include "../Dialogs/popularurls.h" #include "../GUI/kcmdline.h" #include "../GUI/dirhistorybutton.h" #include "../GUI/mediabutton.h" #include "../GUI/syncbrowsebutton.h" #include "../UserAction/useractionpopupmenu.h" #include "listpanelactions.h" #include "viewactions.h" #include "krpreviewpopup.h" #include "panelpopup.h" #include "panelfunc.h" #include "krpopupmenu.h" #include "krviewfactory.h" #include "krcolorcache.h" #include "krerrordisplay.h" #include "krlayoutfactory.h" #include "krsearchbar.h" #include "dirhistoryqueue.h" class ActionButton : public QToolButton { public: ActionButton(QWidget *parent, ListPanel *panel, QAction *action, QString text = QString()) : QToolButton(parent), panel(panel), action(action) { setText(text); setAutoRaise(true); if(KConfigGroup(krConfig, "ListPanelButtons").readEntry("Icons", false) || text.isEmpty()) setIcon(action->icon()); setToolTip(action->toolTip()); } protected: virtual void mousePressEvent(QMouseEvent *) Q_DECL_OVERRIDE { panel->slotFocusOnMe(); action->trigger(); } ListPanel *panel; QAction *action; }; ///////////////////////////////////////////////////// // The list panel constructor // ///////////////////////////////////////////////////// ListPanel::ListPanel(QWidget *parent, AbstractPanelManager *manager, KConfigGroup cfg) : QWidget(parent), KrPanel(manager), panelType(-1), colorMask(255), compareMode(false), previewJob(0), inlineRefreshJob(0), searchBar(0), cdRootButton(0), cdUpButton(0), popupBtn(0), popup(0), fileSystemError(0), _locked(false) { if(cfg.isValid()) panelType = cfg.readEntry("Type", -1); if (panelType == -1) panelType = defaultPanelType(); gui = this; func = new ListPanelFunc(this); _actions = krApp->listPanelActions(); setAcceptDrops(true); QHash widgets; #define ADD_WIDGET(widget) widgets.insert(#widget, widget); // media button mediaButton = new MediaButton(this); connect(mediaButton, SIGNAL(aboutToShow()), this, SLOT(slotFocusOnMe())); connect(mediaButton, SIGNAL(openUrl(const QUrl&)), func, SLOT(openUrl(const QUrl&))); connect(mediaButton, SIGNAL(newTab(const QUrl&)), SLOT(newTab(const QUrl&))); ADD_WIDGET(mediaButton); // status bar status = new KrSqueezedTextLabel(this); KConfigGroup group(krConfig, "Look&Feel"); status->setFont(group.readEntry("Filelist Font", _FilelistFont)); status->setAutoFillBackground(false); status->setText(""); // needed for initialization code! status->setWhatsThis(i18n("The statusbar displays information about the filesystem " "which holds your current folder: total size, free space, " "type of filesystem, etc.")); ADD_WIDGET(status); // back button backButton = new ActionButton(this, this, _actions->actHistoryBackward); ADD_WIDGET(backButton); // forward button forwardButton = new ActionButton(this, this, _actions->actHistoryForward); ADD_WIDGET(forwardButton); // ... create the history button historyButton = new DirHistoryButton(func->history, this); connect(historyButton, SIGNAL(aboutToShow()), this, SLOT(slotFocusOnMe())); connect(historyButton, SIGNAL(gotoPos(int)), func, SLOT(historyGotoPos(int))); ADD_WIDGET(historyButton); // bookmarks button bookmarksButton = new KrBookmarkButton(this); connect(bookmarksButton, SIGNAL(aboutToShow()), this, SLOT(slotFocusOnMe())); connect(bookmarksButton, SIGNAL(openUrl(const QUrl&)), func, SLOT(openUrl(const QUrl&))); bookmarksButton->setWhatsThis(i18n("Open menu with bookmarks. You can also add " "current location to the list, edit bookmarks " "or add subfolder to the list.")); ADD_WIDGET(bookmarksButton); // url input field urlNavigator = new KUrlNavigator(new KFilePlacesModel(this), QUrl(), this); urlNavigator->setWhatsThis(i18n("Name of folder where you are. You can also " "enter name of desired location to move there. " "Use of Net protocols like ftp or fish is possible.")); // handle certain key events here in event filter urlNavigator->editor()->installEventFilter(this); urlNavigator->setUrlEditable(isNavigatorEditModeSet()); urlNavigator->setShowFullPath(group.readEntry("Navigator Full Path", false)); connect(urlNavigator, SIGNAL(returnPressed()), this, SLOT(slotFocusOnMe())); connect(urlNavigator, SIGNAL(urlChanged(QUrl)), func, SLOT(navigatorUrlChanged(QUrl))); connect(urlNavigator->editor()->lineEdit(), SIGNAL(editingFinished()), this, SLOT(resetNavigatorMode())); connect(urlNavigator, SIGNAL(tabRequested(QUrl)), this, SLOT(newTab(QUrl))); connect(urlNavigator, SIGNAL(urlsDropped(QUrl, QDropEvent*)), this, SLOT(handleDrop(QUrl, QDropEvent*))); ADD_WIDGET(urlNavigator); // toolbar QWidget * toolbar = new QWidget(this); QHBoxLayout * toolbarLayout = new QHBoxLayout(toolbar); toolbarLayout->setContentsMargins(0, 0, 0, 0); toolbarLayout->setSpacing(0); ADD_WIDGET(toolbar); fileSystemError = new KrErrorDisplay(this); fileSystemError->setWordWrap(true); fileSystemError->hide(); ADD_WIDGET(fileSystemError); // client area clientArea = new QWidget(this); QVBoxLayout *clientLayout = new QVBoxLayout(clientArea); clientLayout->setSpacing(0); clientLayout->setContentsMargins(0, 0, 0, 0); ADD_WIDGET(clientArea); // totals label totals = new KrSqueezedTextLabel(this); totals->setFont(group.readEntry("Filelist Font", _FilelistFont)); totals->setAutoFillBackground(false); totals->setWhatsThis(i18n("The totals bar shows how many files exist, " "how many selected and the bytes math")); ADD_WIDGET(totals); // free space label freeSpace = new KrSqueezedTextLabel(this); freeSpace->setFont(group.readEntry("Filelist Font", _FilelistFont)); freeSpace->setAutoFillBackground(false); freeSpace->setText(""); freeSpace->setAlignment(Qt::AlignRight | Qt::AlignVCenter); ADD_WIDGET(freeSpace); // progress indicator for the preview job previewProgress = new QProgressBar(this); previewProgress->hide(); ADD_WIDGET(previewProgress); // a cancel button for the inplace refresh mechanism inlineRefreshCancelButton = new QToolButton(this); inlineRefreshCancelButton->hide(); inlineRefreshCancelButton->setIcon(krLoader->loadIcon("dialog-cancel", KIconLoader::Toolbar, 16)); connect(inlineRefreshCancelButton, SIGNAL(clicked()), this, SLOT(inlineRefreshCancel())); ADD_WIDGET(inlineRefreshCancelButton); // button for changing the panel popup position in the panel popupPositionBtn = new QToolButton(this); popupPositionBtn->hide(); popupPositionBtn->setAutoRaise(true); popupPositionBtn->setIcon(krLoader->loadIcon("exchange-positions", KIconLoader::Toolbar, 16)); popupPositionBtn->setToolTip(i18n("Move popup panel clockwise")); connect(popupPositionBtn, &QToolButton::clicked, [this]() { // moving position clockwise setPopupPosition((popupPosition() + 1) % 4); }); ADD_WIDGET(popupPositionBtn); // a quick button to open the popup panel popupBtn = new QToolButton(this); popupBtn->setAutoRaise(true); popupBtn->setIcon(krLoader->loadIcon("arrow-up", KIconLoader::Toolbar, 16)); connect(popupBtn, SIGNAL(clicked()), this, SLOT(togglePanelPopup())); popupBtn->setToolTip(i18n("Open the popup panel")); ADD_WIDGET(popupBtn); #undef ADD_WIDGET // toolbar buttons cdOtherButton = new ActionButton(toolbar, this, _actions->actCdToOther, "="); toolbarLayout->addWidget(cdOtherButton); cdUpButton = new ActionButton(toolbar, this, _actions->actDirUp, ".."); toolbarLayout->addWidget(cdUpButton); cdHomeButton = new ActionButton(toolbar, this, _actions->actHome, "~"); toolbarLayout->addWidget(cdHomeButton); cdRootButton = new ActionButton(toolbar, this, _actions->actRoot, "/"); toolbarLayout->addWidget(cdRootButton); // ... creates the button for sync-browsing syncBrowseButton = new SyncBrowseButton(toolbar); syncBrowseButton->setAutoRaise(true); toolbarLayout->addWidget(syncBrowseButton); setButtons(); // create a splitter to hold the view and the popup splt = new PercentalSplitter(clientArea); splt->setChildrenCollapsible(true); splt->setOrientation(Qt::Vertical); // expand vertical if splitter orientation is horizontal QSizePolicy sizePolicy = splt->sizePolicy(); sizePolicy.setVerticalPolicy(QSizePolicy::Expanding); splt->setSizePolicy(sizePolicy); clientLayout->addWidget(splt); // view createView(); // search (in folder) bar searchBar = new KrSearchBar(view, clientArea); searchBar->hide(); bool top = group.readEntry("Quicksearch Position", "bottom") == "top"; clientLayout->insertWidget(top ? 0 : -1, searchBar); // create the layout KrLayoutFactory fact(this, widgets); QLayout *layout = fact.createLayout(); if(!layout) { // fallback: create a layout by ourself QVBoxLayout *v = new QVBoxLayout; v->setContentsMargins(0, 0, 0, 0); v->setSpacing(0); QHBoxLayout *h = new QHBoxLayout; h->setContentsMargins(0, 0, 0, 0); h->setSpacing(0); h->addWidget(urlNavigator); h->addWidget(toolbar); h->addStretch(); v->addLayout(h); h = new QHBoxLayout; h->setContentsMargins(0, 0, 0, 0); h->setSpacing(0); h->addWidget(mediaButton); h->addWidget(status); h->addWidget(backButton); h->addWidget(forwardButton); h->addWidget(historyButton); h->addWidget(bookmarksButton); v->addLayout(h); v->addWidget(fileSystemError); v->addWidget(clientArea); h = new QHBoxLayout; h->setContentsMargins(0, 0, 0, 0); h->setSpacing(0); h->addWidget(totals); h->addWidget(freeSpace); h->addWidget(previewProgress); h->addWidget(inlineRefreshCancelButton); h->addWidget(popupBtn); v->addLayout(h); layout = v; } setLayout(layout); connect(&KrColorCache::getColorCache(), SIGNAL(colorsRefreshed()), this, SLOT(refreshColors())); connect(krApp, SIGNAL(shutdown()), SLOT(inlineRefreshCancel())); } ListPanel::~ListPanel() { inlineRefreshCancel(); delete view; view = 0; delete func; delete status; delete bookmarksButton; delete totals; delete urlNavigator; delete cdRootButton; delete cdHomeButton; delete cdUpButton; delete cdOtherButton; delete syncBrowseButton; // delete layout; } void ListPanel::reparent(QWidget *parent, AbstractPanelManager *manager) { setParent(parent); _manager = manager; } int ListPanel::defaultPanelType() { KConfigGroup group(krConfig, "Look&Feel"); return group.readEntry("Default Panel Type", KrViewFactory::defaultViewId()); } bool ListPanel::isNavigatorEditModeSet() { KConfigGroup group(krConfig, "Look&Feel"); return group.readEntry("Navigator Edit Mode", false); } void ListPanel::createView() { view = KrViewFactory::createView(panelType, splt, krConfig); view->init(); view->setMainWindow(krApp); // KrViewFactory may create a different view type than requested panelType = view->instance()->id(); if(this == ACTIVE_PANEL) view->prepareForActive(); else view->prepareForPassive(); view->refreshColors(); splt->insertWidget(popupPosition() < 2 ? 1 : 0, view->widget()); view->widget()->installEventFilter(this); - connect(view->op(), SIGNAL(calcSpace(KrViewItem*)), func, SLOT(calcSpace(KrViewItem*))); connect(view->op(), SIGNAL(goHome()), func, SLOT(home())); connect(view->op(), SIGNAL(dirUp()), func, SLOT(dirUp())); connect(view->op(), SIGNAL(deleteFiles(bool)), func, SLOT(deleteFiles(bool))); connect(view->op(), SIGNAL(middleButtonClicked(KrViewItem *)), SLOT(newTab(KrViewItem *))); connect(view->op(), SIGNAL(currentChanged(KrViewItem *)), SLOT(slotCurrentChanged(KrViewItem*))); connect(view->op(), SIGNAL(renameItem(const QString &, const QString &)), func, SLOT(rename(const QString &, const QString &))); connect(view->op(), SIGNAL(executed(const QString&)), func, SLOT(execute(const QString&))); connect(view->op(), SIGNAL(goInside(const QString&)), func, SLOT(goInside(const QString&))); connect(view->op(), SIGNAL(needFocus()), this, SLOT(slotFocusOnMe())); connect(view->op(), SIGNAL(selectionChanged()), this, SLOT(slotUpdateTotals())); connect(view->op(), SIGNAL(itemDescription(const QString&)), krApp, SLOT(statusBarUpdate(const QString&))); connect(view->op(), SIGNAL(contextMenu(const QPoint &)), this, SLOT(popRightClickMenu(const QPoint &))); connect(view->op(), SIGNAL(emptyContextMenu(const QPoint &)), this, SLOT(popEmptyRightClickMenu(const QPoint &))); connect(view->op(), SIGNAL(letsDrag(QStringList, QPixmap)), this, SLOT(startDragging(QStringList, QPixmap))); connect(view->op(), &KrViewOperator::gotDrop, this, [this](QDropEvent *event) {handleDrop(event, true); }); connect(view->op(), SIGNAL(previewJobStarted(KJob*)), this, SLOT(slotPreviewJobStarted(KJob*))); connect(view->op(), SIGNAL(refreshActions()), krApp->viewActions(), SLOT(refreshActions())); connect(view->op(), SIGNAL(currentChanged(KrViewItem*)), func->history, SLOT(saveCurrentItem())); connect(view->op(), &KrViewOperator::goBack, func, &ListPanelFunc::historyBackward); connect(view->op(), &KrViewOperator::goForward, func, &ListPanelFunc::historyForward); view->setFiles(func->files()); func->refreshActions(); } void ListPanel::changeType(int type) { if (panelType != type) { QString current = view->getCurrentItem(); QList selection = view->selectedUrls(); bool filterApplysToDirs = view->properties()->filterApplysToDirs; KrViewProperties::FilterSpec filter = view->filter(); FilterSettings filterSettings = view->properties()->filterSettings; panelType = type; KrView *oldView = view; createView(); searchBar->setView(view); delete oldView; view->setFilter(filter, filterSettings, filterApplysToDirs); view->setSelectionUrls(selection); view->setCurrentItem(current); view->makeItemVisible(view->getCurrentKrViewItem()); } } int ListPanel::getProperties() { int props = 0; if (syncBrowseButton->state() == SYNCBROWSE_CD) props |= PROP_SYNC_BUTTON_ON; if (_locked) props |= PROP_LOCKED; return props; } void ListPanel::setProperties(int prop) { syncBrowseButton->setChecked(prop & PROP_SYNC_BUTTON_ON); _locked = (prop & PROP_LOCKED); } bool ListPanel::eventFilter(QObject * watched, QEvent * e) { if(view && watched == view->widget()) { if(e->type() == QEvent::FocusIn && this != ACTIVE_PANEL && !isHidden()) slotFocusOnMe(); else if(e->type() == QEvent::ShortcutOverride) { QKeyEvent *ke = static_cast(e); if(ke->key() == Qt::Key_Escape && ke->modifiers() == Qt::NoModifier) { // if the cancel refresh action has no shortcut assigned, // we need this event ourselves to cancel refresh if(_actions->actCancelRefresh->shortcut().isEmpty()) { e->accept(); return true; } } } } // handle URL navigator key events else if(watched == urlNavigator->editor()) { // override default shortcut for panel focus if(e->type() == QEvent::ShortcutOverride) { QKeyEvent *ke = static_cast(e); if ((ke->key() == Qt::Key_Escape) && (ke->modifiers() == Qt::NoModifier)) { e->accept(); // we will get the key press event now return true; } } else if(e->type() == QEvent::KeyPress) { QKeyEvent *ke = static_cast(e); if ((ke->key() == Qt::Key_Down) && (ke->modifiers() == Qt::ControlModifier)) { slotFocusOnMe(); return true; } else if ((ke->key() == Qt::Key_Escape) && (ke->modifiers() == Qt::NoModifier)) { // reset navigator urlNavigator->editor()->setUrl(urlNavigator->locationUrl()); slotFocusOnMe(); return true; } } } return false; } void ListPanel::togglePanelPopup() { if(!popup) { popup = new PanelPopup(splt, isLeft(), krApp); // fix vertical grow of splitter (and entire window) if its content // demands more space QSizePolicy sizePolicy = popup->sizePolicy(); sizePolicy.setVerticalPolicy(QSizePolicy::Ignored); popup->setSizePolicy(sizePolicy); connect(this, SIGNAL(pathChanged(const QUrl&)), popup, SLOT(onPanelPathChange(const QUrl&))); connect(popup, SIGNAL(selection(const QUrl&)), SLOTS, SLOT(refresh(const QUrl&))); connect(popup, SIGNAL(hideMe()), this, SLOT(togglePanelPopup())); } if (popup->isHidden()) { if (popupSizes.count() > 0) { splt->setSizes(popupSizes); } else { // on the first time, resize to 50% QList lst; lst << height() / 2 << height() / 2; splt->setSizes(lst); } popup->show(); popupBtn->setIcon(krLoader->loadIcon("arrow-down", KIconLoader::Toolbar, 16)); popupBtn->setToolTip(i18n("Close the popup panel")); popupPositionBtn->show(); } else { popupSizes.clear(); popupSizes = splt->sizes(); popup->hide(); popupBtn->setIcon(krLoader->loadIcon("arrow-up", KIconLoader::Toolbar, 16)); popupBtn->setToolTip(i18n("Open the popup panel")); popupPositionBtn->hide(); QList lst; lst << height() << 0; splt->setSizes(lst); if (ACTIVE_PANEL) ACTIVE_PANEL->gui->slotFocusOnMe(); } } QString ListPanel::realPath() const { return _realPath.path(); } void ListPanel::setButtons() { KConfigGroup group(krConfig, "Look&Feel"); mediaButton->setVisible(group.readEntry("Media Button Visible", true)); backButton->setVisible(group.readEntry("Back Button Visible", false)); forwardButton->setVisible(group.readEntry("Forward Button Visible", false)); historyButton->setVisible(group.readEntry("History Button Visible", true)); bookmarksButton->setVisible(group.readEntry("Bookmarks Button Visible", true)); if (group.readEntry("Panel Toolbar visible", _PanelToolBar)) { cdRootButton->setVisible(group.readEntry("Root Button Visible", _cdRoot)); cdHomeButton->setVisible(group.readEntry("Home Button Visible", _cdHome)); cdUpButton->setVisible(group.readEntry("Up Button Visible", _cdUp)); cdOtherButton->setVisible(group.readEntry("Equal Button Visible", _cdOther)); syncBrowseButton->setVisible(group.readEntry("SyncBrowse Button Visible", _syncBrowseButton)); } else { cdRootButton->hide(); cdHomeButton->hide(); cdUpButton->hide(); cdOtherButton->hide(); syncBrowseButton->hide(); } } void ListPanel::slotUpdateTotals() { totals->setText(view->statistics()); } void ListPanel::compareDirs(bool otherPanelToo) { // Performs a check in order to avoid that the next code is executed twice if (otherPanelToo == true) { // If both panels are showing the same directory if (_manager->currentPanel()->virtualPath() == otherPanel()->virtualPath()) { if (KMessageBox::warningContinueCancel(this, i18n("Warning: The left and the right side are showing the same folder.")) != KMessageBox::Continue) { return; } } } KConfigGroup pg(krConfig, "Private"); int compareMode = pg.readEntry("Compare Mode", 0); KConfigGroup group(krConfig, "Look&Feel"); bool selectDirs = group.readEntry("Mark Dirs", false); KrViewItem *item, *otherItem; for (item = view->getFirst(); item != 0; item = view->getNext(item)) { if (item->name() == "..") continue; for (otherItem = otherPanel()->view->getFirst(); otherItem != 0 && otherItem->name() != item->name() ; otherItem = otherPanel()->view->getNext(otherItem)); bool isSingle = (otherItem == 0), isDifferent = false, isNewer = false; if (func->getFileItem(item)->isDir() && !selectDirs) { item->setSelected(false); continue; } if (otherItem) { if (!func->getFileItem(item)->isDir()) isDifferent = ITEM2FILEITEM(otherPanel(), otherItem)->getSize() != func->getFileItem(item)->getSize(); isNewer = func->getFileItem(item)->getTime_t() > ITEM2FILEITEM(otherPanel(), otherItem)->getTime_t(); } switch (compareMode) { case 0: item->setSelected(isNewer || isSingle); break; case 1: item->setSelected(isNewer); break; case 2: item->setSelected(isSingle); break; case 3: item->setSelected(isDifferent || isSingle); break; case 4: item->setSelected(isDifferent); break; } } view->updateView(); if (otherPanelToo) otherPanel()->gui->compareDirs(false); } void ListPanel::refreshColors() { view->refreshColors(); emit refreshColors(this == ACTIVE_PANEL); } void ListPanel::slotFocusOnMe(bool focus) { if (focus && _manager->currentPanel() != this) { // ignore focus request if this panel is not shown return; } krApp->setUpdatesEnabled(false); if(focus) { emit activate(); _actions->activePanelChanged(); func->refreshActions(); slotCurrentChanged(view->getCurrentKrViewItem()); view->prepareForActive(); otherPanel()->gui->slotFocusOnMe(false); } else { // in case a new url was entered but not refreshed to, // reset url navigator to the current url urlNavigator->setLocationUrl(virtualPath()); view->prepareForPassive(); } urlNavigator->setActive(focus); refreshColors(); emit refreshPathLabel(); krApp->setUpdatesEnabled(true); } // this is used to start the panel ////////////////////////////////////////////////////////////////// void ListPanel::start(const QUrl &url) { QUrl startUrl(url); if (!startUrl.isValid()) startUrl = QUrl::fromLocalFile(ROOT_DIR); _realPath = startUrl.isLocalFile() ? startUrl : QUrl::fromLocalFile(ROOT_DIR); func->openUrl(startUrl); setJumpBack(startUrl); } void ListPanel::slotStartUpdate(bool directoryChange) { if (inlineRefreshJob) inlineRefreshListResult(0); setCursor(Qt::BusyCursor); const QUrl currentUrl = virtualPath(); if (directoryChange) { if (this == ACTIVE_PANEL) { slotFocusOnMe(); } if (func->files()->isLocal()) _realPath = currentUrl; urlNavigator->setLocationUrl(currentUrl); emit pathChanged(currentUrl); krApp->popularUrls()->addUrl(currentUrl); searchBar->hideBar(); } if (compareMode) otherPanel()->view->refresh(); // return cursor to normal arrow setCursor(Qt::ArrowCursor); slotUpdateTotals(); } void ListPanel::updateFilesystemStats(const QString &metaInfo, const QString &fsType, KIO::filesize_t total, KIO::filesize_t free) { QString statusText, mountPoint, freeSpaceText; if (!metaInfo.isEmpty()) { statusText = metaInfo; mountPoint = freeSpaceText = ""; } else { const int perc = total == 0 ? 0 : (int)(((float)free / (float)total) * 100.0); mountPoint = func->files()->mountPoint(); statusText = i18nc("%1=free space,%2=total space,%3=percentage of usage, " "%4=mountpoint,%5=filesystem type", "%1 free out of %2 (%3%) on %4 [(%5)]", KIO::convertSize(free), KIO::convertSize(total), perc, mountPoint, fsType); freeSpaceText = " " + i18n("%1 free", KIO::convertSize(free)); } status->setText(statusText); freeSpace->setText(freeSpaceText); mediaButton->updateIcon(mountPoint); } void ListPanel::handleDrop(QDropEvent *event, bool onView) { // check what was dropped const QList urls = KUrlMimeData::urlsFromMimeData(event->mimeData()); if (urls.isEmpty()) { event->ignore(); // not for us to handle! return; } // find dropping destination QString destinationDir = ""; const bool dragFromThisPanel = event->source() == this; const KrViewItem *item = onView ? view->getKrViewItemAt(event->pos()) : 0; if (item) { const FileItem *file = item->getFileItem(); if (file && !file->isDir() && dragFromThisPanel) { event->ignore(); // dragging on files in same panel, ignore return ; } else if (!file || file->isDir()) { // item is ".." dummy or a directory destinationDir = item->name(); } } else if (dragFromThisPanel) { event->ignore(); // dragged from this panel onto an empty spot in this panel, ignore return ; } QUrl destination = QUrl(virtualPath()); destination.setPath(destination.path() + '/' + destinationDir); func->files()->dropFiles(destination, event); if(KConfigGroup(krConfig, "Look&Feel").readEntry("UnselectBeforeOperation", _UnselectBeforeOperation)) { KrPanel *p = dragFromThisPanel ? this : otherPanel(); p->view->saveSelection(); p->view->unselectAll(); } } void ListPanel::handleDrop(const QUrl &destination, QDropEvent *event) { func->files()->dropFiles(destination, event); } void ListPanel::startDragging(QStringList names, QPixmap px) { if (names.isEmpty()) { // avoid dragging empty urls return; } QList urls = func->files()->getUrls(names); QDrag *drag = new QDrag(this); QMimeData *mimeData = new QMimeData; drag->setPixmap(px); mimeData->setUrls(urls); drag->setMimeData(mimeData); drag->start(Qt::MoveAction | Qt::CopyAction | Qt::LinkAction); } // pops a right-click menu for items void ListPanel::popRightClickMenu(const QPoint &loc) { // run it, on the mouse location int j = QFontMetrics(font()).height() * 2; KrPopupMenu::run(QPoint(loc.x() + 5, loc.y() + j), this); } void ListPanel::popEmptyRightClickMenu(const QPoint &loc) { KrPopupMenu::run(loc, this); } QString ListPanel::getCurrentName() { QString name = view->getCurrentItem(); if (name != "..") return name; else return QString(); } void ListPanel::prepareToDelete() { view->setNameToMakeCurrent(view->firstUnmarkedBelowCurrent()); } void ListPanel::keyPressEvent(QKeyEvent *e) { switch (e->key()) { case Qt::Key_Enter : case Qt::Key_Return : if (e->modifiers() & Qt::ControlModifier) { if (e->modifiers() & Qt::AltModifier) { FileItem *fileitem = func->files()->getFileItem(view->getCurrentKrViewItem()->name()); if (fileitem && fileitem->isDir()) newTab(fileitem->getUrl(), true); } else { SLOTS->insertFileName((e->modifiers() & Qt::ShiftModifier) != 0); } } else e->ignore(); break; case Qt::Key_Right : case Qt::Key_Left : if (e->modifiers() == Qt::ControlModifier) { // user pressed CTRL+Right/Left - refresh other panel to the selected path if it's a // directory otherwise as this one if ((isLeft() && e->key() == Qt::Key_Right) || (!isLeft() && e->key() == Qt::Key_Left)) { QUrl newPath; KrViewItem *it = view->getCurrentKrViewItem(); if (it->name() == "..") { newPath = KIO::upUrl(func->files()->currentDirectory()); } else { FileItem *v = func->getFileItem(it); // If it's a directory different from ".." if (v && v->isDir() && v->getName() != "..") { newPath = v->getUrl(); } else { // If it's a supported compressed file if (v && KRarcHandler::arcSupported(v->getMime())) { newPath = func->browsableArchivePath(v->getUrl().fileName()); } else { newPath = func->files()->currentDirectory(); } } } otherPanel()->func->openUrl(newPath); } else { func->openUrl(otherPanel()->func->files()->currentDirectory()); } return ; } else e->ignore(); break; case Qt::Key_Down : if (e->modifiers() == Qt::ControlModifier) { // give the keyboard focus to the command line if (MAIN_VIEW->cmdLine()->isVisible()) MAIN_VIEW->cmdLineFocus(); else MAIN_VIEW->focusTerminalEmulator(); return ; } else if (e->modifiers() == (Qt::ControlModifier | Qt::ShiftModifier)) { // give the keyboard focus to TE MAIN_VIEW->focusTerminalEmulator(); } else e->ignore(); break; case Qt::Key_Up : if (e->modifiers() == Qt::ControlModifier) { // give the keyboard focus to the url navigator editLocation(); return ; } else e->ignore(); break; case Qt::Key_Escape: inlineRefreshCancel(); break; default: // if we got this, it means that the view is not doing // the quick search thing, so send the characters to the commandline, if normal key if (e->modifiers() == Qt::NoModifier) MAIN_VIEW->cmdLine()->addText(e->text()); //e->ignore(); } } void ListPanel::showEvent(QShowEvent *e) { panelActive(); QWidget::showEvent(e); } void ListPanel::hideEvent(QHideEvent *e) { panelInactive(); QWidget::hideEvent(e); } void ListPanel::panelActive() { //func->files()->enableRefresh(true) } void ListPanel::panelInactive() { // don't refresh when not active (ie: hidden, application isn't focused ...) // TODO disabled so that the user sees changes in non-focused window; if the performance impact // is too high we need another solution here //func->files()->enableRefresh(false); } void ListPanel::slotPreviewJobStarted(KJob *job) { previewJob = job; connect(job, SIGNAL(percent(KJob*, unsigned long)), SLOT(slotPreviewJobPercent(KJob*, unsigned long))); connect(job, &KJob::result, this, &ListPanel::slotPreviewJobResult); inlineRefreshCancelButton->setMaximumHeight(popupBtn->height()); inlineRefreshCancelButton->show(); previewProgress->setValue(0); previewProgress->setFormat(i18n("loading previews: %p%")); previewProgress->setMaximumHeight(inlineRefreshCancelButton->height()); previewProgress->show(); } void ListPanel::slotPreviewJobPercent(KJob* /*job*/, unsigned long percent) { previewProgress->setValue(percent); } void ListPanel::slotPreviewJobResult(KJob* /*job*/) { previewJob = 0; previewProgress->hide(); if(!inlineRefreshJob) inlineRefreshCancelButton->hide(); } void ListPanel::slotJobStarted(KIO::Job* job) { // disable the parts of the panel we don't want touched status->setEnabled(false); urlNavigator->setEnabled(false); cdRootButton->setEnabled(false); cdHomeButton->setEnabled(false); cdUpButton->setEnabled(false); cdOtherButton->setEnabled(false); popupBtn->setEnabled(false); if(popup) popup->setEnabled(false); bookmarksButton->setEnabled(false); historyButton->setEnabled(false); syncBrowseButton->setEnabled(false); // connect to the job interface to provide in-panel refresh notification connect(job, SIGNAL(infoMessage(KJob*, const QString &)), SLOT(inlineRefreshInfoMessage(KJob*, const QString &))); connect(job, SIGNAL(percent(KJob*, unsigned long)), SLOT(inlineRefreshPercent(KJob*, unsigned long))); connect(job, SIGNAL(result(KJob*)), this, SLOT(inlineRefreshListResult(KJob*))); inlineRefreshJob = job; totals->setText(i18n(">> Reading...")); inlineRefreshCancelButton->show(); } void ListPanel::inlineRefreshCancel() { if (inlineRefreshJob) { disconnect(inlineRefreshJob, 0, this, 0); inlineRefreshJob->kill(KJob::EmitResult); inlineRefreshListResult(0); } if(previewJob) { disconnect(previewJob, 0, this, 0); previewJob->kill(KJob::EmitResult); slotPreviewJobResult(0); } } void ListPanel::inlineRefreshPercent(KJob*, unsigned long perc) { QString msg = i18n(">> Reading: %1 % complete...", perc); totals->setText(msg); } void ListPanel::inlineRefreshInfoMessage(KJob*, const QString &msg) { totals->setText(i18n(">> Reading: %1", msg)); } void ListPanel::inlineRefreshListResult(KJob*) { if(inlineRefreshJob) disconnect(inlineRefreshJob, 0, this, 0); inlineRefreshJob = 0; // reenable everything status->setEnabled(true); urlNavigator->setEnabled(true); cdRootButton->setEnabled(true); cdHomeButton->setEnabled(true); cdUpButton->setEnabled(true); cdOtherButton->setEnabled(true); popupBtn->setEnabled(true); if(popup) popup->setEnabled(true); bookmarksButton->setEnabled(true); historyButton->setEnabled(true); syncBrowseButton->setEnabled(true); if(!previewJob) inlineRefreshCancelButton->hide(); } void ListPanel::jumpBack() { func->openUrl(_jumpBackURL); } void ListPanel::setJumpBack(QUrl url) { _jumpBackURL = url; } void ListPanel::slotFilesystemError(QString msg) { if (func->ignoreFileSystemErrors()) return; refreshColors(); fileSystemError->setText(i18n("Error: %1", msg)); fileSystemError->show(); } void ListPanel::showButtonMenu(QToolButton *b) { if(this != ACTIVE_PANEL) slotFocusOnMe(); if(b->isHidden()) b->menu()->exec(mapToGlobal(clientArea->pos())); else b->click(); } void ListPanel::openBookmarks() { showButtonMenu(bookmarksButton); } void ListPanel::openHistory() { showButtonMenu(historyButton); } void ListPanel::openMedia() { showButtonMenu(mediaButton); } void ListPanel::rightclickMenu() { if (view->getCurrentKrViewItem()) popRightClickMenu(mapToGlobal(view->getCurrentKrViewItem()->itemRect().topLeft())); } void ListPanel::toggleSyncBrowse() { syncBrowseButton->toggle(); } void ListPanel::editLocation() { urlNavigator->setUrlEditable(true); urlNavigator->setFocus(); urlNavigator->editor()->lineEdit()->selectAll(); } void ListPanel::showSearchBar() { searchBar->showBar(); } void ListPanel::showSearchFilter() { searchBar->showBar(KrSearchBar::MODE_FILTER); } void ListPanel::saveSettings(KConfigGroup cfg, bool saveHistory) { QUrl url = virtualPath(); url.setPassword(QString()); // make sure no password is saved cfg.writeEntry("Url", url.toString()); cfg.writeEntry("Type", getType()); cfg.writeEntry("Properties", getProperties()); if(saveHistory) func->history->save(KConfigGroup(&cfg, "History")); view->saveSettings(KConfigGroup(&cfg, "View")); // splitter/popup state if (popup && !popup->isHidden()) { popup->saveSettings(KConfigGroup(&cfg, "PanelPopup")); cfg.writeEntry("PopupPosition", popupPosition()); cfg.writeEntry("SplitterSizes", splt->saveState()); cfg.writeEntry("PopupPage", popup->currentPage()); } else { cfg.deleteEntry("PopupPosition"); cfg.deleteEntry("SplitterSizes"); cfg.deleteEntry("PopupPage"); } } void ListPanel::restoreSettings(KConfigGroup cfg) { changeType(cfg.readEntry("Type", defaultPanelType())); setProperties(cfg.readEntry("Properties", 0)); view->restoreSettings(KConfigGroup(&cfg, "View")); _realPath = QUrl::fromLocalFile(ROOT_DIR); if(func->history->restore(KConfigGroup(&cfg, "History"))) func->refresh(); else { QUrl url(cfg.readEntry("Url", ROOT_DIR)); if (!url.isValid()) url = QUrl::fromLocalFile(ROOT_DIR); func->openUrl(url); } setJumpBack(func->history->currentUrl()); if (cfg.hasKey("PopupPosition")) { // popup was visible, restore togglePanelPopup(); // create and show popup->restoreSettings(KConfigGroup(&cfg, "PanelPopup")); setPopupPosition(cfg.readEntry("PopupPosition", 42 /* dummy */)); splt->restoreState(cfg.readEntry("SplitterSizes", QByteArray())); popup->setCurrentPage(cfg.readEntry("PopupPage", 0)); } } void ListPanel::slotCurrentChanged(KrViewItem *item) { // update status bar if (item) krApp->statusBarUpdate(item->description()); // update popup panel; which panel to display on? PanelPopup *p; if(popup && !popup->isHidden()) p = popup; else if(otherPanel()->gui->popup && !otherPanel()->gui->popup->isHidden()) p = otherPanel()->gui->popup; else return; p->update(item ? func->files()->getFileItem(item->name()) : 0); } void ListPanel::otherPanelChanged() { func->syncURL = QUrl(); } void ListPanel::getFocusCandidates(QVector &widgets) { if(urlNavigator->editor()->isVisible()) widgets << urlNavigator->editor(); if(view->widget()->isVisible()) widgets << view->widget(); if(popup && popup->isVisible()) widgets << popup; } void ListPanel::updateButtons() { backButton->setEnabled(func->history->canGoBack()); forwardButton->setEnabled(func->history->canGoForward()); historyButton->setEnabled(func->history->count() > 1); cdRootButton->setEnabled(!virtualPath().matches(QUrl::fromLocalFile(ROOT_DIR), QUrl::StripTrailingSlash)); cdUpButton->setEnabled(!func->files()->isRoot()); cdHomeButton->setEnabled(!func->atHome()); } void ListPanel::newTab(KrViewItem *it) { if (!it) return; else if (it->name() == "..") { newTab(KIO::upUrl(virtualPath()), true); } else if (ITEM2FILEITEM(this, it)->isDir()) { QUrl url = virtualPath(); url = url.adjusted(QUrl::StripTrailingSlash); url.setPath(url.path() + '/' + (it->name())); newTab(url, true); } } void ListPanel::resetNavigatorMode() { if (isNavigatorEditModeSet()) return; // set to "navigate" mode if url wasn't changed if (urlNavigator->uncommittedUrl().matches(virtualPath(), QUrl::StripTrailingSlash)) { // NOTE: this also sets focus to the navigator urlNavigator->setUrlEditable(false); slotFocusOnMe(); } } int ListPanel::popupPosition() const { int pos = splt->orientation() == Qt::Vertical ? 1 : 0; return pos + (qobject_cast(splt->widget(0)) == NULL ? 2 : 0); } void ListPanel::setPopupPosition(int pos) { splt->setOrientation(pos % 2 == 0 ? Qt::Horizontal : Qt::Vertical); if ((pos < 2) != (qobject_cast(splt->widget(0)) != NULL)) { splt->insertWidget(0, splt->widget(1)); // swapping widgets in splitter } } diff --git a/krusader/Panel/panelfunc.cpp b/krusader/Panel/panelfunc.cpp index 5e703640..aaf1c382 100644 --- a/krusader/Panel/panelfunc.cpp +++ b/krusader/Panel/panelfunc.cpp @@ -1,1225 +1,1232 @@ /*************************************************************************** panelfunc.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 "panelfunc.h" // QtCore #include #include #include #include #include #include // QtGui #include #include // QtWidgets #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "dirhistoryqueue.h" #include "krcalcspacedialog.h" #include "listpanel.h" #include "krerrordisplay.h" #include "listpanelactions.h" #include "../krglobal.h" #include "../krslots.h" #include "../kractions.h" #include "../defaults.h" #include "../abstractpanelmanager.h" #include "../krservices.h" #include "../Archive/krarchandler.h" #include "../Archive/packjob.h" #include "../FileSystem/fileitem.h" #include "../FileSystem/virtualfilesystem.h" #include "../FileSystem/krpermhandler.h" #include "../FileSystem/filesystemprovider.h" +#include "../FileSystem/sizecalculator.h" #include "../Dialogs/packgui.h" #include "../Dialogs/krdialogs.h" #include "../Dialogs/krpleasewait.h" #include "../Dialogs/krspwidgets.h" #include "../Dialogs/checksumdlg.h" #include "../KViewer/krviewer.h" #include "../GUI/syncbrowsebutton.h" #include "../MountMan/kmountman.h" QPointer ListPanelFunc::copyToClipboardOrigin; ListPanelFunc::ListPanelFunc(ListPanel *parent) : QObject(parent), panel(parent), fileSystemP(0), urlManuallyEntered(false), _refreshing(false), _ignoreFileSystemErrors(false) { history = new DirHistoryQueue(panel); delayTimer.setSingleShot(true); connect(&delayTimer, SIGNAL(timeout()), this, SLOT(doRefresh())); } ListPanelFunc::~ListPanelFunc() { if (fileSystemP) { fileSystemP->deleteLater(); } delete history; } void ListPanelFunc::navigatorUrlChanged(const QUrl &url) { if (_refreshing) return; if (!ListPanel::isNavigatorEditModeSet()) { panel->urlNavigator->setUrlEditable(false); } openUrl(KrServices::escapeFileUrl(url), QString(), true); } bool ListPanelFunc::isSyncing(const QUrl &url) { if(otherFunc()->otherFunc() == this && panel->otherPanel()->gui->syncBrowseButton->state() == SYNCBROWSE_CD && !otherFunc()->syncURL.isEmpty() && otherFunc()->syncURL == url) return true; return false; } void ListPanelFunc::openFileNameInternal(const QString &name, bool externallyExecutable) { if (name == "..") { dirUp(); return ; } FileItem *fileitem = files()->getFileItem(name); if (fileitem == 0) return ; QUrl url = files()->getUrl(name); if (fileitem->isDir()) { panel->view->setNameToMakeCurrent(QString()); openUrl(url); return; } QString mime = fileitem->getMime(); QUrl arcPath = browsableArchivePath(name); if (!arcPath.isEmpty()) { bool browseAsDirectory = !externallyExecutable || (KConfigGroup(krConfig, "Archives").readEntry("ArchivesAsDirectories", _ArchivesAsDirectories) && (KRarcHandler::arcSupported(mime) || KrServices::isoSupported(mime))); if (browseAsDirectory) { openUrl(arcPath); return; } } if (externallyExecutable) { if (KRun::isExecutableFile(url, mime)) { runCommand(KShell::quoteArg(url.path())); return; } KService::Ptr service = KMimeTypeTrader::self()->preferredService(mime); if(service) { runService(*service, QList() << url); return; } displayOpenWithDialog(QList() << url); } } QUrl ListPanelFunc::cleanPath(const QUrl &urlIn) { QUrl url = urlIn; url.setPath(QDir::cleanPath(url.path())); if (!url.isValid() || url.isRelative()) { if (url.url() == "~") url = QUrl::fromLocalFile(QDir::homePath()); else if (!url.url().startsWith('/')) { // possible relative URL - translate to full URL url = files()->currentDirectory(); url.setPath(url.path() + '/' + urlIn.path()); } } url.setPath(QDir::cleanPath(url.path())); return url; } void ListPanelFunc::openUrl(const QUrl &url, const QString& nameToMakeCurrent, bool manuallyEntered) { if (panel->syncBrowseButton->state() == SYNCBROWSE_CD) { //do sync-browse stuff.... if(syncURL.isEmpty()) syncURL = panel->otherPanel()->virtualPath(); QString relative = QDir(panel->virtualPath().path() + '/').relativeFilePath(url.path()); syncURL.setPath(QDir::cleanPath(syncURL.path() + '/' + relative)); panel->otherPanel()->gui->setLocked(false); otherFunc()->openUrlInternal(syncURL, nameToMakeCurrent, false, false); } openUrlInternal(url, nameToMakeCurrent, false, manuallyEntered); } void ListPanelFunc::immediateOpenUrl(const QUrl &url) { openUrlInternal(url, QString(), true, false); } void ListPanelFunc::openUrlInternal(const QUrl &url, const QString& nameToMakeCurrent, bool immediately, bool manuallyEntered) { const QUrl cleanUrl = cleanPath(url); if (panel->isLocked() && !files()->currentDirectory().matches(cleanUrl, QUrl::StripTrailingSlash)) { panel->_manager->newTab(url); urlManuallyEntered = false; return; } urlManuallyEntered = manuallyEntered; history->add(cleanUrl, nameToMakeCurrent); if(immediately) doRefresh(); else refresh(); } void ListPanelFunc::refresh() { panel->inlineRefreshCancel(); delayTimer.start(0); // to avoid qApp->processEvents() deadlock situaltion } void ListPanelFunc::doRefresh() { _refreshing = true; delayTimer.stop(); QUrl url = history->currentUrl(); if(!url.isValid()) { //FIXME go back in history here ? panel->slotStartUpdate(true); // refresh the panel urlManuallyEntered = false; _refreshing = false; return ; } panel->inlineRefreshCancel(); // if we are not refreshing to current URL bool isEqualUrl = files()->currentDirectory().matches(url, QUrl::StripTrailingSlash); if (!isEqualUrl) { panel->setCursor(Qt::WaitCursor); panel->view->clearSavedSelection(); } if(panel->fileSystemError) panel->fileSystemError->hide(); bool refreshFailed = false; while (true) { QUrl url = history->currentUrl(); isEqualUrl = files()->currentDirectory().matches(url, QUrl::StripTrailingSlash); // may get a new filesystem for this url FileSystem *fileSystem = FileSystemProvider::instance().getFilesystem(url, files()); fileSystem->setParentWindow(krMainWindow); connect(fileSystem, &FileSystem::aboutToOpenDir, &krMtMan, &KMountMan::autoMount, Qt::DirectConnection); if (fileSystem != fileSystemP) { panel->view->setFiles(0); // disconnect older signals disconnect(fileSystemP, 0, panel, 0); fileSystemP->deleteLater(); fileSystemP = fileSystem; // v != 0 so this is safe } else { if (fileSystemP->isRefreshing()) { delayTimer.start(100); /* if filesystem is busy try refreshing later */ return; } } // (re)connect filesystem signals disconnect(files(), 0, panel, 0); connect(files(), SIGNAL(refreshDone(bool)), panel, SLOT(slotStartUpdate(bool))); connect(files(), &FileSystem::fileSystemInfoChanged, panel, &ListPanel::updateFilesystemStats); connect(files(), SIGNAL(refreshJobStarted(KIO::Job*)), panel, SLOT(slotJobStarted(KIO::Job*))); connect(files(), SIGNAL(error(QString)), panel, SLOT(slotFilesystemError(QString))); panel->view->setFiles(files()); if(!history->currentItem().isEmpty() && isEqualUrl) { // if the url we're refreshing into is the current one, then the // partial refresh will not generate the needed signals to actually allow the // view to use nameToMakeCurrent. do it here instead (patch by Thomas Jarosch) panel->view->setCurrentItem(history->currentItem()); panel->view->makeItemVisible(panel->view->getCurrentKrViewItem()); } panel->view->setNameToMakeCurrent(history->currentItem()); int savedHistoryState = history->state(); // NOTE: this is blocking. Returns false on error or interruption (cancel requested or panel // was deleted) const bool refreshed = fileSystemP->refresh(url); if (refreshed) { // update the history and address bar, as the actual url might differ from the one requested history->setCurrentUrl(fileSystemP->currentDirectory()); panel->urlNavigator->setLocationUrl(fileSystemP->currentDirectory()); break; // we have a valid refreshed URL now } if (!panel || !panel->view) // this panel was deleted while refreshing return; refreshFailed = true; panel->view->setNameToMakeCurrent(QString()); if(history->state() != savedHistoryState) // don't go back if the history was touched break; if(!history->goBack()) { // put the root dir to the beginning of history, if it's not there yet if (!url.matches(QUrl::fromLocalFile(ROOT_DIR), QUrl::StripTrailingSlash)) history->pushBackRoot(); else break; } _ignoreFileSystemErrors = true; } _ignoreFileSystemErrors = false; panel->view->setNameToMakeCurrent(QString()); panel->setCursor(Qt::ArrowCursor); // on local file system change the working directory if (files()->isLocal()) QDir::setCurrent(KrServices::urlToLocalPath(files()->currentDirectory())); // see if the open url operation failed, and if so, // put the attempted url in the navigator bar and let the user change it if (refreshFailed) { if(isSyncing(url)) panel->otherPanel()->gui->syncBrowseButton->setChecked(false); else if(urlManuallyEntered) { panel->urlNavigator->setLocationUrl(url); if(panel == ACTIVE_PANEL) panel->editLocation(); } } if(otherFunc()->otherFunc() == this) // not true if our tab is not active otherFunc()->syncURL = QUrl(); urlManuallyEntered = false; refreshActions(); _refreshing = false; } void ListPanelFunc::redirectLink() { if (!files()->isLocal()) { KMessageBox::sorry(krMainWindow, i18n("You can edit links only on local file systems")); return ; } FileItem *fileitem = files()->getFileItem(panel->getCurrentName()); if (!fileitem) return ; QString file = fileitem->getUrl().path(); QString currentLink = fileitem->getSymDest(); if (currentLink.isEmpty()) { KMessageBox::sorry(krMainWindow, i18n("The current file is not a link, so it cannot be redirected.")); return ; } // ask the user for a new destination bool ok = false; QString newLink = QInputDialog::getText(krMainWindow, i18n("Link Redirection"), i18n("Please enter the new link destination:"), QLineEdit::Normal, currentLink, &ok); // if the user canceled - quit if (!ok || newLink == currentLink) return ; // delete the current link if (unlink(file.toLocal8Bit()) == -1) { KMessageBox::sorry(krMainWindow, i18n("Cannot remove old link: %1", file)); return ; } // try to create a new symlink if (symlink(newLink.toLocal8Bit(), file.toLocal8Bit()) == -1) { KMessageBox:: /* --=={ Patch by Heiner }==-- */sorry(krMainWindow, i18n("Failed to create a new link: %1", file)); return ; } } void ListPanelFunc::krlink(bool sym) { if (!files()->isLocal()) { KMessageBox::sorry(krMainWindow, i18n("You can create links only on local file systems")); return; } QString name = panel->getCurrentName(); // ask the new link name.. bool ok = false; QString linkName = QInputDialog::getText(krMainWindow, i18n("New Link"), i18n("Create a new link to: %1", name), QLineEdit::Normal, name, &ok); // if the user canceled - quit if (!ok || linkName == name) return; // if the name is already taken - quit if (files()->getFileItem(linkName) != 0) { KMessageBox::sorry(krMainWindow, i18n("A folder or a file with this name already exists.")); return; } // make link name and target absolute path if (linkName.left(1) != "/") linkName = files()->currentDirectory().path() + '/' + linkName; name = files()->getUrl(name).path(); if (sym) { if (symlink(name.toLocal8Bit(), linkName.toLocal8Bit()) == -1) KMessageBox::sorry(krMainWindow, i18n("Failed to create a new symlink '%1' to: '%2'", linkName, name)); } else { if (link(name.toLocal8Bit(), linkName.toLocal8Bit()) == -1) KMessageBox::sorry(krMainWindow, i18n("Failed to create a new link '%1' to '%2'", linkName, name)); } } void ListPanelFunc::view() { QString fileName = panel->getCurrentName(); if (fileName.isNull()) return ; // if we're trying to view a directory, just exit FileItem *fileitem = files()->getFileItem(fileName); if (!fileitem || fileitem->isDir()) return ; if (!fileitem->isReadable()) { KMessageBox::sorry(0, i18n("No permissions to view this file.")); return ; } // call KViewer. KrViewer::view(files()->getUrl(fileName)); // nothing more to it! } void ListPanelFunc::viewDlg() { // ask the user for a url to view QUrl dest = KChooseDir::getFile(i18n("Enter a URL to view:"), panel->virtualPath(), panel->virtualPath()); if (dest.isEmpty()) return ; // the user canceled KrViewer::view(dest); // view the file } void ListPanelFunc::terminal() { SLOTS->runTerminal(panel->realPath()); } void ListPanelFunc::edit() { KFileItem tmp; if (fileToCreate.isEmpty()) { QString name = panel->getCurrentName(); if (name.isNull()) return; fileToCreate = files()->getUrl(name); } tmp = KFileItem(fileToCreate); if (tmp.isDir()) { KMessageBox::sorry(krMainWindow, i18n("You cannot edit a folder")); fileToCreate = QUrl(); return ; } if (!tmp.isReadable()) { KMessageBox::sorry(0, i18n("No permissions to edit this file.")); fileToCreate = QUrl(); return; } KrViewer::edit(fileToCreate); fileToCreate = QUrl(); } void ListPanelFunc::editNew() { if(!fileToCreate.isEmpty()) return; // ask the user for the filename to edit fileToCreate = KChooseDir::getFile(i18n("Enter the filename to edit:"), panel->virtualPath(), panel->virtualPath()); if(fileToCreate.isEmpty()) return ; // the user canceled // if the file exists, edit it instead of creating a new one QFile f(fileToCreate.toLocalFile()); if(f.exists()) { edit(); } else { QTemporaryFile *tempFile = new QTemporaryFile; tempFile->open(); KIO::CopyJob *job = KIO::copy(QUrl::fromLocalFile(tempFile->fileName()), fileToCreate); job->setUiDelegate(0); job->setDefaultPermissions(true); connect(job, SIGNAL(result(KJob*)), SLOT(slotFileCreated(KJob*))); connect(job, SIGNAL(result(KJob*)), tempFile, SLOT(deleteLater())); } } void ListPanelFunc::slotFileCreated(KJob *job) { if(!job->error() || job->error() == KIO::ERR_FILE_ALREADY_EXIST) { KrViewer::edit(fileToCreate); if(KIO::upUrl(fileToCreate).matches(panel->virtualPath(), QUrl::StripTrailingSlash)) refresh(); else if(KIO::upUrl(fileToCreate).matches(panel->otherPanel()->virtualPath(), QUrl::StripTrailingSlash)) otherFunc()->refresh(); } else KMessageBox::sorry(krMainWindow, job->errorString()); fileToCreate = QUrl(); } void ListPanelFunc::copyFiles(bool enqueue, bool move) { const QStringList fileNames = panel->getSelectedNames(); if (fileNames.isEmpty()) return ; // safety QUrl destination = panel->otherPanel()->virtualPath(); const KConfigGroup group(krConfig, "Advanced"); const bool showDialog = move ? group.readEntry("Confirm Move", _ConfirmMove) : group.readEntry("Confirm Copy", _ConfirmCopy); if (showDialog) { QString operationText; if (move) { operationText = fileNames.count() == 1 ? i18n("Move %1 to:", fileNames.first()) : i18np("Move %1 file to:", "Move %1 files to:", fileNames.count()); } else { operationText = fileNames.count() == 1 ? i18n("Copy %1 to:", fileNames.first()) : i18np("Copy %1 file to:", "Copy %1 files to:", fileNames.count()); } // ask the user for the copy/move dest const KChooseDir::ChooseResult result = KChooseDir::getCopyDir(operationText, destination, panel->virtualPath()); destination = result.url; if (destination.isEmpty()) return ; // the user canceled enqueue = result.enqueue; } const JobMan::StartMode startMode = enqueue && krJobMan->isQueueModeEnabled() ? JobMan::Delay : !enqueue && !krJobMan->isQueueModeEnabled() ? JobMan::Start : JobMan::Enqueue; const QList fileUrls = files()->getUrls(fileNames); if (move) { // after the delete return the cursor to the first unmarked file above the current item panel->prepareToDelete(); } // make sure the user does not overwrite multiple files by mistake if (fileNames.count() > 1) { destination = FileSystem::ensureTrailingSlash(destination); } KIO::CopyJob::CopyMode mode = move ? KIO::CopyJob::Move : KIO::CopyJob::Copy; FileSystemProvider::instance().startCopyFiles(fileUrls, destination, mode, true, startMode); if(KConfigGroup(krConfig, "Look&Feel").readEntry("UnselectBeforeOperation", _UnselectBeforeOperation)) { panel->view->saveSelection(); panel->view->unselectAll(); } } // called from SLOTS to begin the renaming process void ListPanelFunc::rename() { panel->view->renameCurrentItem(); } // called by signal itemRenamed() from the view to complete the renaming process void ListPanelFunc::rename(const QString &oldname, const QString &newname) { if (oldname == newname) return ; // do nothing // set current after rename panel->view->setNameToMakeCurrent(newname); // as always - the filesystem do the job files()->rename(oldname, newname); } void ListPanelFunc::mkdir() { // ask the new dir name.. // suggested name is the complete name for the directories // while filenames are suggested without their extension QString suggestedName = panel->getCurrentName(); if (!suggestedName.isEmpty() && !files()->getFileItem(suggestedName)->isDir()) suggestedName = QFileInfo(suggestedName).completeBaseName(); QString dirName = QInputDialog::getText(krMainWindow, i18n("New folder"), i18n("Folder's name:"), QLineEdit::Normal, suggestedName); // if the user canceled - quit if (dirName.isEmpty()) return ; QStringList dirTree = dirName.split('/'); for (QStringList::Iterator it = dirTree.begin(); it != dirTree.end(); ++it) { if (*it == ".") continue; if (*it == "..") { immediateOpenUrl(QUrl::fromUserInput(*it, QString(), QUrl::AssumeLocalFile)); continue; } // check if the name is already taken if (files()->getFileItem(*it)) { // if it is the last dir to be created - quit if (*it == dirTree.last()) { KMessageBox::sorry(krMainWindow, i18n("A folder or a file with this name already exists.")); return ; } // else go into this dir else { immediateOpenUrl(QUrl::fromUserInput(*it, QString(), QUrl::AssumeLocalFile)); continue; } } panel->view->setNameToMakeCurrent(*it); // as always - the filesystem does the job files()->mkDir(*it); if (dirTree.count() > 1) immediateOpenUrl(QUrl::fromUserInput(*it, QString(), QUrl::AssumeLocalFile)); } // for } void ListPanelFunc::deleteFiles(bool reallyDelete) { if (files()->type() == FileSystem::FS_VIRTUAL && files()->isRoot()) { // only virtual deletion possible removeVirtualFiles(); return; } // first get the selected file names list QStringList fileNames = panel->getSelectedNames(); if (fileNames.isEmpty()) return; const KConfigGroup generalGroup(krConfig, "General"); bool moveToTrash = !reallyDelete && generalGroup.readEntry("Move To Trash", _MoveToTrash); // make sure this is possible moveToTrash = moveToTrash && files()->canMoveToTrash(fileNames); // now ask the user if he/she is sure: const KConfigGroup advancedGroup(krConfig, "Advanced"); if (advancedGroup.readEntry("Confirm Delete", _ConfirmDelete)) { QString s; // text KGuiItem b; // continue button if (moveToTrash) { s = i18np("Do you really want to move this item to the trash?", "Do you really want to move these %1 items to the trash?", fileNames.count()); b = KGuiItem(i18n("&Trash")); } else if (files()->type() == FileSystem::FS_VIRTUAL) { s = i18np("Do you really want to delete this item physically (not just " "removing it from the virtual items)?", "Do you really want to delete these %1 items physically (not just " "removing them from the virtual items)?", fileNames.count()); b = KStandardGuiItem::del(); } else { s = i18np("Do you really want to delete this item?", "Do you really want to delete these %1 items?", fileNames.count()); b = KStandardGuiItem::del(); } // 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, fileNames, i18n("Warning"), b) != KMessageBox::Continue) return; } // we want to warn the user about non empty dir bool emptyDirVerify = advancedGroup.readEntry("Confirm Unempty Dir", _ConfirmUnemptyDir); // TODO only local fs supported emptyDirVerify &= files()->isLocal(); if (emptyDirVerify) { for (const QString fileName: fileNames) { FileItem *fileItem = files()->getFileItem(fileName); if (fileItem && !fileItem->isSymLink() && fileItem->isDir()) { // read local dir... const QDir dir(fileItem->getUrl().path()); if (dir.entryList(QDir::TypeMask | QDir::System | QDir::Hidden).count() > 2) { // ...is not empty, ask user const KMessageBox::ButtonCode result = KMessageBox::warningYesNoCancel( krMainWindow, i18n("

Folder %1 is not empty.

Skip this one " "or delete all?

", fileName), QString(), KGuiItem(i18n("&Skip")), KGuiItem(i18n("&Delete All"))); if (result == KMessageBox::Yes) { fileNames.removeAll(fileName); // skip } else if (result == KMessageBox::No) { break; // accept all remaining } else { return; // cancel } } } } } if (fileNames.count() == 0) return; // nothing to delete // after the delete return the cursor to the first unmarked // file above the current item; panel->prepareToDelete(); // let the filesystem do the job... files()->deleteFiles(fileNames, moveToTrash); } void ListPanelFunc::removeVirtualFiles() { if (files()->type() != FileSystem::FS_VIRTUAL) { krOut << "filesystem not virtual"; return; } const QStringList fileNames = panel->getSelectedNames(); if (fileNames.isEmpty()) return; const QString text = i18np("Do you really want to delete this virtual item (physical files stay untouched)?", "Do you really want to delete these %1 virtual items (physical files stay " "untouched)?", fileNames.count()); if (KMessageBox::warningContinueCancelList(krMainWindow, text, fileNames, i18n("Warning"), KStandardGuiItem::remove()) != KMessageBox::Continue) return; VirtualFileSystem *fileSystem = static_cast(files()); fileSystem->remove(fileNames); } void ListPanelFunc::goInside(const QString& name) { openFileNameInternal(name, false); } void ListPanelFunc::runCommand(QString cmd) { krOut << "Run command: " << cmd; const QString workdir = panel->virtualPath().isLocalFile() ? panel->virtualPath().path() : QDir::homePath(); if(!KRun::runCommand(cmd, krMainWindow, workdir)) KMessageBox::error(0, i18n("Could not start %1", cmd)); } void ListPanelFunc::runService(const KService &service, QList urls) { krOut << "Run service: " << service.name(); KIO::DesktopExecParser parser(service, urls); QStringList args = parser.resultingArguments(); if (!args.isEmpty()) runCommand(KShell::joinArgs(args)); else KMessageBox::error(0, i18n("%1 cannot open %2", service.name(), KrServices::toStringList(urls).join(", "))); } void ListPanelFunc::displayOpenWithDialog(QList urls) { // NOTE: we are not using KRun::displayOpenWithDialog() because we want the commands working // directory to be the panel directory KOpenWithDialog dialog(urls, panel); dialog.hideRunInTerminal(); if (dialog.exec()) { KService::Ptr service = dialog.service(); if(!service) service = KService::Ptr(new KService(dialog.text(), dialog.text(), QString())); runService(*service, urls); } } QUrl ListPanelFunc::browsableArchivePath(const QString &filename) { FileItem *fileitem = files()->getFileItem(filename); QUrl url = files()->getUrl(filename); QString mime = fileitem->getMime(); if(url.isLocalFile()) { QString protocol = KrServices::registeredProtocol(mime); if(!protocol.isEmpty()) { url.setScheme(protocol); return url; } } return QUrl(); } // this is done when you double click on a file void ListPanelFunc::execute(const QString& name) { openFileNameInternal(name, true); } void ListPanelFunc::pack() { const QStringList fileNames = panel->getSelectedNames(); if (fileNames.isEmpty()) return ; // safety if (fileNames.count() == 0) return ; // nothing to pack // choose the default name QString defaultName = panel->virtualPath().fileName(); if (defaultName.isEmpty()) defaultName = "pack"; if (fileNames.count() == 1) defaultName = fileNames.first(); // ask the user for archive name and packer new PackGUI(defaultName, panel->otherPanel()->virtualPath().toDisplayString(QUrl::PreferLocalFile | QUrl::StripTrailingSlash), fileNames.count(), fileNames.first()); if (PackGUI::type.isEmpty()) { return ; // the user canceled } // check for partial URLs if (!PackGUI::destination.contains(":/") && !PackGUI::destination.startsWith('/')) { PackGUI::destination = panel->virtualPath().toDisplayString() + '/' + PackGUI::destination; } QString destDir = PackGUI::destination; if (!destDir.endsWith('/')) destDir += '/'; bool packToOtherPanel = (destDir == FileSystem::ensureTrailingSlash(panel->otherPanel()->virtualPath()).toDisplayString(QUrl::PreferLocalFile)); QUrl destURL = QUrl::fromUserInput(destDir + PackGUI::filename + '.' + PackGUI::type, QString(), QUrl::AssumeLocalFile); if (destURL.isLocalFile() && QFile::exists(destURL.path())) { QString msg = i18n("

The archive %1.%2 already exists. Do you want to overwrite it?

All data in the previous archive will be lost.

", PackGUI::filename, PackGUI::type); if (PackGUI::type == "zip") { msg = i18n("

The archive %1.%2 already exists. Do you want to overwrite it?

Zip will replace identically named entries in the zip archive or add entries for new names.

", PackGUI::filename, PackGUI::type); } if (KMessageBox::warningContinueCancel(krMainWindow, msg, QString(), KStandardGuiItem::overwrite()) == KMessageBox::Cancel) return ; // stop operation } else if (destURL.scheme() == QStringLiteral("virt")) { KMessageBox::error(krMainWindow, i18n("Cannot pack files onto a virtual destination.")); return; } PackJob * job = PackJob::createPacker(files()->currentDirectory(), destURL, fileNames, PackGUI::type, PackGUI::extraProps); job->setUiDelegate(new KIO::JobUiDelegate()); KIO::getJobTracker()->registerJob(job); job->ui()->setAutoErrorHandlingEnabled(true); if (packToOtherPanel) connect(job, SIGNAL(result(KJob*)), panel->otherPanel()->func, SLOT(refresh())); } void ListPanelFunc::testArchive() { const QStringList fileNames = panel->getSelectedNames(); if (fileNames.isEmpty()) return ; // safety TestArchiveJob * job = TestArchiveJob::testArchives(files()->currentDirectory(), fileNames); job->setUiDelegate(new KIO::JobUiDelegate()); KIO::getJobTracker()->registerJob(job); job->ui()->setAutoErrorHandlingEnabled(true); } void ListPanelFunc::unpack() { const QStringList fileNames = panel->getSelectedNames(); if (fileNames.isEmpty()) return ; // safety QString s; if (fileNames.count() == 1) s = i18n("Unpack %1 to:", fileNames[0]); else s = i18np("Unpack %1 file to:", "Unpack %1 files to:", fileNames.count()); // ask the user for the copy dest QUrl dest = KChooseDir::getDir(s, panel->otherPanel()->virtualPath(), panel->virtualPath()); if (dest.isEmpty()) return ; // the user canceled bool packToOtherPanel = (dest.matches(panel->otherPanel()->virtualPath(), QUrl::StripTrailingSlash)); UnpackJob * job = UnpackJob::createUnpacker(files()->currentDirectory(), dest, fileNames); job->setUiDelegate(new KIO::JobUiDelegate()); KIO::getJobTracker()->registerJob(job); job->ui()->setAutoErrorHandlingEnabled(true); if (packToOtherPanel) connect(job, SIGNAL(result(KJob*)), panel->otherPanel()->func, SLOT(refresh())); } // a small ugly function, used to prevent duplication of EVERY line of // code (maybe except 3) from createChecksum and matchChecksum static void checksum_wrapper(ListPanel *panel, QStringList& args, bool &folders) { KrViewItemList items; panel->view->getSelectedKrViewItems(&items); if (items.isEmpty()) return ; // nothing to do // determine if we need recursive mode (md5deep) folders = false; for (KrViewItemList::Iterator it = items.begin(); it != items.end(); ++it) { if (panel->func->getFileItem(*it)->isDir()) { folders = true; args << (*it)->name(); } else args << (*it)->name(); } } void ListPanelFunc::createChecksum() { QStringList args; bool folders; checksum_wrapper(panel, args, folders); CreateChecksumDlg dlg(args, folders, panel->realPath()); } void ListPanelFunc::matchChecksum() { QStringList args; bool folders; checksum_wrapper(panel, args, folders); QList checksumFiles = files()->searchFileItems(KRQuery(MatchChecksumDlg::checksumTypesFilter)); MatchChecksumDlg dlg(args, folders, panel->realPath(), (checksumFiles.size() == 1 ? checksumFiles[0]->getUrl().toDisplayString(QUrl::PreferLocalFile) : QString())); } -void ListPanelFunc::calcSpace(KrViewItem *item) +void ListPanelFunc::calcSpace() { - QStringList items; - if (item) { - items << item->name(); - } else { - panel->view->getSelectedItems(&items); - if (items.isEmpty()) { - panel->view->selectAllIncludingDirs(); - panel->view->getSelectedItems(&items); - if (items.isEmpty()) - return ; // nothing to do - } + QStringList fileNames; + panel->view->getSelectedItems(&fileNames); + if (fileNames.isEmpty()) { + // current file is ".." dummy file + panel->view->selectAllIncludingDirs(); + panel->view->getSelectedItems(&fileNames); } - QPointer calc = new KrCalcSpaceDialog(krMainWindow, panel, items, item != 0); - calc->exec(); - panel->slotUpdateTotals(); - delete calc; + SizeCalculator *sizeCalculator = new SizeCalculator(files()->getUrls(fileNames)); + connect(sizeCalculator, &SizeCalculator::calculated, this, &ListPanelFunc::slotSizeCalculated); + connect(sizeCalculator, &SizeCalculator::finished, panel, &ListPanel::slotUpdateTotals); + connect(this, &ListPanelFunc::destroyed, sizeCalculator, &SizeCalculator::deleteLater); + KrCalcSpaceDialog::showDialog(panel, sizeCalculator); +} + +void ListPanelFunc::slotSizeCalculated(const QUrl &url, KIO::filesize_t size) +{ + KrViewItem *item = panel->view->findItemByUrl(url); + if (!item) + return; + + item->setSize(size); + item->redraw(); } void ListPanelFunc::FTPDisconnect() { // you can disconnect only if connected! if (files()->isRemote()) { panel->_actions->actFTPDisconnect->setEnabled(false); panel->view->setNameToMakeCurrent(QString()); openUrl(QUrl::fromLocalFile(panel->realPath())); // open the last local URL } } void ListPanelFunc::newFTPconnection() { QUrl url = KRSpWidgets::newFTP(); // if the user canceled - quit if (url.isEmpty()) return ; panel->_actions->actFTPDisconnect->setEnabled(true); openUrl(url); } void ListPanelFunc::properties() { const QStringList names = panel->getSelectedNames(); if (names.isEmpty()) return ; // no names... KFileItemList fi; for (int i = 0 ; i < names.count() ; ++i) { FileItem *fileitem = files()->getFileItem(names[i]); if (!fileitem) continue; QUrl url = files()->getUrl(names[i]); fi.push_back(KFileItem(fileitem->getEntry(), url)); } if (fi.isEmpty()) return ; // Show the properties dialog KPropertiesDialog *dlg = new KPropertiesDialog(fi, krMainWindow); connect(dlg, SIGNAL(applied()), SLOT(refresh())); dlg->show(); } void ListPanelFunc::refreshActions() { panel->updateButtons(); if(ACTIVE_PANEL != panel) return; QString protocol = files()->currentDirectory().scheme(); krRemoteEncoding->setEnabled(protocol == "ftp" || protocol == "sftp" || protocol == "fish" || protocol == "krarc"); //krMultiRename->setEnabled( fileSystemType == FileSystem::FS_NORMAL ); // batch rename //krProperties ->setEnabled( fileSystemType == FileSystem::FS_NORMAL || fileSystemType == FileSystem::FS_FTP ); // file properties /* krUnpack->setEnabled(true); // unpack archive krTest->setEnabled(true); // test archive krSelect->setEnabled(true); // select a group by filter krSelectAll->setEnabled(true); // select all files krUnselect->setEnabled(true); // unselect by filter krUnselectAll->setEnabled( true); // remove all selections krInvert->setEnabled(true); // invert the selection krFTPConnect->setEnabled(true); // connect to an ftp krFTPNew->setEnabled(true); // create a new connection krAllFiles->setEnabled(true); // show all files in list krCustomFiles->setEnabled(true); // show a custom set of files krRoot->setEnabled(true); // go all the way up krExecFiles->setEnabled(true); // show only executables */ panel->_actions->setViewActions[panel->panelType]->setChecked(true); panel->_actions->actFTPDisconnect->setEnabled(files()->isRemote()); // allow disconnecting a network session panel->_actions->actCreateChecksum->setEnabled(files()->isLocal()); panel->_actions->actDirUp->setEnabled(!files()->isRoot()); panel->_actions->actRoot->setEnabled(!panel->virtualPath().matches(QUrl::fromLocalFile(ROOT_DIR), QUrl::StripTrailingSlash)); panel->_actions->actHome->setEnabled(!atHome()); panel->_actions->actHistoryBackward->setEnabled(history->canGoBack()); panel->_actions->actHistoryForward->setEnabled(history->canGoForward()); panel->view->op()->emitRefreshActions(); } FileSystem* ListPanelFunc::files() { if (!fileSystemP) fileSystemP = FileSystemProvider::instance().getFilesystem(QUrl::fromLocalFile("/")); return fileSystemP; } void ListPanelFunc::clipboardChanged(QClipboard::Mode mode) { if (mode == QClipboard::Clipboard && this == copyToClipboardOrigin) { disconnect(QApplication::clipboard(), 0, this, 0); copyToClipboardOrigin = 0; } } void ListPanelFunc::copyToClipboard(bool move) { const QStringList fileNames = panel->getSelectedNames(); if (fileNames.isEmpty()) return ; // safety QList fileUrls = files()->getUrls(fileNames); QMimeData *mimeData = new QMimeData; mimeData->setData("application/x-kde-cutselection", move ? "1" : "0"); mimeData->setUrls(fileUrls); if (copyToClipboardOrigin) disconnect(QApplication::clipboard(), 0, copyToClipboardOrigin, 0); copyToClipboardOrigin = this; QApplication::clipboard()->setMimeData(mimeData, QClipboard::Clipboard); connect(QApplication::clipboard(), SIGNAL(changed(QClipboard::Mode)), this, SLOT(clipboardChanged(QClipboard::Mode))); } void ListPanelFunc::pasteFromClipboard() { QClipboard * cb = QApplication::clipboard(); ListPanelFunc *origin = 0; if (copyToClipboardOrigin) { disconnect(QApplication::clipboard(), 0, copyToClipboardOrigin, 0); origin = copyToClipboardOrigin; copyToClipboardOrigin = 0; } bool move = false; const QMimeData *data = cb->mimeData(); if (data->hasFormat("application/x-kde-cutselection")) { QByteArray a = data->data("application/x-kde-cutselection"); if (!a.isEmpty()) move = (a.at(0) == '1'); // true if 1 } QList urls = data->urls(); if (urls.isEmpty()) return ; if(origin && KConfigGroup(krConfig, "Look&Feel").readEntry("UnselectBeforeOperation", _UnselectBeforeOperation)) { origin->panel->view->saveSelection(); for(KrViewItem *item = origin->panel->view->getFirst(); item != 0; item = origin->panel->view->getNext(item)) { if (urls.contains(item->getFileItem()->getUrl())) item->setSelected(false); } } files()->addFiles(urls, move ? KIO::CopyJob::Move : KIO::CopyJob::Copy); } ListPanelFunc* ListPanelFunc::otherFunc() { return panel->otherPanel()->func; } void ListPanelFunc::historyGotoPos(int pos) { if(history->gotoPos(pos)) refresh(); } void ListPanelFunc::historyBackward() { if(history->goBack()) refresh(); } void ListPanelFunc::historyForward() { if(history->goForward()) refresh(); } void ListPanelFunc::dirUp() { openUrl(KIO::upUrl(files()->currentDirectory()), files()->currentDirectory().fileName()); } void ListPanelFunc::home() { openUrl(QUrl::fromLocalFile(QDir::homePath())); } void ListPanelFunc::root() { openUrl(QUrl::fromLocalFile(ROOT_DIR)); } void ListPanelFunc::cdToOtherPanel() { openUrl(panel->otherPanel()->virtualPath()); } void ListPanelFunc::syncOtherPanel() { otherFunc()->openUrl(panel->virtualPath()); } bool ListPanelFunc::atHome() { return QUrl::fromLocalFile(QDir::homePath()).matches(panel->virtualPath(), QUrl::StripTrailingSlash); } diff --git a/krusader/Panel/panelfunc.h b/krusader/Panel/panelfunc.h index 5e05a17c..e8c19070 100644 --- a/krusader/Panel/panelfunc.h +++ b/krusader/Panel/panelfunc.h @@ -1,162 +1,164 @@ /*************************************************************************** panelfunc.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 PANELFUNC_H #define PANELFUNC_H #include "krviewitem.h" #include "../FileSystem/filesystem.h" // QtCore #include #include // QtGui #include #include class DirHistoryQueue; class ListPanel; class ListPanelFunc : public QObject { friend class ListPanel; Q_OBJECT public slots: void execute(const QString&); void goInside(const QString&); void navigatorUrlChanged(const QUrl &url); void openUrl(const QUrl &path, const QString& nameToMakeCurrent = QString(), bool manuallyEntered = false); void rename(const QString &oldname, const QString &newname); // actions void historyBackward(); void historyForward(); void dirUp(); void refresh(); void home(); void root(); void cdToOtherPanel(); void FTPDisconnect(); void newFTPconnection(); void terminal(); void view(); void viewDlg(); void edit(); void editNew(); // create a new textfile and edit it void moveFilesDelayed() { moveFiles(true); } void copyFilesDelayed() { copyFiles(true); } void moveFiles(bool enqueue = false) { copyFiles(enqueue, true); } void copyFiles(bool enqueue = false, bool move = false); /*! * asks the user the new directory name */ void mkdir(); void deleteFiles(bool reallyDelete = false); // delete virtual files or directories in virtual filesystem void removeVirtualFiles(); void rename(); void krlink(bool sym = true); void createChecksum(); void matchChecksum(); void pack(); void unpack(); void testArchive(); - // Calculate the occupied space of an item or the currently selected item and show it in a dialog - void calcSpace(KrViewItem *item = 0); + /** Calculate the occupied space of the currently selected items and show a dialog. */ + void calcSpace(); void properties(); void cut() { copyToClipboard(true); } void copyToClipboard(bool move = false); void pasteFromClipboard(); void syncOtherPanel(); public: ListPanelFunc(ListPanel *parent); ~ListPanelFunc(); FileSystem* files(); // return a pointer to the filesystem inline FileItem* getFileItem(KrViewItem *item) { return files()->getFileItem(item->name()); } inline FileItem* getFileItem(const QString& name) { return files()->getFileItem(name); } void refreshActions(); void redirectLink(); void runService(const KService &service, QList urls); void displayOpenWithDialog(QList urls); QUrl browsableArchivePath(const QString &); ListPanelFunc* otherFunc(); bool atHome(); bool ignoreFileSystemErrors() { return _ignoreFileSystemErrors; } protected slots: // Load the current url from history and refresh filesystem and panel to it. If this fails, try the // next url in history until success (last try is root) void doRefresh(); void slotFileCreated(KJob *job); // a file has been created by editNewFile() void historyGotoPos(int pos); void clipboardChanged(QClipboard::Mode mode); + // Update the directory size in view + void slotSizeCalculated(const QUrl &url, KIO::filesize_t size); protected: QUrl cleanPath(const QUrl &url); bool isSyncing(const QUrl &url); // when externallyExecutable == true, the file can be executed or opened with other software void openFileNameInternal(const QString &name, bool externallyExecutable); void immediateOpenUrl(const QUrl &url); void openUrlInternal(const QUrl &url, const QString& makeCurrent, bool immediately, bool manuallyEntered); void runCommand(QString cmd); ListPanel* panel; // our ListPanel DirHistoryQueue* history; FileSystem* fileSystemP; // pointer to fileSystem. QTimer delayTimer; QUrl syncURL; QUrl fileToCreate; // file that's to be created by editNewFile() bool urlManuallyEntered; static QPointer copyToClipboardOrigin; private: bool _refreshing; // ignore url changes while refreshing bool _ignoreFileSystemErrors; // ignore (repeated) errors emitted by filesystem; }; #endif diff --git a/krusader/defaults.h b/krusader/defaults.h index a811fd84..5661f038 100644 --- a/krusader/defaults.h +++ b/krusader/defaults.h @@ -1,342 +1,340 @@ /*************************************************************************** defaults.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 DEFAULTS_H #define DEFAULTS_H // QtGui #include /////////////////////// [Startup] // UI Save component Settings #define _UiSave true // Show Cmd Line #define _ShowCmdline false // Show status bar #define _ShowStatusBar true // Show actions tool bar #define _ShowActionsToolBar true // Show tool bar #define _ShowToolBar true // Show FN Keys #define _ShowFNkeys true // Show Terminal Emulator #define _ShowTerminalEmulator false // Remember Position #define _RememberPos true // Start to tray #define _StartToTray false // Left Tab Bar // Right Tab Bar // Size where lister is the default viewer #define _ListerLimit 10 ////////////////////////[Look&Feel] // Filelist Font /////// #define _FilelistFont QFontDatabase::systemFont(QFontDatabase::GeneralFont) // Warn On Exit //////// #define _WarnOnExit false // Minimize To Tray //// #define _MinimizeToTray false // Mark Dirs /////////// #define _MarkDirs false // Show Hidden ///////// #define _ShowHidden true // Sort By Extension /// #define _SortByExt false // Case Sensative Sort / #define _CaseSensativeSort false // Html Min Font Size // #define _HtmlMinFontSize 12 // Filelist Icon Size // #define _FilelistIconSize QString("22") // Mouse Selection ///// #define _MouseSelection 0 // 0 - normal (shift+click, ctrl+click), 1 - left click, 2 - right click // Use fullpath tab names ///// #define _FullPathTabNames false // User defined folder icons #define _UserDefinedFolderIcons true // Unslect files before copy/move #define _UnselectBeforeOperation true // Filter dialog remembers settings #define _FilterDialogRemembersSettings false // Panel Toolbar Checkboxes // Panel Toolbar Visible checkbox turned off #define _PanelToolBar true // cd / is turned on #define _cdRoot true // cd ~ is turned on #define _cdHome false // cd .. is turned on #define _cdUp true // cd other panel is turned on #define _cdOther false // syncBrowseButton is turned on #define _syncBrowseButton false // Use the default colors of KDE #define _KDEDefaultColors true // Enable Alternate Background colors #define _AlternateBackground true // Show current item even if not focused #define _ShowCurrentItemAlways false // Dim the colors of the inactive panel #define _DimInactiveColors false // Human Readable Size #define _HumanReadableSize true // With Icons #define _WithIcons true // Single Click Selects #define _SingleClickSelects false // Numeric Permissions #define _NumericPermissions false // Number of Columns in the Brief View #define _NumberOfBriefColumns 3 // Default Sort Method #define _DefaultSortMethod KrViewProperties::Krusader // Show splashscreen #define _ShowSplashScreen false // Single instance mode #define _SingleInstanceMode false /////////////////////// [General] // Move To Trash ////// #define _MoveToTrash true // Terminal /////////// #define _Terminal "konsole --separate" // Send CDs /////////// #define _SendCDs true // Editor ///////////// #define _Editor "internal editor" // Use Okteta as Hex viewer /////// #define _UseOktetaViewer false // Temp Directory ///// #define _TempDirectory "/tmp/krusader.tmp" // Classic Quicksearch #define _NewStyleQuicksearch true // Case Sensitive quick search, if _NewStyleQuicksearch is true #define _CaseSensitiveQuicksearch false // View In Separate Window #define _ViewInSeparateWindow false /////////////////////// [Advanced] // Permission Check /// //#define _PermCheck true // AutoMount ////////// #define _AutoMount false // Preserving date ////////// #define _PreserveAttributes false // Nonmount Points //// #define _NonMountPoints "/, " // Confirm Unempty Dir // (for delete) #define _ConfirmUnemptyDir true // Confirm Delete ///// (for deleting files) #define _ConfirmDelete true // Confirm Copy /////// (for copying files) #define _ConfirmCopy true // Confirm Move /////// (for moving files) #define _ConfirmMove true // Icon Cache Size //// #define _IconCacheSize 2048 /////////////////////// [Archives] // Do Tar ///////////// #define _DoTar true // Do GZip //////////// #define _DoGZip true // Do Zip ///////////// #define _DoZip true // Do UnZip /////////// #define _DoUnZip true // Do BZip2 /////////// #define _DoBZip2 true // Do LZMA /////////// #define _DoLZMA true // Do XZ /////////// #define _DoXZ true // Do Rar ///////////// #define _DoRar true // Do UnRar /////////// #define _DoUnRar true // Do UnAce /////////// #define _DoUnAce true // Do Arj ///////////// #define _DoArj true // Do UnArj /////////// #define _DoUnarj true // Do RPM ///////////// #define _DoRPM true // Do DEB ///////////// ====> new #define _DoDEB true // Do Lha ///////////// #define _DoLha true // Do 7z ///////////// ====> new #define _Do7z true // Allow Move Into Archive // #define _MoveIntoArchive false // Test Archives ////// #define _TestArchives false // Test Before Unpack //// #define _TestBeforeUnpack true // Supported Packers // ====> a QStringList of SYSTEM supported archives ( also new ) // default compression level #define _defaultCompressionLevel 5 // treat Archives as Directories #define _ArchivesAsDirectories true /////////////////////// [UserActions] // Terminal for UserActions /////////// #define _UserActions_Terminal "konsole --noclose --workdir %d --title %t -e" // Normal font for output collection /////// #define _UserActions_NormalFont QFontDatabase::systemFont(QFontDatabase::GeneralFont) // Font for output collection with fixed width /////// #define _UserActions_FixedFont QFontDatabase::systemFont(QFontDatabase::FixedFont) // Use for output collection fixed width font as default /////// #define _UserActions_UseFixedFont false /////////////////////// [Private] // Start Position ///// #define _StartPosition QPoint(QApplication::desktop()->width()/2 - MAIN_VIEW->sizeHint().width()/2,QApplication::desktop()->height()/2 - 250) // Start Size ///////// #define _StartSize QSize(MAIN_VIEW->sizeHint().width(),500) // Panel Size ///////// #define _PanelSize 0 // Terminal Size ////// #define _TerminalSize 0 // Left Name Size - size of the left panel's name column // Left Size Size - size of the left panel's size column // Left Date Size - size of the left panel's date column // Right Name Size - size of the right panel's name column // Right Size Size - size of the left panel's size column // Right Date Size - size of the left panel's date column // Splitter Sizes - sizes of the splitter /////////////////////// [RemoteMan] // Connections //////// // the basic connections are defined internally /////////////////////// [Search] // Saved Searches ///// // holds an index of saved searches // Confirm Feed to Listbox ///// (costum-name on feed ti listbox) #define _ConfirmFeedToListbox true /////////// here are additional variables used internally by Krusader //////////// // BookmarkArchives - The infobox about not allowing bookmarks inside archives // BackArchiveWarning - The infobox about not allowing to back up into archives // SupermountWarning - Warning about mounting/unmounting supermount filesystems // lastHomeRight - Save the last place the right list panel was showing // lastHomeLeft - Save the last place the left list panel was showing // lastUsedPacker - used by packGUI to remember the last used packer /////////////////////// [Popular Urls] // PopularUrls - a string list containing the top urls // PopularUrlsRank - an int list contains the urls' ranking /////////////////////// [Synchronize directories] // Don't overwrite automatically ///////////// #define _ConfirmOverWrites false // Recursive search in the subdirectories ///////////// #define _RecurseSubdirs true // The searcher follows symlinks ///////////// #define _FollowSymlinks false // Files with similar size are compared by content ///////////// #define _CompareByContent false // The date information is ignored at synchronization ///////////// #define _IgnoreDate false // Asymmetric Client-File Server compare mode ///////////// #define _Asymmetric false // Case insensitive compare in synchronizer ///////////// #define _IgnoreCase false // Scrolls the results of the synchronization ///////////// #define _ScrollResults false // The right arrow button is turned on ///////////// #define _BtnLeftToRight true // The equals button is turned on ///////////// #define _BtnEquals true // The not equals button is turned on ///////////// #define _BtnDifferents true // The left arrow button is turned on ///////////// #define _BtnRightToLeft true // The trash button is turned on ///////////// #define _BtnDeletable true // The duplicates button is turned on ///////////// #define _BtnDuplicates true // The singles button is turned on ///////////// #define _BtnSingles true /////////////////////// [Custom Selection Mode] // QT Selection #define _QtSelection false // Left Selects #define _LeftSelects true // Left Preserves #define _LeftPreserves false // ShiftCtrl Left Selects #define _ShiftCtrlLeft false // Right Selects #define _RightSelects true // Right Preserves #define _RightPreserves false // ShiftCtrl Right Selects #define _ShiftCtrlRight false // Space Moves Down #define _SpaceMovesDown true -// Space Calc Space -#define _SpaceCalcSpace true // Insert Moves Down #define _InsertMovesDown true // Immediate Context Menu #define _ImmediateContextMenu true // Root directory #ifdef Q_WS_WIN #define DIR_SEPARATOR "/" #define DIR_SEPARATOR2 "\\" #define DIR_SEPARATOR_CHAR '/' #define DIR_SEPARATOR_CHAR2 '\\' #define REPLACE_DIR_SEP2(x) x = x.replace( DIR_SEPARATOR2, DIR_SEPARATOR ); #define ROOT_DIR "C:\\" #define EXEC_SUFFIX ".exe" #else #define DIR_SEPARATOR "/" #define DIR_SEPARATOR2 "/" #define DIR_SEPARATOR_CHAR '/' #define DIR_SEPARATOR_CHAR2 '/' #define REPLACE_DIR_SEP2(x) #define ROOT_DIR "/" #define EXEC_SUFFIX "" #endif #endif