1 /*
2  *   File name:	k4dirstat.cpp
3  *   Summary:	The K4DirStat Application
4  *   License:	GPL - See file COPYING for details.
5  *
6  *   Author:	Stefan Hundhammer <kdirstat@gmx.de>
7  *		Joshua Hodosh <kdirstat@grumpypenguin.org>
8  *		Parts auto-generated by KDevelop
9  *
10  *   Updated:	2010-03-01
11  */
12 
13 #include "k4dirstat.h"
14 #include "settings.h"
15 
16 #include <unistd.h>
17 #include <QtGui/QDropEvent>
18 #include <QtGui/QPainter>
19 
20 #include <QStatusBar>
21 #include <kconfigdialog.h>
22 
23 #include <kactioncollection.h>
24 #include <krecentfilesaction.h>
25 #include <kstandardaction.h>
26 
27 #include <KLocalizedString>
28 #include <QFileDialog>
29 #include <QGuiApplication>
30 #include <kmessagebox.h>
31 #include <ktoggleaction.h>
32 #include <ktoolbar.h>
33 #include <ktoolinvocation.h>
34 #include <kurlrequesterdialog.h>
35 #include <kxmlguifactory.h>
36 
37 #include "kactivitytracker.h"
38 #include "kcleanupcollection.h"
39 #include "kdirstatsettings.h"
40 #include "kdirtree.h"
41 #include "kdirtreecache.h"
42 #include "kdirtreeview.h"
43 #include "kexcluderules.h"
44 #include "ktreemaptile.h"
45 #include "ktreemapview.h"
46 #include <KIO/ApplicationLauncherJob>
47 #include <KIO/JobUiDelegate>
48 #include <KHelpClient>
49 #include <KIconEngine>
50 #include <KIconLoader>
51 #include <QClipboard>
52 #include <QIcon>
53 #include <QList>
54 #include <QMenu>
55 #include <QSplitter>
56 #include <QStorageInfo>
57 #include <QLabel>
58 
59 #include "settings.h"
60 
61 #define USER_CLEANUPS 10 // Number of user cleanup actions
62 
63 #define ID_STATUS_MSG 1
64 #define ID_PACMAN 42
65 #define PACMAN_WIDTH 350
66 #define PACMAN_INTERVAL 75 // millisec
67 
68 using namespace KDirStat;
69 
icon(const QString & iconName)70 static QIcon icon(const QString &iconName) {
71   return QIcon(new KIconEngine(iconName, KIconLoader::global()));
72 }
73 
74 k4dirstat *k4dirstat::instance_ = NULL;
75 
k4dirstat()76 k4dirstat::k4dirstat()
77     : KXmlGuiWindow(),
78       // m_view(new k4dirstatView(this)),
79       m_printer(0) {
80   Q_ASSERT(instance_ == NULL);
81   instance_ = this;
82   // accept dnd
83   setAcceptDrops(true);
84 
85   // Simple inits
86 
87   _activityTracker = 0; // Might or might not be needed
88 
89   // Those will be created delayed, only when needed
90 
91   _settingsDialog = 0;
92   _feedbackDialog = 0;
93   _treemapView = 0;
94   _pacMan = 0;
95   _pacManDelimiter = 0;
96   _treemapViewHeight = 0;
97 
98   connect(QCoreApplication::instance(), SIGNAL(aboutToQuit()), this,
99           SLOT(triggerSaveConfig()));
100 
101   // Set up internal (mainWin -> mainWin) connections
102 
103   connect(this, SIGNAL(readConfig(void)), this, SLOT(readMainWinConfig(void)));
104 
105   connect(this, SIGNAL(saveConfig(void)), this, SLOT(saveMainWinConfig(void)));
106 
107   // Create main window
108 
109   _splitter = new QSplitter(Qt::Vertical, this);
110   setCentralWidget(_splitter);
111 
112   _treeView = new KDirTreeView(_splitter);
113 
114   connect(_treeView, SIGNAL(progressInfo(const QString &)), this,
115           SLOT(statusMsg(const QString &)));
116 
117   connect(_treeView->tree(), SIGNAL(selectionChanged(KDirTree*)), this,
118           SLOT(selectionChanged(KDirTree*)));
119 
120   connect(_treeView, SIGNAL(contextMenu(const QPoint &)),
121           this, SLOT(contextMenu(const QPoint &)));
122 
123   connect(this, SIGNAL(readConfig()), _treeView, SLOT(readConfig()));
124   connect(this, SIGNAL(saveConfig()), _treeView, SLOT(saveConfig()));
125 
126   connect(_treeView, SIGNAL(finished()), this,
127           SLOT(createTreemapViewDelayed()));
128   connect(_treeView, SIGNAL(aborted()), this, SLOT(createTreemapViewDelayed()));
129   connect(_treeView, SIGNAL(startingReading()), this,
130           SLOT(deleteTreemapView()));
131 
132   connect(_treeView, SIGNAL(startingReading()), this, SLOT(updateActions()));
133   connect(_treeView, SIGNAL(finished()), this, SLOT(updateActions()));
134   connect(_treeView, SIGNAL(aborted()), this, SLOT(updateActions()));
135 
136   // tell the KXmlGuiWindow that this is indeed the main widget
137   // setCentralWidget(m_view);
138 
139   // set up the elements of the status bar
140   initStatusBar();
141 
142   // then, setup our actions
143   setupActions();
144 
145   // setup the cleanup actions
146   initCleanups();
147 
148   _freeSpaceLabel = new QLabel();
149   statusBar()->addPermanentWidget(_freeSpaceLabel);
150   // add a status bar
151   statusBar()->show();
152 
153   // a call to KXmlGuiWindow::setupGUI() populates the GUI
154   // with actions, using KXMLGUI.
155   // It also applies the saved mainwindow settings, if any, and ask the
156   // mainwindow to automatically save settings if changed: window size,
157   // toolbar position, icon size, etc.
158   setupGUI();
159 
160   _treeViewContextMenu =
161       static_cast<QMenu *>(factory()->container("treeViewContextMenu", this));
162   _treemapContextMenu =
163       static_cast<QMenu *>(factory()->container("treemapContextMenu", this));
164 
165   readMainWinConfig();
166 
167   // Disable certain actions at startup
168 
169   _editCopy->setEnabled(false);
170   _reportMailToOwner->setEnabled(false);
171   _fileRefreshAll->setEnabled(false);
172   _fileRefreshSelected->setEnabled(false);
173   updateActions();
174 }
175 
~k4dirstat()176 k4dirstat::~k4dirstat() {}
177 
setupActions()178 void k4dirstat::setupActions() {
179 
180   _fileAskOpenDir =
181       KStandardAction::open(this, SLOT(fileAskOpenDir()), actionCollection());
182 
183   _fileAskOpenUrl = actionCollection()->addAction("file_open_url", this,
184                                                   SLOT(fileAskOpenUrl()));
185   _fileAskOpenUrl->setText(i18n("Open &URL..."));
186   _fileAskOpenUrl->setIcon(icon("konqueror"));
187 
188   _fileOpenRecent = KStandardAction::openRecent(
189       this, SLOT(fileOpenRecent(const QUrl &)), actionCollection());
190   _fileCloseDir =
191       KStandardAction::close(this, SLOT(fileCloseDir()), actionCollection());
192 
193   _fileRefreshAll = actionCollection()->addAction("file_refresh_all", this,
194                                                   SLOT(refreshAll()));
195   _fileRefreshAll->setText(i18n("Refresh &All"));
196   _fileRefreshAll->setIcon(icon("document-revert"));
197 
198   _fileRefreshSelected = actionCollection()->addAction(
199       "file_refresh_selected", this, SLOT(refreshSelected()));
200   _fileRefreshSelected->setText(i18n("Refresh &Selected"));
201 
202   _fileReadExcludedDir = actionCollection()->addAction(
203       "file_read_excluded_dir", this, SLOT(refreshSelected()));
204   _fileReadExcludedDir->setText(i18n("Read &Excluded Directory"));
205 
206   _fileContinueReadingAtMountPoint = actionCollection()->addAction(
207       "file_continue_reading_at_mount_point", this, SLOT(refreshSelected()));
208   _fileContinueReadingAtMountPoint->setText(
209       i18n("Continue Reading at &Mount Point"));
210   _fileContinueReadingAtMountPoint->setIcon(icon("drive-harddisk"));
211 
212   _fileStopReading = actionCollection()->addAction("file_stop_reading", this,
213                                                    SLOT(stopReading()));
214   _fileStopReading->setText(i18n("Stop Rea&ding"));
215   _fileStopReading->setIcon(icon("process-stop"));
216 
217   _fileAskWriteCache = actionCollection()->addAction(
218       "file_ask_write_cache", this, SLOT(askWriteCache()));
219   _fileAskWriteCache->setText(i18n("&Write to Cache File..."));
220   _fileAskWriteCache->setIcon(icon("document-export"));
221 
222   _fileAskReadCache = actionCollection()->addAction("file_ask_read_cache", this,
223                                                     SLOT(askReadCache()));
224   _fileAskReadCache->setText(i18n("&Read Cache File..."));
225   _fileAskReadCache->setIcon(icon("document-import"));
226 
227   _fileQuit = KStandardAction::quit(QCoreApplication::instance(), SLOT(quit()),
228                                     actionCollection());
229   _editCopy = KStandardAction::copy(this, SLOT(editCopy()), actionCollection());
230 
231   _cleanupOpenWith = actionCollection()->addAction("cleanup_open_with", this,
232                                                    SLOT(cleanupOpenWith()));
233   _cleanupOpenWith->setText(i18n("Open With"));
234 
235   _treemapZoomIn = actionCollection()->addAction("treemap_zoom_in", this,
236                                                  SLOT(treemapZoomIn()));
237   _treemapZoomIn->setText(i18n("Zoom in"));
238   _treemapZoomIn->setIcon(icon("zoom-in"));
239   actionCollection()->setDefaultShortcut(_treemapZoomIn, Qt::Key_Plus);
240 
241   _treemapZoomOut = actionCollection()->addAction("treemap_zoom_out", this,
242                                                   SLOT(treemapZoomOut()));
243   _treemapZoomOut->setText(i18n("Zoom out"));
244   _treemapZoomOut->setIcon(icon("zoom-out"));
245   actionCollection()->setDefaultShortcut(_treemapZoomOut, Qt::Key_Minus);
246 
247   _treemapSelectParent = actionCollection()->addAction(
248       "treemap_select_parent", this, SLOT(treemapSelectParent()));
249   _treemapSelectParent->setText(i18n("Select Parent"));
250   _treemapSelectParent->setIcon(icon("go-up"));
251   actionCollection()->setDefaultShortcut(_treemapSelectParent,
252                                          Qt::Key_Asterisk);
253 
254   _treemapRebuild = actionCollection()->addAction("treemap_rebuild", this,
255                                                   SLOT(treemapRebuild()));
256   _treemapRebuild->setText(i18n("Rebuild Treemap"));
257 
258   _showTreemapView =
259       new KToggleAction(i18n("Show Treemap"), actionCollection());
260   actionCollection()->addAction("options_show_treemap", _showTreemapView);
261   //_showTreemapView->set
262   connect(_showTreemapView, SIGNAL(triggered()), this,
263           SLOT(toggleTreemapView()));
264   actionCollection()->setDefaultShortcut(_showTreemapView, Qt::Key_F9);
265 
266   QAction *newAct =
267       actionCollection()->addAction("treemap_help", this, SLOT(treemapHelp()));
268   newAct->setText(i18n("Help about Treemaps"));
269   newAct->setIcon(icon("help-contents"));
270 
271   QAction *pref = KStandardAction::preferences(this, SLOT(preferences()),
272                                                actionCollection());
273 
274   _reportMailToOwner = actionCollection()->addAction(
275       "report_mail_to_owner", _treeView, SLOT(sendMailToOwner()));
276   _reportMailToOwner->setText(i18n("Send &Mail to Owner"));
277   _reportMailToOwner->setIcon(icon("mail-message-new"));
278 
279   // _helpSendFeedbackMail =
280   // actionCollection()->addAction("help_send_feedback_mail",this,
281   // SLOT(sendFeedbackMail())); _helpSendFeedbackMail->setText(i18n("Send
282   // &Feedback Mail"));
283 
284   _fileAskOpenDir->setStatusTip(i18n("Opens a directory"));
285   _fileAskOpenUrl->setStatusTip(i18n("Opens a (possibly remote) directory"));
286   _fileOpenRecent->setStatusTip(i18n("Opens a recently used directory"));
287   _fileCloseDir->setStatusTip(i18n("Closes the current directory"));
288   _fileRefreshAll->setStatusTip(i18n("Re-reads the entire directory tree"));
289   _fileRefreshSelected->setStatusTip(i18n("Re-reads the selected subtree"));
290   _fileReadExcludedDir->setStatusTip(
291       i18n("Scan directory tree that was previously excluded"));
292   _fileContinueReadingAtMountPoint->setStatusTip(
293       i18n("Scan mounted file systems"));
294   _fileStopReading->setStatusTip(i18n("Stops directory reading"));
295   _fileAskWriteCache->setStatusTip(
296       i18n("Writes the current directory tree to a cache file that can be "
297            "loaded much faster"));
298   _fileAskReadCache->setStatusTip(
299       i18n("Reads a directory tree from a cache file"));
300   _fileQuit->setStatusTip(i18n("Quits the application"));
301   _editCopy->setStatusTip(
302       i18n("Copies the URL of the selected item to the clipboard"));
303   _cleanupOpenWith->setStatusTip(
304       i18n("Open file or directory with arbitrary application"));
305   _showTreemapView->setStatusTip(i18n("Enables/disables the treemap view"));
306   _treemapZoomIn->setStatusTip(i18n("Zoom treemap in"));
307   _treemapZoomOut->setStatusTip(i18n("Zoom treemap out"));
308   _treemapSelectParent->setStatusTip(i18n("Select parent"));
309   _treemapRebuild->setStatusTip(
310       i18n("Rebuild treemap to fit into available space"));
311   pref->setStatusTip(i18n("Opens the preferences dialog"));
312   _reportMailToOwner->setStatusTip(
313       i18n("Sends a mail to the owner of the selected subtree"));
314 
315   // custom menu and menu item - the slot is in the class k4dirstatView
316   // KAction *custom = new KAction(KIcon("colorize"), i18n("Swi&tch Colors"),
317   // this); actionCollection()->addAction( QLatin1String("switch_action"), custom
318   // ); connect(custom, SIGNAL(triggered(bool)), m_view, SLOT(switchColors()));
319 }
320 
initCleanups()321 void k4dirstat::initCleanups() {
322   _cleanupCollection = new KCleanupCollection(*actionCollection());
323   _cleanupCollection->setParent(this);
324   Q_CHECK_PTR(_cleanupCollection);
325   _cleanupCollection->addStdCleanups();
326   _cleanupCollection->addUserCleanups(USER_CLEANUPS);
327   _cleanupCollection->readConfig();
328 
329   connect(_treeView->tree(), SIGNAL(selectionChanged(KDirTree*)),
330           _cleanupCollection, SIGNAL(selectionChanged(KDirTree*)));
331 
332   connect(this, SIGNAL(readConfig(void)), _cleanupCollection,
333           SLOT(readConfig(void)));
334 
335   connect(this, SIGNAL(saveConfig(void)), _cleanupCollection,
336           SLOT(saveConfig(void)));
337 }
338 
revertCleanupsToDefaults()339 void k4dirstat::revertCleanupsToDefaults() {
340   _cleanupCollection->revertToDefault(USER_CLEANUPS);
341 }
342 
initStatusBar()343 void k4dirstat::initStatusBar() { statusBar()->showMessage(i18n("Ready.")); }
344 
openURL(const QUrl & url)345 void k4dirstat::openURL(const QUrl &url) {
346   statusMsg(i18n("Opening directory..."));
347 
348   _treeView->openURL(url);
349   _fileOpenRecent->addUrl(url);
350   _fileRefreshAll->setEnabled(true);
351   setCaption(url.fileName(), false);
352 
353   statusMsg(i18n("Ready."));
354 }
355 
readMainWinConfig()356 void k4dirstat::readMainWinConfig() {
357   KConfigGroup config = KSharedConfig::openConfig()->group("General Options");
358 
359   // Status settings of the various bars and views
360 
361   _showTreemapView->setChecked(config.readEntry("Show Treemap", true));
362   toggleTreemapView();
363 
364   // Position settings of the various bars
365 
366   // KToolBar::BarPosition toolBarPos;
367   // toolBarPos = ( KToolBar::BarPosition ) config->readEntry( "ToolBarPos",
368   // KToolBar::Top ); toolBar( "mainToolBar" )->setBarPos( toolBarPos );
369 
370   _treemapViewHeight = config.readEntry("TreemapViewHeight", 250);
371 
372   // initialize the recent file list
373   _fileOpenRecent->loadEntries(config);
374 
375   QSize size = config.readEntry("Geometry", QSize());
376 
377   if (!size.isEmpty())
378     resize(size);
379 
380   config = KSharedConfig::openConfig()->group("Animation");
381   _treeView->enablePacManAnimation(config.readEntry("DirTreePacMan", false));
382 
383   config = KSharedConfig::openConfig()->group("Exclude");
384   QStringList excludeRules = config.readEntry("ExcludeRules", QStringList());
385   KExcludeRules::excludeRules()->clear();
386 
387   for (QStringList::Iterator it = excludeRules.begin();
388        it != excludeRules.end(); ++it) {
389     QString ruleText = *it;
390     KExcludeRules::excludeRules()->add(new KExcludeRule(QRegExp(ruleText)));
391     qDebug() << "Adding exclude rule: " << ruleText << Qt::endl;
392   }
393 
394   if (excludeRules.size() == 0)
395     qDebug() << "No exclude rules defined" << Qt::endl;
396 }
397 
saveMainWinConfig()398 void k4dirstat::saveMainWinConfig() {
399   KConfigGroup config = KSharedConfig::openConfig()->group("General Options");
400   _fileOpenRecent->saveEntries(config);
401   config.writeEntry("Show Treemap", _showTreemapView->isChecked());
402   if (_treemapView)
403     config.writeEntry("TreemapViewHeight", _treemapView->height());
404 }
405 
406 //============================================================================
407 //				     Slots
408 //============================================================================
409 
fileAskOpenDir()410 void k4dirstat::fileAskOpenDir() {
411   statusMsg(i18n("Opening directory..."));
412   QUrl url =
413       QFileDialog::getExistingDirectoryUrl(this, i18n("Open Directory..."));
414 
415   if (!url.isEmpty())
416     openURL(url);
417 
418   statusMsg(i18n("Ready."));
419 }
420 
fileAskOpenUrl()421 void k4dirstat::fileAskOpenUrl() {
422   statusMsg(i18n("Opening URL..."));
423 
424   QUrl url = KUrlRequesterDialog::getUrl(QUrl(), // startDir
425                                          this, i18n("Open URL..."));
426 
427   if (!url.isEmpty())
428     openURL(fixedUrl(url.url()));
429 
430   statusMsg(i18n("Ready."));
431 }
432 
fileOpenRecent(const QUrl & url)433 void k4dirstat::fileOpenRecent(const QUrl &url) {
434   statusMsg(i18n("Opening directory..."));
435 
436   if (!url.isEmpty())
437     openURL(fixedUrl(url.url()));
438 
439   statusMsg(i18n("Ready."));
440 }
441 
fileCloseDir()442 void k4dirstat::fileCloseDir() {
443   statusMsg(i18n("Closing directory..."));
444 
445   _treeView->clear();
446   _fileRefreshAll->setEnabled(false);
447   close();
448 
449   statusMsg(i18n("Ready."));
450 }
451 
refreshAll()452 void k4dirstat::refreshAll() {
453   statusMsg(i18n("Refreshing directory tree..."));
454   _treeView->refreshAll();
455   statusMsg(i18n("Ready."));
456 }
457 
refreshSelected()458 void k4dirstat::refreshSelected() {
459   statusMsg(i18n("Refreshing selected subtree..."));
460   auto sel = _treeView->tree()->selection();
461   for(auto it = sel.begin(); it != sel.end(); ++it)
462     if(!(*it)->isDotEntry())
463     _treeView->tree()->refresh(*it);
464   statusMsg(i18n("Ready."));
465 }
466 
stopReading()467 void k4dirstat::stopReading() { _treeView->abortReading(); }
468 
askWriteCache()469 void k4dirstat::askWriteCache() {
470   QString file_name;
471 
472   do {
473     file_name = QFileDialog::getSaveFileName(this, i18n("Write to Cache File"),
474                                              DEFAULT_CACHE_NAME);
475 
476     if (file_name.isEmpty()) // user hit "cancel"
477       return;
478 
479     if (access(file_name.toLatin1(), F_OK) == 0) // file exists
480     {
481       int button = KMessageBox::questionYesNoCancel(
482           this, i18n("File %1 exists. Overwrite?", file_name),
483           i18n("Overwrite?")); // caption
484 
485       if (button == KMessageBox::Cancel)
486         return;
487       if (button == KMessageBox::No)
488         file_name = "";
489     }
490   } while (file_name.isEmpty());
491 
492   statusMsg(i18n("Writing cache file..."));
493 
494   if (!_treeView || !_treeView->writeCache(file_name)) {
495     QString errMsg = i18n("Error writing cache file %1", file_name);
496     statusMsg(errMsg);
497     KMessageBox::sorry(this, errMsg,
498                        i18n("Write Error")); // caption
499   }
500 
501   statusMsg(i18n("Wrote cache file %1", file_name));
502 }
503 
askReadCache()504 void k4dirstat::askReadCache() {
505   QString file_name = QFileDialog::getOpenFileName(
506       this, i18n("Read Cache File"), DEFAULT_CACHE_NAME);
507 
508   if (!file_name.isNull() && _treeView) {
509     statusMsg(i18n("Reading cache file..."));
510     _fileRefreshAll->setEnabled(true);
511     _treeView->readCache(file_name);
512   }
513 }
514 
editCopy()515 void k4dirstat::editCopy() {
516   if (_treeView->selection()) {
517     QGuiApplication *app =
518         dynamic_cast<QGuiApplication *>(QCoreApplication::instance());
519     if (app)
520       app->clipboard()->setText(_treeView->selection()->url());
521   }
522 
523 #if 0
524 #warning debug
525     if ( _activityTracker )
526         _activityTracker->trackActivity( 800 );
527 #endif
528 }
529 
cleanupOpenWith()530 void k4dirstat::cleanupOpenWith() {
531   if (!_treeView->selection())
532     return;
533 
534   KFileInfo *sel = _treeView->selection();
535 
536   if (sel->isDotEntry())
537     return;
538 
539   QList<QUrl> urlList;
540   urlList.append(QUrl::fromUserInput(sel->url(), QDir::currentPath(),
541                                      QUrl::AssumeLocalFile));
542   auto *job = new KIO::ApplicationLauncherJob();
543   job->setUrls(urlList);
544   job->setUiDelegate(new KIO::JobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, this));
545   job->start();
546 }
547 
atLeastOneNotDotEntry(KDirTree * tree)548 bool atLeastOneNotDotEntry(KDirTree * tree) {
549   auto sel = tree->selection();
550   for(auto it = sel.begin(); it != sel.end(); ++it) {
551     if((*it)->isDotEntry())
552       return false;
553   }
554   return true;
555 }
556 
selectionChanged(KDirTree * tree)557 void k4dirstat::selectionChanged(KDirTree* tree) {
558   _fileRefreshSelected->setEnabled(atLeastOneNotDotEntry(tree));
559   if (tree->selection().size() == 1) {
560     // TODO: Most action have been written for single selection. We keep
561     // that logic until all actions have been ported to multi-selection.
562      KFileInfo * selection = tree->selection()[0];
563     _editCopy->setEnabled(true);
564     _reportMailToOwner->setEnabled(true);
565     _cleanupOpenWith->setEnabled(!selection->isDotEntry());
566     _fileReadExcludedDir->setEnabled(selection->isExcluded());
567 
568     if (selection->isMountPoint() &&
569         selection->readState() == KDirOnRequestOnly) {
570       _fileContinueReadingAtMountPoint->setEnabled(true);
571     } else
572       _fileContinueReadingAtMountPoint->setEnabled(false);
573 
574     statusMsg(selection->url());
575     QStorageInfo i(selection->url());
576     if(i.isValid())
577       _freeSpaceLabel->setText(formatSize(i.bytesFree()) + " free");
578   } else {
579     _editCopy->setEnabled(false);
580     _reportMailToOwner->setEnabled(false);
581     _fileContinueReadingAtMountPoint->setEnabled(false);
582     _cleanupOpenWith->setEnabled(false);
583     statusMsg("");
584   }
585 
586   updateActions();
587 }
588 
updateActions()589 void k4dirstat::updateActions() {
590   _treemapZoomIn->setEnabled(_treemapView && _treemapView->canZoomIn());
591   _treemapZoomOut->setEnabled(_treemapView && _treemapView->canZoomOut());
592   _treemapRebuild->setEnabled(_treemapView && _treemapView->rootTile());
593   _treemapSelectParent->setEnabled(_treemapView &&
594                                    _treemapView->canSelectParent());
595 
596   if (_treeView->tree() && _treeView->tree()->isBusy())
597     _fileStopReading->setEnabled(true);
598   else
599     _fileStopReading->setEnabled(false);
600 }
601 
treemapZoomIn()602 void k4dirstat::treemapZoomIn() {
603   if (_treemapView) {
604     _treemapView->zoomIn();
605     updateActions();
606   }
607 }
608 
treemapZoomOut()609 void k4dirstat::treemapZoomOut() {
610   if (_treemapView) {
611     _treemapView->zoomOut();
612     updateActions();
613   }
614 }
615 
treemapSelectParent()616 void k4dirstat::treemapSelectParent() {
617   if (_treemapView) {
618     _treemapView->selectParent();
619     updateActions();
620   }
621 }
622 
treemapRebuild()623 void k4dirstat::treemapRebuild() {
624   if (_treemapView) {
625     _treemapView->rebuildTreemap();
626     updateActions();
627   }
628 }
629 
treemapHelp()630 void k4dirstat::treemapHelp() { KHelpClient::invokeHelp("treemap_intro"); }
631 
toggleTreemapView()632 void k4dirstat::toggleTreemapView() {
633   if (_showTreemapView->isChecked()) {
634     if (!_treemapView)
635       createTreemapView();
636   } else {
637     if (_treemapView)
638       deleteTreemapView();
639   }
640 }
641 
preferences()642 void k4dirstat::preferences() {
643   if (_settingsDialog && _settingsDialog->isVisible())
644     return;
645   // TODO no longer store the instance as it's always recreated.
646   // need to detect closing
647   _settingsDialog = new KDirStat::KSettingsDialog(this);
648   _settingsDialog->show();
649 }
650 
statusMsg(const QString & text)651 void k4dirstat::statusMsg(const QString &text) {
652   // Change status message permanently
653   statusBar()->showMessage(text);
654 }
655 
contextMenu(const QPoint & pos)656 void k4dirstat::contextMenu(const QPoint &pos) {
657   if (_treeViewContextMenu)
658     _treeViewContextMenu->popup(pos);
659 }
660 
contextMenu(KTreemapTile * tile,const QPoint & pos)661 void k4dirstat::contextMenu(KTreemapTile *tile, const QPoint &pos) {
662   NOT_USED(tile);
663 
664   if (_treemapContextMenu)
665     _treemapContextMenu->popup(pos);
666 }
667 
createTreemapViewDelayed()668 void k4dirstat::createTreemapViewDelayed() {
669   QTimer::singleShot(0, this, SLOT(createTreemapView()));
670 }
671 
createTreemapView()672 void k4dirstat::createTreemapView() {
673   if (!_showTreemapView->isChecked() || !_treeView->tree())
674     return;
675 
676   if (_treemapView)
677     delete _treemapView;
678 
679   // qDebug() << "Creating KTreemapView" << endl;
680   _treemapView =
681       new KTreemapView(_treeView->tree(), _splitter,
682                        QSize(_splitter->width(), _treemapViewHeight));
683   Q_CHECK_PTR(_treemapView);
684 
685   connect(_treemapView, SIGNAL(contextMenu(KTreemapTile *, const QPoint &)),
686           this, SLOT(contextMenu(KTreemapTile *, const QPoint &)));
687 
688   connect(_treemapView, SIGNAL(treemapChanged()), this, SLOT(updateActions()));
689 
690   if (_activityTracker) {
691     connect(_treemapView, SIGNAL(userActivity(int)), _activityTracker,
692             SLOT(trackActivity(int)));
693   }
694 
695   _treemapView->show(); // QSplitter needs explicit show() for new children
696   updateActions();
697 }
698 
deleteTreemapView()699 void k4dirstat::deleteTreemapView() {
700   if (_treemapView) {
701     // qDebug() << "Deleting KTreemapView" << endl;
702     _treemapViewHeight = _treemapView->height();
703 
704     delete _treemapView;
705     _treemapView = 0;
706   }
707 
708   updateActions();
709 }
710 
triggerSaveConfig()711 void k4dirstat::triggerSaveConfig() { emit saveConfig(); }
712 
713 /*void k4dirstat::fileNew()
714 {
715     // this slot is called whenever the File->New menu is selected,
716     // the New shortcut is pressed (usually CTRL+N) or the New toolbar
717     // button is clicked
718 
719     // create a new window
720     (new k4dirstat)->show();
721 }
722 
723 void k4dirstat::optionsPreferences()
724 {
725     // The preference dialog is derived from prefs_base.ui
726     //
727     // compare the names of the widgets in the .ui file
728     // to the names of the variables in the .kcfg file
729     //avoid to have 2 dialogs shown
730     if ( KConfigDialog::showDialog( "settings" ) )  {
731         return;
732     }
733     KConfigDialog *dialog = new KConfigDialog(this, "settings",
734 Settings::self()); QWidget *generalSettingsDlg = new QWidget;
735     ui_prefs_base.setupUi(generalSettingsDlg);
736     dialog->addPage(generalSettingsDlg, i18n("General"), "package_setting");
737     connect(dialog, SIGNAL(settingsChanged(QString)), m_view,
738 SLOT(settingsChanged())); dialog->setAttribute( Qt::WA_DeleteOnClose );
739     dialog->show();
740 }*/
741