diff --git a/krusader/DiskUsage/diskusage.cpp b/krusader/DiskUsage/diskusage.cpp index 7710096a..f32a073e 100644 --- a/krusader/DiskUsage/diskusage.cpp +++ b/krusader/DiskUsage/diskusage.cpp @@ -1,1136 +1,1138 @@ /*************************************************************************** diskusage.cpp - description ------------------- copyright : (C) 2004 + by Csaba Karai e-mail : krusader@users.sourceforge.net web site : http://krusader.sourceforge.net --------------------------------------------------------------------------- Description *************************************************************************** A db dD d8888b. db db .d8888. .d8b. d8888b. d88888b d8888b. 88 ,8P' 88 `8D 88 88 88' YP d8' `8b 88 `8D 88' 88 `8D 88,8P 88oobY' 88 88 `8bo. 88ooo88 88 88 88ooooo 88oobY' 88`8b 88`8b 88 88 `Y8b. 88~~~88 88 88 88~~~~~ 88`8b 88 `88. 88 `88. 88b d88 db 8D 88 88 88 .8D 88. 88 `88. YP YD 88 YD ~Y8888P' `8888Y' YP YP Y8888D' Y88888P 88 YD S o u r c e F i l e *************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "diskusage.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../VFS/krpermhandler.h" #include "../VFS/krvfshandler.h" #include "../kicons.h" #include "../defaults.h" #include "../krglobal.h" #include "../Panel/krpanel.h" #include "../Panel/panelfunc.h" #include "filelightParts/Config.h" #include "dulines.h" #include "dulistview.h" #include "dufilelight.h" // these are the values that will exist in the menu #define DELETE_ID 90 #define EXCLUDE_ID 91 #define PARENT_DIR_ID 92 #define NEW_SEARCH_ID 93 #define REFRESH_ID 94 #define STEP_INTO_ID 95 #define INCLUDE_ALL_ID 96 #define VIEW_POPUP_ID 97 #define LINES_VIEW_ID 98 #define DETAILED_VIEW_ID 99 #define FILELIGHT_VIEW_ID 100 #define NEXT_VIEW_ID 101 #define PREVIOUS_VIEW_ID 102 #define ADDITIONAL_POPUP_ID 103 #define MAX_FILENUM 100 LoaderWidget::LoaderWidget(QWidget *parent) : QScrollArea(parent), cancelled(false) { QPalette palette = viewport()->palette(); palette.setColor(viewport()->backgroundRole(), Qt::white); viewport()->setPalette(palette); widget = new QWidget(parent); QGridLayout *loaderLayout = new QGridLayout(widget); loaderLayout->setSpacing(0); loaderLayout->setContentsMargins(0, 0, 0, 0); QFrame *loaderBox = new QFrame(widget); loaderBox->setFrameShape(QFrame::Box); loaderBox->setFrameShadow(QFrame::Sunken); loaderBox->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); loaderBox->setFrameStyle(QFrame::Panel + QFrame::Raised); loaderBox->setLineWidth(2); QGridLayout *synchGrid = new QGridLayout(loaderBox); synchGrid->setSpacing(6); synchGrid->setContentsMargins(11, 11, 11, 11); QLabel *titleLabel = new QLabel(i18n("Loading Usage Information"), loaderBox); titleLabel->setAlignment(Qt::AlignHCenter); synchGrid->addWidget(titleLabel, 0, 0, 1, 2); QLabel *filesLabel = new QLabel(i18n("Files:"), loaderBox); filesLabel->setFrameShape(QLabel::StyledPanel); filesLabel->setFrameShadow(QLabel::Sunken); synchGrid->addWidget(filesLabel, 1, 0); QLabel *directoriesLabel = new QLabel(i18n("Directories:"), loaderBox); directoriesLabel->setFrameShape(QLabel::StyledPanel); directoriesLabel->setFrameShadow(QLabel::Sunken); synchGrid->addWidget(directoriesLabel, 2, 0); QLabel *totalSizeLabel = new QLabel(i18n("Total Size:"), loaderBox); totalSizeLabel->setFrameShape(QLabel::StyledPanel); totalSizeLabel->setFrameShadow(QLabel::Sunken); synchGrid->addWidget(totalSizeLabel, 3, 0); files = new QLabel(loaderBox); files->setFrameShape(QLabel::StyledPanel); files->setFrameShadow(QLabel::Sunken); files->setAlignment(Qt::AlignRight); synchGrid->addWidget(files, 1, 1); directories = new QLabel(loaderBox); directories->setFrameShape(QLabel::StyledPanel); directories->setFrameShadow(QLabel::Sunken); directories->setAlignment(Qt::AlignRight); synchGrid->addWidget(directories, 2, 1); totalSize = new QLabel(loaderBox); totalSize->setFrameShape(QLabel::StyledPanel); totalSize->setFrameShadow(QLabel::Sunken); totalSize->setAlignment(Qt::AlignRight); synchGrid->addWidget(totalSize, 3, 1); int width; searchedDirectory = new KSqueezedTextLabel(loaderBox); searchedDirectory->setFrameShape(QLabel::StyledPanel); searchedDirectory->setFrameShadow(QLabel::Sunken); searchedDirectory->setMinimumWidth(width = QFontMetrics(searchedDirectory->font()).width("W") * 30); searchedDirectory->setMaximumWidth(width); synchGrid->addWidget(searchedDirectory, 4, 0, 1, 2); QFrame *line = new QFrame(loaderBox); line->setFrameStyle(QFrame::HLine | QFrame::Sunken); synchGrid->addWidget(line, 5, 0, 1, 2); QWidget *hboxWidget = new QWidget(loaderBox); QHBoxLayout * hbox = new QHBoxLayout(hboxWidget); QSpacerItem* spacer = new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding); hbox->addItem(spacer); QPushButton *cancelButton = new QPushButton(hboxWidget); cancelButton->setText(i18n("Cancel")); hbox->addWidget(cancelButton); synchGrid->addWidget(hboxWidget, 6, 1); loaderLayout->addWidget(loaderBox, 0, 0); setWidget(widget); setAlignment(Qt::AlignCenter); connect(cancelButton, SIGNAL(clicked()), this, SLOT(slotCancelled())); } void LoaderWidget::init() { cancelled = false; } void LoaderWidget::setCurrentURL(const QUrl &url) { searchedDirectory->setText(vfs::ensureTrailingSlash(url).toDisplayString(QUrl::PreferLocalFile)); } void LoaderWidget::setValues(int fileNum, int dirNum, KIO::filesize_t total) { files->setText(QString("%1").arg(fileNum)); directories->setText(QString("%1").arg(dirNum)); totalSize->setText(QString("%1").arg(KRpermHandler::parseSize(total).trimmed())); } void LoaderWidget::slotCancelled() { cancelled = true; } DiskUsage::DiskUsage(QString confGroup, QWidget *parent) : QStackedWidget(parent), currentDirectory(0), root(0), configGroup(confGroup), loading(false), abortLoading(false), clearAfterAbort(false), deleting(false), searchVfs(0) { listView = new DUListView(this); lineView = new DULines(this); filelightView = new DUFilelight(this); loaderView = new LoaderWidget(this); addWidget(listView); addWidget(lineView); addWidget(filelightView); addWidget(loaderView); setView(VIEW_LINES); Filelight::Config::read(); connect(&loadingTimer, SIGNAL(timeout()), this, SLOT(slotLoadDirectory())); } DiskUsage::~DiskUsage() { if (listView) // don't remove these lines. The module will crash at exit if removed delete listView; if (lineView) delete lineView; if (filelightView) delete filelightView; if (root) delete root; QHashIterator< File *, Properties * > lit(propertyMap); while (lit.hasNext()) delete lit.next().value(); } void DiskUsage::load(const QUrl &baseDir) { if (searchVfs && !searchVfs->vfs_canDelete()) { return; } fileNum = dirNum = 0; currentSize = 0; emit status(i18n("Loading the disk usage information...")); clear(); baseURL = baseDir.adjusted(QUrl::StripTrailingSlash); root = new Directory(baseURL.fileName(), baseDir.toDisplayString(QUrl::PreferLocalFile)); directoryStack.clear(); parentStack.clear(); directoryStack.push(""); parentStack.push(root); if (searchVfs) { delete searchVfs; searchVfs = 0; } searchVfs = KrVfsHandler::getVfs(baseDir); if (searchVfs == 0) { loading = abortLoading = clearAfterAbort = false; emit loadFinished(false); return; } searchVfs->vfs_setQuiet(true); currentVfile = 0; if (!loading) { viewBeforeLoad = activeView; setView(VIEW_LOADER); } loading = true; loaderView->init(); loaderView->setCurrentURL(baseURL); loaderView->setValues(fileNum, dirNum, currentSize); loadingTimer.setSingleShot(true); loadingTimer.start(0); } void DiskUsage::slotLoadDirectory() { if (searchVfs && !searchVfs->vfs_canDelete()) { // recursive call from slotLoadDirectory? loadingTimer.setSingleShot(true); loadingTimer.start(100); // as it can cause crash, ignore it and wait while return; // the recursion finishes } if ((currentVfile == 0 && directoryStack.isEmpty()) || loaderView->wasCancelled() || abortLoading) { if (searchVfs) delete searchVfs; searchVfs = 0; currentVfile = 0; setView(viewBeforeLoad); if (clearAfterAbort) clear(); else { calculateSizes(); changeDirectory(root); } emit loadFinished(!(loaderView->wasCancelled() || abortLoading)); loading = abortLoading = clearAfterAbort = false; } else if (loading) { for (int counter = 0; counter != MAX_FILENUM; counter ++) { if (currentVfile == 0) { if (directoryStack.isEmpty()) break; dirToCheck = directoryStack.pop(); currentParent = parentStack.pop(); contentMap.insert(dirToCheck, currentParent); QUrl url = baseURL; - if (!dirToCheck.isEmpty()) + if (!dirToCheck.isEmpty()) { url = url.adjusted(QUrl::StripTrailingSlash); url.setPath(url.path() + '/' + (dirToCheck)); + } #ifdef BSD if (url.isLocalFile() && url.path().left(7) == "/procfs") break; #else if (url.isLocalFile() && url.path().left(5) == "/proc") break; #endif loaderView->setCurrentURL(url); if (!searchVfs->vfs_refresh(url)) break; dirNum++; currentVfile = searchVfs->vfs_getFirstFile(); } else { fileNum++; File *newItem = 0; QString mime = currentVfile->vfile_getMime(true); // fast == not using mimetype magic if (currentVfile->vfile_isDir() && !currentVfile->vfile_isSymLink()) { newItem = new Directory(currentParent, currentVfile->vfile_getName(), dirToCheck, currentVfile->vfile_getSize(), currentVfile->vfile_getMode(), currentVfile->vfile_getOwner(), currentVfile->vfile_getGroup(), currentVfile->vfile_getPerm(), currentVfile->vfile_getTime_t(), currentVfile->vfile_isSymLink(), mime); directoryStack.push((dirToCheck.isEmpty() ? "" : dirToCheck + '/') + currentVfile->vfile_getName()); parentStack.push(dynamic_cast(newItem)); } else { newItem = new File(currentParent, currentVfile->vfile_getName(), dirToCheck, currentVfile->vfile_getSize(), currentVfile->vfile_getMode(), currentVfile->vfile_getOwner(), currentVfile->vfile_getGroup(), currentVfile->vfile_getPerm(), currentVfile->vfile_getTime_t(), currentVfile->vfile_isSymLink(), mime); currentSize += currentVfile->vfile_getSize(); } currentParent->append(newItem); currentVfile = searchVfs->vfs_getNextFile(); } } loaderView->setValues(fileNum, dirNum, currentSize); loadingTimer.setSingleShot(true); loadingTimer.start(0); } } void DiskUsage::stopLoad() { abortLoading = true; } void DiskUsage::close() { if (loading) { abortLoading = true; clearAfterAbort = true; } } void DiskUsage::dirUp() { if (currentDirectory != 0) { if (currentDirectory->parent() != 0) changeDirectory((Directory *)(currentDirectory->parent())); else { QUrl up = KIO::upUrl(baseURL); if (KMessageBox::questionYesNo(this, i18n("Stepping into the parent folder requires " "loading the content of the \"%1\" URL. Do you wish " "to continue?", up.toDisplayString(QUrl::PreferLocalFile)), i18n("Krusader::DiskUsage"), KStandardGuiItem::yes(), KStandardGuiItem::no(), "DiskUsageLoadParentDir" ) == KMessageBox::Yes) load(up); } } } Directory * DiskUsage::getDirectory(QString dir) { while (dir.endsWith('/')) dir.truncate(dir.length() - 1); if (dir.isEmpty()) return root; if (contentMap.find(dir) == contentMap.end()) return 0; return contentMap[ dir ]; } File * DiskUsage::getFile(QString path) { if (path.isEmpty()) return root; QString dir = path; int ndx = path.lastIndexOf('/'); QString file = path.mid(ndx + 1); if (ndx == -1) dir = ""; else dir.truncate(ndx); Directory *dirEntry = getDirectory(dir); if (dirEntry == 0) return 0; for (Iterator it = dirEntry->iterator(); it != dirEntry->end(); ++it) if ((*it)->name() == file) return *it; return 0; } void DiskUsage::clear() { baseURL = QUrl(); emit clearing(); QHashIterator< File *, Properties * > lit(propertyMap); while (lit.hasNext()) delete lit.next().value(); propertyMap.clear(); contentMap.clear(); if (root) delete root; root = currentDirectory = 0; } int DiskUsage::calculateSizes(Directory *dirEntry, bool emitSig, int depth) { int changeNr = 0; if (dirEntry == 0) dirEntry = root; KIO::filesize_t own = 0, total = 0; for (Iterator it = dirEntry->iterator(); it != dirEntry->end(); ++it) { File * item = *it; if (!item->isExcluded()) { if (item->isDir()) changeNr += calculateSizes(dynamic_cast(item), emitSig, depth + 1); else own += item->size(); total += item->size(); } } KIO::filesize_t oldOwn = dirEntry->ownSize(), oldTotal = dirEntry->size(); dirEntry->setSizes(total, own); if (dirEntry == currentDirectory) currentSize = total; if (emitSig && (own != oldOwn || total != oldTotal)) { emit changed(dirEntry); changeNr++; } if (depth == 0 && changeNr != 0) emit changeFinished(); return changeNr; } int DiskUsage::exclude(File *file, bool calcPercents, int depth) { int changeNr = 0; if (!file->isExcluded()) { file->exclude(true); emit changed(file); changeNr++; if (file->isDir()) { Directory *dir = dynamic_cast(file); for (Iterator it = dir->iterator(); it != dir->end(); ++it) changeNr += exclude(*it, false, depth + 1); } } if (calcPercents) { calculateSizes(root, true); calculatePercents(true); createStatus(); } if (depth == 0 && changeNr != 0) emit changeFinished(); return changeNr; } int DiskUsage::include(Directory *dir, int depth) { int changeNr = 0; if (dir == 0) return 0; for (Iterator it = dir->iterator(); it != dir->end(); ++it) { File *item = *it; if (item->isDir()) changeNr += include(dynamic_cast(item), depth + 1); if (item->isExcluded()) { item->exclude(false); emit changed(item); changeNr++; } } if (depth == 0 && changeNr != 0) emit changeFinished(); return changeNr; } void DiskUsage::includeAll() { include(root); calculateSizes(root, true); calculatePercents(true); createStatus(); } int DiskUsage::del(File *file, bool calcPercents, int depth) { int deleteNr = 0; if (file == root) return 0; KConfigGroup gg(krConfig, "General"); bool trash = gg.readEntry("Move To Trash", _MoveToTrash); QUrl url = QUrl::fromLocalFile(file->fullPath()); if (calcPercents) { // now ask the user if he want to delete: KConfigGroup ga(krConfig, "Advanced"); if (ga.readEntry("Confirm Delete", _ConfirmDelete)) { QString s, b; if (trash && url.isLocalFile()) { s = i18nc("singularOnly", "Do you really want to move this item to the trash?"); b = i18n("&Trash"); } else { s = i18nc("singularOnly", "Do you really want to delete this item?"); b = i18n("&Delete"); } QStringList name; name.append(file->fullPath()); // show message // note: i'm using continue and not yes/no because the yes/no has cancel as default button if (KMessageBox::warningContinueCancelList(krMainWindow, s, name, i18n("Warning"), KGuiItem(b)) != KMessageBox::Continue) return 0; } emit status(i18n("Deleting %1...", file->name())); } if (file == currentDirectory) dirUp(); if (file->isDir()) { Directory *dir = dynamic_cast(file); Iterator it; while ((it = dir->iterator()) != dir->end()) deleteNr += del(*it, false, depth + 1); QString path; for (const Directory *d = (Directory*)file; d != root && d && d->parent() != 0; d = d->parent()) { if (!path.isEmpty()) path = '/' + path; path = d->name() + path; } contentMap.remove(path); } emit deleted(file); deleteNr++; KIO::Job *job; if (trash) { job = KIO::trash(url); } else { job = KIO::del(QUrl::fromLocalFile(file->fullPath()), KIO::HideProgressInfo); } deleting = true; // during qApp->processEvent strange things can occur grabMouse(); // that's why we disable the mouse and keyboard events grabKeyboard(); job->exec(); delete job; releaseMouse(); releaseKeyboard(); deleting = false; ((Directory *)(file->parent()))->remove(file); delete file; if (depth == 0) createStatus(); if (calcPercents) { calculateSizes(root, true); calculatePercents(true); createStatus(); emit enteringDirectory(currentDirectory); } if (depth == 0 && deleteNr != 0) emit deleteFinished(); return deleteNr; } void * DiskUsage::getProperty(File *item, QString key) { QHash< File *, Properties *>::iterator itr = propertyMap.find(item); if (itr == propertyMap.end()) return 0; QHash::iterator it = (*itr)->find(key); if (it == (*itr)->end()) return 0; return it.value(); } void DiskUsage::addProperty(File *item, QString key, void * prop) { Properties *props; QHash< File *, Properties *>::iterator itr = propertyMap.find(item); if (itr == propertyMap.end()) { props = new Properties(); propertyMap.insert(item, props); } else props = *itr; props->insert(key, prop); } void DiskUsage::removeProperty(File *item, QString key) { QHash< File *, Properties *>::iterator itr = propertyMap.find(item); if (itr == propertyMap.end()) return; (*itr)->remove(key); if ((*itr)->count() == 0) propertyMap.remove(item); } void DiskUsage::createStatus() { Directory *dirEntry = currentDirectory; if (dirEntry == 0) return; QUrl url = baseURL; - if (dirEntry != root) + if (dirEntry != root) { url = url.adjusted(QUrl::StripTrailingSlash); url.setPath(url.path() + '/' + (dirEntry->directory())); + } emit status(i18n("Current folder:%1, Total size:%2, Own size:%3", url.toDisplayString(QUrl::PreferLocalFile | QUrl::StripTrailingSlash), ' ' + KRpermHandler::parseSize(dirEntry->size()), ' ' + KRpermHandler::parseSize(dirEntry->ownSize()))); } void DiskUsage::changeDirectory(Directory *dir) { currentDirectory = dir; currentSize = dir->size(); calculatePercents(true, dir); createStatus(); emit enteringDirectory(dir); } Directory* DiskUsage::getCurrentDir() { return currentDirectory; } void DiskUsage::rightClickMenu(const QPoint & pos, File *fileItem, QMenu *addPopup, QString addPopupName) { QMenu popup(this); popup.setTitle(i18n("Disk Usage")); QHash actionHash; if (fileItem != 0) { QAction * actDelete = popup.addAction(i18n("Delete")); actionHash[ actDelete ] = DELETE_ID; actDelete->setShortcut(Qt::Key_Delete); QAction * actExclude = popup.addAction(i18n("Exclude")); actionHash[ actExclude ] = EXCLUDE_ID; actExclude->setShortcut(Qt::CTRL + Qt::Key_E); popup.addSeparator(); } QAction * myAct = popup.addAction(i18n("Up one folder")); actionHash[ myAct ] = PARENT_DIR_ID; myAct->setShortcut(Qt::SHIFT + Qt::Key_Up); myAct = popup.addAction(i18n("New search")); actionHash[ myAct ] = NEW_SEARCH_ID; myAct->setShortcut(Qt::CTRL + Qt::Key_N); myAct = popup.addAction(i18n("Refresh")); actionHash[ myAct ] = REFRESH_ID; myAct->setShortcut(Qt::CTRL + Qt::Key_R); myAct = popup.addAction(i18n("Include all")); actionHash[ myAct ] = INCLUDE_ALL_ID; myAct->setShortcut(Qt::CTRL + Qt::Key_I); myAct = popup.addAction(i18n("Step into")); actionHash[ myAct ] = STEP_INTO_ID; myAct->setShortcut(Qt::SHIFT + Qt::Key_Down); popup.addSeparator(); if (addPopup != 0) { QAction * menu = popup.addMenu(addPopup); menu->setText(addPopupName); } QMenu viewPopup; myAct = viewPopup.addAction(i18n("Lines")); actionHash[ myAct ] = LINES_VIEW_ID; myAct->setShortcut(Qt::CTRL + Qt::Key_L); myAct = viewPopup.addAction(i18n("Detailed")); actionHash[ myAct ] = DETAILED_VIEW_ID; myAct->setShortcut(Qt::CTRL + Qt::Key_D); myAct = viewPopup.addAction(i18n("Filelight")); actionHash[ myAct ] = FILELIGHT_VIEW_ID; myAct->setShortcut(Qt::CTRL + Qt::Key_F); viewPopup.addSeparator(); myAct = viewPopup.addAction(i18n("Next")); actionHash[ myAct ] = NEXT_VIEW_ID; myAct->setShortcut(Qt::SHIFT + Qt::Key_Right); myAct = viewPopup.addAction(i18n("Previous")); actionHash[ myAct ] = PREVIOUS_VIEW_ID; myAct->setShortcut(Qt::SHIFT + Qt::Key_Left); QAction * menu = popup.addMenu(&viewPopup); menu->setText(i18n("View")); QAction * res = popup.exec(pos); if (actionHash.contains(res)) executeAction(actionHash[ res ], fileItem); } void DiskUsage::executeAction(int action, File * fileItem) { // check out the user's option switch (action) { case DELETE_ID: if (fileItem) del(fileItem); break; case EXCLUDE_ID: if (fileItem) exclude(fileItem); break; case PARENT_DIR_ID: dirUp(); break; case NEW_SEARCH_ID: emit newSearch(); break; case REFRESH_ID: load(baseURL); break; case INCLUDE_ALL_ID: includeAll(); break; case STEP_INTO_ID: { QString uri; if (fileItem && fileItem->isDir()) uri = fileItem->fullPath(); else uri = currentDirectory->fullPath(); ACTIVE_FUNC->openUrl(QUrl::fromLocalFile(uri)); } break; case LINES_VIEW_ID: setView(VIEW_LINES); break; case DETAILED_VIEW_ID: setView(VIEW_DETAILED); break; case FILELIGHT_VIEW_ID: setView(VIEW_FILELIGHT); break; case NEXT_VIEW_ID: setView((activeView + 1) % 3); break; case PREVIOUS_VIEW_ID: setView((activeView + 2) % 3); break; } // currentWidget()->setFocus(); } void DiskUsage::keyPressEvent(QKeyEvent *e) { if (activeView != VIEW_LOADER) { switch (e->key()) { case Qt::Key_E: if (e->modifiers() == Qt::ControlModifier) { executeAction(EXCLUDE_ID, getCurrentFile()); return; } case Qt::Key_D: if (e->modifiers() == Qt::ControlModifier) { executeAction(DETAILED_VIEW_ID); return; } case Qt::Key_F: if (e->modifiers() == Qt::ControlModifier) { executeAction(FILELIGHT_VIEW_ID); return; } case Qt::Key_I: if (e->modifiers() == Qt::ControlModifier) { executeAction(INCLUDE_ALL_ID); return; } break; case Qt::Key_L: if (e->modifiers() == Qt::ControlModifier) { executeAction(LINES_VIEW_ID); return; } case Qt::Key_N: if (e->modifiers() == Qt::ControlModifier) { executeAction(NEW_SEARCH_ID); return; } break; case Qt::Key_R: if (e->modifiers() == Qt::ControlModifier) { executeAction(REFRESH_ID); return; } break; case Qt::Key_Up: if (e->modifiers() == Qt::ShiftModifier) { executeAction(PARENT_DIR_ID); return; } break; case Qt::Key_Down: if (e->modifiers() == Qt::ShiftModifier) { executeAction(STEP_INTO_ID); return; } break; case Qt::Key_Left: if (e->modifiers() == Qt::ShiftModifier) { executeAction(PREVIOUS_VIEW_ID); return; } break; case Qt::Key_Right: if (e->modifiers() == Qt::ShiftModifier) { executeAction(NEXT_VIEW_ID); return; } break; case Qt::Key_Delete: if (!e->modifiers()) { executeAction(DELETE_ID, getCurrentFile()); return; } case Qt::Key_Plus: if (activeView == VIEW_FILELIGHT) { filelightView->zoomIn(); return; } break; case Qt::Key_Minus: if (activeView == VIEW_FILELIGHT) { filelightView->zoomOut(); return; } break; } } QStackedWidget::keyPressEvent(e); } QPixmap DiskUsage::getIcon(QString mime) { QPixmap icon; if (!QPixmapCache::find(mime, icon)) { // get the icon. if (mime == "Broken Link !") // FIXME: this doesn't work anymore - the reported mimetype for a broken link is now "unknown" icon = FL_LOADICON("file-broken"); else { QMimeDatabase db; QMimeType mt = db.mimeTypeForName(mime); if (mt.isValid()) icon = FL_LOADICON(mt.iconName()); else icon = FL_LOADICON("file-broken"); } // insert it into the cache QPixmapCache::insert(mime, icon); } return icon; } int DiskUsage::calculatePercents(bool emitSig, Directory *dirEntry, int depth) { int changeNr = 0; if (dirEntry == 0) dirEntry = root; for (Iterator it = dirEntry->iterator(); it != dirEntry->end(); ++it) { File *item = *it; if (!item->isExcluded()) { int newPerc; if (dirEntry->size() == 0 && item->size() == 0) newPerc = 0; else if (dirEntry->size() == 0) newPerc = -1; else newPerc = (int)((double)item->size() / (double)currentSize * 10000. + 0.5); int oldPerc = item->intPercent(); item->setPercent(newPerc); if (emitSig && newPerc != oldPerc) { emit changed(item); changeNr++; } if (item->isDir()) changeNr += calculatePercents(emitSig, dynamic_cast(item), depth + 1); } } if (depth == 0 && changeNr != 0) emit changeFinished(); return changeNr; } QString DiskUsage::getToolTip(File *item) { QMimeDatabase db; QMimeType mt = db.mimeTypeForName(item->mime()); QString mime; if (mt.isValid()) mime = mt.comment(); time_t tma = item->time(); struct tm* t = localtime((time_t *) & tma); QDateTime tmp(QDate(t->tm_year + 1900, t->tm_mon + 1, t->tm_mday), QTime(t->tm_hour, t->tm_min)); QString date = QLocale().toString(tmp, QLocale::ShortFormat); QString str = "
" + "" + ""; if (item->isDir()) str += ""; str += "" + "" + "" + "
" + i18n("Name:") + "" + item->name() + "
" + i18n("Type:") + "" + mime + "
" + i18n("Size:") + "" + KRpermHandler::parseSize(item->size()) + "
" + i18n("Own size:") + "" + KRpermHandler::parseSize(item->ownSize()) + "
" + i18n("Last modified:") + "" + date + "
" + i18n("Permissions:") + "" + item->perm() + "
" + i18n("Owner:") + "" + item->owner() + " - " + item->group() + "
"; str.replace(' ', " "); return str; } void DiskUsage::setView(int view) { switch (view) { case VIEW_LINES: setCurrentWidget(lineView); break; case VIEW_DETAILED: setCurrentWidget(listView); break; case VIEW_FILELIGHT: setCurrentWidget(filelightView); break; case VIEW_LOADER: setCurrentWidget(loaderView); break; } // currentWidget()->setFocus(); emit viewChanged(activeView = view); } File * DiskUsage::getCurrentFile() { File * file = 0; switch (activeView) { case VIEW_LINES: file = lineView->getCurrentFile(); break; case VIEW_DETAILED: file = listView->getCurrentFile(); break; case VIEW_FILELIGHT: file = filelightView->getCurrentFile(); break; } return file; } bool DiskUsage::event(QEvent * e) { if (deleting) { // if we are deleting, disable the mouse and switch (e->type()) { // keyboard events case QEvent::MouseButtonPress: case QEvent::MouseButtonRelease: case QEvent::MouseButtonDblClick: case QEvent::MouseMove: case QEvent::KeyPress: case QEvent::KeyRelease: return true; default: break; } } if (e->type() == QEvent::ShortcutOverride) { QKeyEvent* ke = (QKeyEvent*) e; if (ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::KeypadModifier) { switch (ke->key()) { case Qt::Key_Delete: case Qt::Key_Plus: case Qt::Key_Minus: ke->accept(); break; } } else if (ke->modifiers() == Qt::ShiftModifier) { switch (ke->key()) { case Qt::Key_Left: case Qt::Key_Right: case Qt::Key_Up: case Qt::Key_Down: ke->accept(); break; } } else if (ke->modifiers() & Qt::ControlModifier) { switch (ke->key()) { case Qt::Key_D: case Qt::Key_E: case Qt::Key_F: case Qt::Key_I: case Qt::Key_L: case Qt::Key_N: case Qt::Key_R: ke->accept(); break; } } } return QStackedWidget::event(e); } diff --git a/krusader/VFS/virtualcopyjob.cpp b/krusader/VFS/virtualcopyjob.cpp index f9635189..58482a29 100644 --- a/krusader/VFS/virtualcopyjob.cpp +++ b/krusader/VFS/virtualcopyjob.cpp @@ -1,412 +1,413 @@ /*************************************************************************** virtualcopyjob.cpp - description ------------------- copyright : (C) 2006 + 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 "virtualcopyjob.h" #include "vfs.h" #include "vfile.h" #include #include #include #include #include #include #define REPORT_TIMEOUT 200 class MyUiDelegate : public KIO::JobUiDelegate { public: MyUiDelegate(VirtualCopyJob * ref) : KIO::JobUiDelegate(), copyJobRef(ref) {} virtual KIO::RenameDialog_Result askFileRename(KJob * job, const QString & caption, const QUrl& src, const QUrl & dest, KIO::RenameDialog_Options mode, QString& newDest, KIO::filesize_t sizeSrc = (KIO::filesize_t) - 1, KIO::filesize_t sizeDest = (KIO::filesize_t) - 1, const QDateTime &ctimeSrc = QDateTime(), const QDateTime &ctimeDest = QDateTime(), const QDateTime &mtimeSrc = QDateTime(), const QDateTime &mtimeDest = QDateTime()) Q_DECL_OVERRIDE { if (copyJobRef->isSkipAll()) { if (mode & KIO::M_MULTI) return KIO::R_AUTO_SKIP; else return KIO::R_SKIP; } if (copyJobRef->isOverwriteAll()) { if (mode & KIO::M_MULTI) return KIO::R_OVERWRITE_ALL; else return KIO::R_OVERWRITE; } KIO::RenameDialog_Mode mmode = (KIO::RenameDialog_Mode)0; if (copyJobRef->isMulti()) mmode = (KIO::RenameDialog_Mode)(mmode | KIO::M_MULTI | KIO::M_SKIP); else mmode = (KIO::RenameDialog_Mode)(mmode /*| KIO::M_SINGLE*/); if (mode & KIO::M_OVERWRITE) mmode = (KIO::RenameDialog_Mode)(mmode | KIO::M_OVERWRITE); if (mode & KIO::M_OVERWRITE_ITSELF) mmode = (KIO::RenameDialog_Mode)(mmode | KIO::M_OVERWRITE_ITSELF); KIO::RenameDialog_Result res = KIO::JobUiDelegate::askFileRename(job, caption, src, dest, mode, newDest, sizeSrc, sizeDest, ctimeSrc, ctimeDest, mtimeSrc, mtimeDest); if (res == KIO::R_AUTO_SKIP) { copyJobRef->setSkipAll(); if (!(mode & KIO::M_MULTI)) res = KIO::R_SKIP; } if (res == KIO::R_OVERWRITE_ALL) { copyJobRef->setOverwriteAll(); if (!(mode & KIO::M_MULTI)) res = KIO::R_OVERWRITE; } return res; } virtual KIO::SkipDialog_Result askSkip(KJob * job, KIO::SkipDialog_Options options, const QString & error_text) Q_DECL_OVERRIDE { if (copyJobRef->isSkipAll()) { if (options & KIO::SkipDialog_MultipleItems) return KIO::S_AUTO_SKIP; else return KIO::S_SKIP; } KIO::SkipDialog_Result res = KIO::JobUiDelegate::askSkip(job, copyJobRef->isMulti() ? KIO::SkipDialog_MultipleItems: (KIO::SkipDialog_Option)0, error_text); if (res == KIO::S_AUTO_SKIP) { copyJobRef->setSkipAll(); if (!(options & KIO::SkipDialog_MultipleItems)) res = KIO::S_SKIP; } return res; } private: VirtualCopyJob * copyJobRef; }; VirtualCopyJob::VirtualCopyJob(const QStringList *names, vfs * vfs, const QUrl &dest, const QUrl& baseURL, PreserveMode pmode, KIO::CopyJob::CopyMode mode, bool showProgressInfo, bool autoStart) : KIO::Job(), m_overwriteAll(false), m_skipAll(false), m_multi(false), m_totalSize(0), m_totalFiles(0), m_totalSubdirs(0), m_processedSize(0), m_processedFiles(0), m_processedSubdirs(0), m_tempSize(0), m_tempFiles(0), m_dirsToGetSize(), m_filesToCopy(), m_size(), m_filenum(), m_subdirs(), m_baseURL(baseURL), m_dest(dest), m_pmode(pmode), m_mode(mode), m_showProgressInfo(showProgressInfo), m_state(ST_STARTING), m_reportTimer(), m_current(), m_currentDir(), m_dirStack() { m_dest = vfs->ensureTrailingSlash(m_dest); vfile * file = vfs->vfs_getFirstFile(); while (file) { if (names->contains(file->vfile_getName())) { QString relativeDir = QDir(baseURL.path()).relativeFilePath(KIO::upUrl(file->vfile_getUrl()).path()); if (m_filesToCopy.find(relativeDir) == m_filesToCopy.end()) { m_filesToCopy.insert(relativeDir, new QList()); // initialize the dir content m_size[ relativeDir ] = 0; m_filenum[ relativeDir ] = 0; m_subdirs[ relativeDir ] = 0; } QList *list = m_filesToCopy[ relativeDir ]; if (!list->contains(file->vfile_getUrl())) { if (file->vfile_isDir()) { m_dirsToGetSize.append(file->vfile_getUrl()); m_totalSubdirs++; m_subdirs[ relativeDir ]++; } else { m_totalFiles++; m_filenum[ relativeDir ]++; m_totalSize += file->vfile_getSize(); m_size[ relativeDir ] += file->vfile_getSize(); } list->append(file->vfile_getUrl()); } } file = vfs->vfs_getNextFile(); } if (showProgressInfo) { setUiDelegate(new MyUiDelegate(this)); KIO::getJobTracker()->registerJob(this); } if (autoStart) QTimer::singleShot(0, this, SLOT(slotStart())); } VirtualCopyJob::~VirtualCopyJob() { QHashIterator< QString, QList *> lit(m_filesToCopy); while (lit.hasNext()) delete lit.next().value(); } void VirtualCopyJob::slotStart() { connect(&m_reportTimer, SIGNAL(timeout()), this, SLOT(slotReport())); m_reportTimer.setSingleShot(false); m_reportTimer.start(REPORT_TIMEOUT); statNextDir(); } void VirtualCopyJob::slotReport() { switch (m_state) { case ST_CREATING_DIRECTORY: break; case ST_CALCULATING_TOTAL_SIZE: setTotalAmount(KJob::Bytes, m_totalSize); setTotalAmount(KJob::Directories, m_totalSubdirs); setTotalAmount(KJob::Files, m_totalFiles); break; case ST_COPYING: { setProcessedAmount(KJob::Directories, m_processedSubdirs); setProcessedAmount(KJob::Files, m_processedFiles + m_tempFiles); setProcessedAmount(KJob::Bytes, m_processedSize + m_tempSize); double percDbl = ((double)(m_processedSize + m_tempSize) / (double)m_totalSize) * 100. + 0.5; unsigned long perc = (long)percDbl; if (perc > 100) perc = 100; setPercent(perc); break; } default: break; } } void VirtualCopyJob::statNextDir() { m_state = ST_CALCULATING_TOTAL_SIZE; if (m_dirsToGetSize.count() == 0) { slotReport(); // report the total size values createNextDir(); return; } QUrl dirToCheck = m_dirsToGetSize.first(); m_dirsToGetSize.pop_front(); m_currentDir = QDir(m_baseURL.path()).relativeFilePath(KIO::upUrl(dirToCheck).path()); KIO::DirectorySizeJob* kds = KIO::directorySize(dirToCheck); connect(kds, SIGNAL(result(KJob*)), this, SLOT(slotKdsResult(KJob*))); } void VirtualCopyJob::slotKdsResult(KJob * job) { KIO::DirectorySizeJob* kds = static_cast(job); m_totalSize += kds->totalSize(); m_totalFiles += kds->totalFiles(); m_totalSubdirs += kds->totalSubdirs(); m_size[ m_currentDir ] += kds->totalSize(); m_filenum[ m_currentDir ] += kds->totalFiles(); m_subdirs[ m_currentDir ] += kds->totalSubdirs(); statNextDir(); } void VirtualCopyJob::createNextDir() { m_state = ST_CREATING_DIRECTORY; if (m_totalFiles + m_totalSubdirs > 1) m_multi = true; QHashIterator *> diter(m_filesToCopy); if (!diter.hasNext()) { emitResult(); return; } m_currentDir = diter.next().key(); m_current = m_dest; - if (m_currentDir != "./" && !m_currentDir.isEmpty()) + if (m_currentDir != "./" && !m_currentDir.isEmpty()) { m_current = m_current.adjusted(QUrl::StripTrailingSlash); m_current.setPath(m_current.path() + '/' + (m_currentDir)); + } KIO::Job *job = KIO::stat(m_current, KIO::HideProgressInfo); connect(job, SIGNAL(result(KJob*)), this, SLOT(slotStatResult(KJob*))); } void VirtualCopyJob::slotStatResult(KJob *job) { QUrl url = (static_cast(job))->url(); if (job && job->error()) { if (job->error() == KIO::ERR_DOES_NOT_EXIST && !url.matches(KIO::upUrl(url), QUrl::StripTrailingSlash)) { m_dirStack.push_back(url.fileName()); KIO::Job *job = KIO::stat(KIO::upUrl(url), KIO::HideProgressInfo); connect(job, SIGNAL(result(KJob*)), this, SLOT(slotStatResult(KJob*))); return; } job->uiDelegate()->showErrorMessage(); directoryFinished(m_currentDir); createNextDir(); return; } if (m_dirStack.count()) { url.setPath(vfs::ensureTrailingSlash(url).path() + m_dirStack.last()); m_dirStack.pop_back(); KIO::Job *mkdir_job = KIO::mkdir(url); connect(mkdir_job, SIGNAL(result(KJob*)), this, SLOT(slotMkdirResult(KJob*))); } else copyCurrentDir(); } void VirtualCopyJob::slotMkdirResult(KJob *job) { QUrl url = (static_cast(job))->url(); if (job && job->error()) { if (uiDelegate() && !m_skipAll) { KIO::JobUiDelegate *ui = static_cast(uiDelegate()); KIO::SkipDialog_Result skipResult = ui->askSkip(this, m_multi ? KIO::SkipDialog_MultipleItems: (KIO::SkipDialog_Option)0, job->errorString()); switch (skipResult) { case KIO::S_CANCEL: setError(KIO::ERR_USER_CANCELED); emitResult(); return; case KIO::S_AUTO_SKIP: m_skipAll = true; break; case KIO::S_SKIP: default: break; } } directoryFinished(m_currentDir); createNextDir(); return; } if (m_dirStack.count()) { url.setPath(vfs::ensureTrailingSlash(url).path() + m_dirStack.last()); m_dirStack.pop_back(); KIO::Job *mkdir_job = KIO::mkdir(url); connect(mkdir_job, SIGNAL(result(KJob*)), this, SLOT(slotMkdirResult(KJob*))); } else copyCurrentDir(); } void VirtualCopyJob::copyCurrentDir() { m_state = ST_COPYING; KIO::Job * copy_job = PreservingCopyJob::createCopyJob(m_pmode, *m_filesToCopy[ m_currentDir ], m_current, m_mode, false, false); copy_job->setParentJob(this); copy_job->setUiDelegate(new MyUiDelegate(this)); connect(copy_job, SIGNAL(copying(KIO::Job *, const QUrl &, const QUrl &)), this, SLOT(slotCopying(KIO::Job *, const QUrl &, const QUrl &))); connect(copy_job, SIGNAL(moving(KIO::Job *, const QUrl &, const QUrl &)), this, SLOT(slotMoving(KIO::Job *, const QUrl &, const QUrl &))); connect(copy_job, SIGNAL(processedFiles(KIO::Job *, unsigned long)), this, SLOT(slotProcessedFiles(KIO::Job *, unsigned long))); connect(copy_job, SIGNAL(processedSize(KJob *, qulonglong)), this, SLOT(slotProcessedSize(KJob *, qulonglong))); connect(copy_job, SIGNAL(result(KJob*)), this, SLOT(slotCopyResult(KJob*))); } void VirtualCopyJob::slotCopyResult(KJob *job) { if (job && job->error()) { setError(job->error()); setErrorText(job->errorText()); if (job->error() == KIO::ERR_USER_CANCELED) { emitResult(); return; } if (uiDelegate()) uiDelegate()->showErrorMessage(); setError(0); } directoryFinished(m_currentDir); createNextDir(); } void VirtualCopyJob::directoryFinished(const QString &name) { delete m_filesToCopy[ name ]; m_filesToCopy.remove(name); m_processedSize += m_size[ name ]; m_processedFiles += m_filenum[ name ]; m_processedSubdirs += m_subdirs[ name ]; m_tempSize = m_tempFiles = 0; m_size.remove(name); m_filenum.remove(name); m_subdirs.remove(name); } void VirtualCopyJob::slotCopying(KIO::Job *, const QUrl &src, const QUrl &dest) { emit description(this, i18nc("@title job", "Copying"), qMakePair(i18n("Source"), src.toDisplayString()), qMakePair(i18n("Destination"), dest.toDisplayString())); } void VirtualCopyJob::slotMoving(KIO::Job *, const QUrl &src, const QUrl &dest) { emit description(this, i18nc("@title job", "Moving"), qMakePair(i18n("Source"), src.toDisplayString()), qMakePair(i18n("Destination"), dest.toDisplayString())); } void VirtualCopyJob::slotProcessedFiles(KIO::Job *, unsigned long filenum) { m_tempFiles = filenum; } void VirtualCopyJob::slotProcessedSize(KJob *, qulonglong size) { m_tempSize = size; }