1 /*
2 * License: GPL - See file COPYING for details.
3 * Author: Stefan Hundhammer <sh@suse.de>
4 * Joshua Hodosh <kdirstat@grumpypenguin.org>
5 */
6
7 #include <qcheckbox.h>
8 #include <qcombobox.h>
9 #include <qinputdialog.h>
10 #include <qlabel.h>
11 #include <qlayout.h>
12 #include <qlineedit.h>
13 #include <qmessagebox.h>
14 #include <qpushbutton.h>
15 #include <qslider.h>
16 #include <qspinbox.h>
17
18 #include <kcolorbutton.h>
19 #include <kmessagebox.h>
20 #include <ktoolinvocation.h>
21
22 #include "kdirstatsettings.h"
23 #include "kdirtreeview.h"
24 #include "kexcluderules.h"
25 #include "ktreemapview.h"
26 #include <KHelpClient>
27 #include <KLocalizedString>
28 #include <KSharedConfig>
29 #include <QGroupBox>
30 #include <QMenu>
31
32 using namespace KDirStat;
33
addSettingsPage(const char * name)34 template <class T> int KSettingsDialog::addSettingsPage(const char *name) {
35 KSettingsPage *settingsPage = new T(NULL, _mainWin);
36 _pages.append(settingsPage);
37 return tabWidget->addTab(settingsPage, i18n(name));
38 }
39
KSettingsDialog(k4dirstat * mainWin)40 KSettingsDialog::KSettingsDialog(k4dirstat *mainWin)
41 : QDialog(mainWin), _mainWin(mainWin) {
42 setModal(false);
43 setWindowTitle(i18n("Settings"));
44 QDialogButtonBox *buttonBox =
45 new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Apply |
46 QDialogButtonBox::RestoreDefaults |
47 QDialogButtonBox::Cancel | QDialogButtonBox::Help);
48 tabWidget = new QTabWidget(this);
49 QVBoxLayout *mainLayout = new QVBoxLayout;
50 mainLayout->addWidget(tabWidget);
51 mainLayout->addWidget(buttonBox);
52 setLayout(mainLayout);
53 _cleanupsPageIndex = addSettingsPage<KCleanupPage>("&Actions");
54 _treeColorsPageIndex = addSettingsPage<KTreeColorsPage>("&Tree Colors");
55 _treemapPageIndex = addSettingsPage<KTreemapPage>("Tree&map");
56 _generalSettingsPageIndex = addSettingsPage<KGeneralSettingsPage>("&General");
57
58 connect(this, SIGNAL(aboutToShow()), this, SLOT(setup()));
59 connect(this, SIGNAL(accepted()), this, SLOT(apply()));
60 connect(buttonBox->button(QDialogButtonBox::Ok), SIGNAL(clicked()), this,
61 SLOT(accept()));
62 connect(buttonBox->button(QDialogButtonBox::Cancel), SIGNAL(clicked()), this,
63 SLOT(reject()));
64 connect(buttonBox->button(QDialogButtonBox::Apply), SIGNAL(clicked()), this,
65 SLOT(apply()));
66 connect(buttonBox->button(QDialogButtonBox::Help), SIGNAL(clicked()), this,
67 SLOT(slotHelp()));
68 connect(buttonBox->button(QDialogButtonBox::RestoreDefaults),
69 SIGNAL(clicked()), this, SLOT(slotDefault()));
70 }
71
apply()72 void KSettingsDialog::apply() {
73 foreach (KSettingsPage *p, _pages)
74 p->apply();
75 }
76
revertToDefaults()77 void KSettingsDialog::revertToDefaults() {
78 foreach (KSettingsPage *p, _pages)
79 p->revertToDefaults();
80 }
81
setup()82 void KSettingsDialog::setup() {
83 foreach (KSettingsPage *p, _pages)
84 p->setup();
85 }
86
~KSettingsDialog()87 KSettingsDialog::~KSettingsDialog() {
88 // NOP
89 }
90
show()91 void KSettingsDialog::show() {
92 emit aboutToShow();
93 QDialog::show();
94 }
95
slotDefault()96 void KSettingsDialog::slotDefault() {
97 if (KMessageBox::warningContinueCancel(
98 this,
99 i18n("Really revert all settings to their default values?\n"
100 "You will lose all changes you ever made!"),
101 i18n("Please Confirm"), // caption
102 KGuiItem(i18n("&Really Revert to Defaults")) // continueButton
103 ) == KMessageBox::Continue) {
104 revertToDefaults();
105 apply();
106 }
107 }
108
slotHelp()109 void KSettingsDialog::slotHelp() {
110 QString helpTopic = "";
111 int i = tabWidget->currentIndex();
112 if (i == _cleanupsPageIndex)
113 helpTopic = "configuring_cleanups";
114 else if (i == _treeColorsPageIndex)
115 helpTopic = "tree_colors";
116 else if (i == _treemapPageIndex)
117 helpTopic = "treemap_settings";
118 else if (i == _generalSettingsPageIndex)
119 helpTopic = "general_settings";
120
121 // qDebug() << "Help topic: " << helpTopic << endl;
122 KHelpClient::invokeHelp(helpTopic);
123 }
124
125 /*--------------------------------------------------------------------------*/
126
~KSettingsPage()127 KSettingsPage::~KSettingsPage() {
128 // NOP
129 }
130
131 /*--------------------------------------------------------------------------*/
132
KTreeColorsPage(QWidget * parent,k4dirstat * mainWin)133 KTreeColorsPage::KTreeColorsPage(QWidget *parent, k4dirstat *mainWin)
134 : KSettingsPage(parent), _mainWin(mainWin), _treeView(mainWin->treeView()),
135 _maxButtons(KDirStatSettingsMaxColorButton) {
136 // Outer layout box
137
138 QHBoxLayout *outerBox = new QHBoxLayout(this);
139 // Inner layout box with a column of color buttons
140
141 QGridLayout *grid = new QGridLayout();
142 outerBox->addLayout(grid, 1);
143 grid->setColumnStretch(0, 0); // label column - dont' stretch
144
145 for (int i = 1; i < _maxButtons; i++) {
146 grid->setColumnStretch(i, 1); // all other columns stretch as you like
147 }
148
149 for (int i = 0; i < _maxButtons; i++) {
150 QString labelText;
151
152 labelText = i18n("Tree Level %1", i + 1);
153 _colorLabel[i] = new QLabel(labelText, this);
154 grid->addWidget(_colorLabel[i], i, 0);
155
156 _colorButton[i] = new KColorButton(this);
157 _colorButton[i]->setMinimumSize(QSize(80, 10));
158 grid->addWidget(_colorButton[i], i, i + 1, 1, _maxButtons - i);
159 grid->setRowStretch(i, 1);
160 }
161
162 // Vertical slider
163
164 _slider = new QSlider(Qt::Vertical, this);
165 _slider->setMinimum(1);
166 _slider->setMaximum(_maxButtons);
167 _slider->setPageStep(1);
168 _slider->setValue(1);
169
170 outerBox->addWidget(_slider, 0);
171 outerBox->activate();
172
173 connect(_slider, SIGNAL(valueChanged(int)), this, SLOT(enableColors(int)));
174 }
175
~KTreeColorsPage()176 KTreeColorsPage::~KTreeColorsPage() {
177 // NOP
178 }
179
apply()180 void KTreeColorsPage::apply() {
181 _treeView->setUsedFillColors(_slider->value());
182
183 for (int i = 0; i < _maxButtons; i++) {
184 _treeView->setFillColor(i, _colorButton[i]->color());
185 }
186
187 _treeView->viewport()->repaint();
188 }
189
revertToDefaults()190 void KTreeColorsPage::revertToDefaults() {
191 _treeView->setDefaultFillColors();
192 setup();
193 }
194
setup()195 void KTreeColorsPage::setup() {
196 for (int i = 0; i < _maxButtons; i++) {
197 _colorButton[i]->setColor(_treeView->rawFillColor(i));
198 }
199
200 _slider->setValue(_treeView->usedFillColors());
201 enableColors(_treeView->usedFillColors());
202 }
203
enableColors(int maxColors)204 void KTreeColorsPage::enableColors(int maxColors) {
205 for (int i = 0; i < _maxButtons; i++) {
206 _colorButton[i]->setEnabled(i < maxColors);
207 _colorLabel[i]->setEnabled(i < maxColors);
208 }
209 }
210
211 /*--------------------------------------------------------------------------*/
212
KCleanupPage(QWidget * parent,k4dirstat * mainWin)213 KCleanupPage::KCleanupPage(QWidget *parent, k4dirstat *mainWin)
214 : KSettingsPage(parent), _mainWin(mainWin), _currentCleanup(0) {
215 // Copy the main window's cleanup collection.
216
217 _workCleanupCollection = mainWin->cleanupCollection()->cleanupsCopy();
218
219 // Create layout and widgets.
220
221 QHBoxLayout *layout = new QHBoxLayout(this);
222 _listBox = new KCleanupListBox(this);
223 _props = new KCleanupPropertiesPage(this, mainWin);
224
225 // Connect list box signals to reflect changes in the list
226 // selection in the cleanup properties page - whenever the user
227 // clicks on a different cleanup in the list, the properties page
228 // will display that cleanup's values.
229
230 connect(_listBox, SIGNAL(selectCleanup(KCleanup *)), this,
231 SLOT(changeCleanup(KCleanup *)));
232
233 // Fill list box so it can determine a reasonable startup geometry - that
234 // doesn't work if it happens only later.
235
236 setup();
237
238 // Now that _listBox will (hopefully) have determined a reasonable
239 // default geometry, add the widgets to the layout.
240
241 layout->addWidget(_listBox, 0);
242 layout->addWidget(_props, 1);
243 layout->activate();
244 }
245
~KCleanupPage()246 KCleanupPage::~KCleanupPage() {
247 // NOP
248 }
249
changeCleanup(KCleanup * newCleanup)250 void KCleanupPage::changeCleanup(KCleanup *newCleanup) {
251 if (_currentCleanup && newCleanup != _currentCleanup) {
252 storeProps(_currentCleanup);
253 }
254
255 _currentCleanup = newCleanup;
256 _props->setFields(_currentCleanup);
257 }
258
apply()259 void KCleanupPage::apply() { exportCleanups(); }
260
revertToDefaults()261 void KCleanupPage::revertToDefaults() {
262 _mainWin->revertCleanupsToDefaults();
263 setup();
264 }
265
setup()266 void KCleanupPage::setup() {
267 importCleanups();
268
269 // Fill the list box.
270
271 _listBox->clear();
272 for (int i = 0; i < _workCleanupCollection.count(); i++)
273 _listBox->insert(&_workCleanupCollection[i]);
274
275 // (Re-) Initialize list box.
276
277 // _listBox->resize( _listBox->sizeHint() );
278 _listBox->setCurrentRow(0);
279 }
280
importCleanups()281 void KCleanupPage::importCleanups() {
282 // Copy the main window's cleanup collecton to _workCleanupCollection.
283
284 _workCleanupCollection = _mainWin->cleanupCollection()->cleanupsCopy();
285
286 // Pointers to the old collection contents are now invalid!
287
288 _currentCleanup = 0;
289 }
290
exportCleanups()291 void KCleanupPage::exportCleanups() {
292 // Retrieve any pending changes from the properties page and store
293 // them in the current cleanup.
294
295 storeProps(_currentCleanup);
296
297 // Copy the _workCleanupCollection to the main window's cleanup
298 // collection.
299
300 _mainWin->cleanupCollection()->setCleanups(_workCleanupCollection);
301 }
302
storeProps(KCleanup * cleanup)303 void KCleanupPage::storeProps(KCleanup *cleanup) {
304 if (cleanup) {
305 // Retrieve the current fields contents and store them in the current
306 // cleanup.
307
308 *cleanup = _props->fields();
309
310 // Update the list box accordingly - the cleanup's title may have
311 // changed, too!
312
313 _listBox->updateTitle(cleanup);
314 }
315 }
316
317 /*--------------------------------------------------------------------------*/
318
KCleanupListBox(QWidget * parent)319 KCleanupListBox::KCleanupListBox(QWidget *parent) : QListWidget(parent) {
320 _selection = 0;
321
322 connect(this,
323 SIGNAL(currentItemChanged(QListWidgetItem *, QListWidgetItem *)),
324 SLOT(selectCleanup(QListWidgetItem *)));
325 }
326
sizeHint() const327 QSize KCleanupListBox::sizeHint() const {
328 QSize r = QListWidget::sizeHint();
329 r.setWidth(sizeHintForColumn(0));
330 return r;
331 }
332
insert(KCleanup * cleanup)333 void KCleanupListBox::insert(KCleanup *cleanup) {
334 // Create a new listbox item - this will insert itself (!) automatically.
335 // It took me half an afternoon to figure _this_ out. Not too intuitive
336 // when there is an insertItem() method, too, eh?
337
338 new KCleanupListBoxItem(this, cleanup);
339 }
340
selectCleanup(QListWidgetItem * listBoxItem)341 void KCleanupListBox::selectCleanup(QListWidgetItem *listBoxItem) {
342 KCleanupListBoxItem *item = (KCleanupListBoxItem *)listBoxItem;
343 if (item) {
344 _selection = item->cleanup();
345 emit selectCleanup(_selection);
346 }
347 }
348
updateTitle(KCleanup * cleanup)349 void KCleanupListBox::updateTitle(KCleanup *cleanup) {
350 for (int i = 0; i < count(); i++) {
351 KCleanupListBoxItem *item =
352 static_cast<KCleanupListBoxItem *>(this->item(i));
353 if (!cleanup || item->cleanup() == cleanup)
354 item->updateTitle();
355 }
356 }
357
358 /*--------------------------------------------------------------------------*/
359
KCleanupListBoxItem(KCleanupListBox * listBox,KCleanup * cleanup)360 KCleanupListBoxItem::KCleanupListBoxItem(KCleanupListBox *listBox,
361 KCleanup *cleanup)
362 : QListWidgetItem(listBox), _cleanup(cleanup) {
363 Q_CHECK_PTR(cleanup);
364 setText(cleanup->cleanTitle());
365 }
366
updateTitle()367 void KCleanupListBoxItem::updateTitle() { setText(_cleanup->cleanTitle()); }
368
369 /*--------------------------------------------------------------------------*/
370
KCleanupPropertiesPage(QWidget * parent,k4dirstat * mainWin)371 KCleanupPropertiesPage::KCleanupPropertiesPage(QWidget *parent,
372 k4dirstat *mainWin)
373 : QWidget(parent), _mainWin(mainWin) {
374 QVBoxLayout *outerBox = new QVBoxLayout(this);
375 outerBox->setMargin(0);
376 outerBox->setSpacing(0);
377 // The topmost check box: "Enabled".
378
379 _enabled = new QCheckBox(i18n("&Enabled"), this);
380 outerBox->addWidget(_enabled, 0);
381 outerBox->addSpacing(7);
382 outerBox->addStretch();
383
384 connect(_enabled, SIGNAL(toggled(bool)), this, SLOT(enableFields(bool)));
385
386 // All other widgets of this page are grouped together in a
387 // separate subwidget so they can all be enabled / disabled
388 // together.
389 _fields = new QWidget(this);
390 outerBox->addWidget(_fields, 1);
391
392 QVBoxLayout *fieldsBox = new QVBoxLayout(_fields);
393
394 // Grid layout for the edit fields, their labels, some
395 // explanatory text and the "recurse?" check box.
396
397 QGridLayout *grid = new QGridLayout();
398 grid->setSpacing(4);
399 fieldsBox->addLayout(grid, 0);
400 fieldsBox->addStretch();
401 fieldsBox->addSpacing(5);
402
403 grid->setColumnStretch(0, 0); // column for field labels - dont' stretch
404 grid->setColumnStretch(1, 1); // column for edit fields - stretch as you like
405
406 // Edit fields for cleanup action title and command line.
407
408 QLabel *label;
409 _title = new QLineEdit(_fields);
410 grid->addWidget(_title, 0, 1);
411 _command = new QLineEdit(_fields);
412 grid->addWidget(_command, 1, 1);
413
414 label = new QLabel(i18n("&Title:"), _fields);
415 label->setBuddy(_title);
416 grid->addWidget(label, 0, 0);
417
418 label = new QLabel(i18n("&Command Line:"), _fields);
419 label->setBuddy(_command);
420 grid->addWidget(label, 1, 0);
421
422 label = new QLabel(i18n("%p Full Path"), _fields);
423 grid->addWidget(label, 2, 1);
424
425 label = new QLabel(i18n("%n File / Directory Name Without Path"), _fields);
426 grid->addWidget(label, 3, 1);
427
428 label = new QLabel(i18n("%t KDE Trash Directory"), _fields);
429 grid->addWidget(label, 4, 1);
430
431 // "Recurse into subdirs" check box
432
433 _recurse = new QCheckBox(i18n("&Recurse into Subdirectories"), _fields);
434 grid->addWidget(_recurse, 5, 1);
435
436 // "Ask for confirmation" check box
437
438 _askForConfirmation = new QCheckBox(i18n("&Ask for Confirmation"), _fields);
439 grid->addWidget(_askForConfirmation, 6, 1);
440
441 // The "Works for..." check boxes, grouped together in a button group.
442
443 QGroupBox *worksFor = new QGroupBox(i18n("Works for..."), _fields);
444 QVBoxLayout *worksForBox = new QVBoxLayout(worksFor);
445 fieldsBox->addWidget(worksFor, 0);
446 fieldsBox->addSpacing(5);
447 fieldsBox->addStretch();
448
449 _worksForDir = new QCheckBox(i18n("&Directories"), worksFor);
450 _worksForFile = new QCheckBox(i18n("&Files"), worksFor);
451 _worksForDotEntry = new QCheckBox(i18n("<Files> P&seudo Entries"), worksFor);
452
453 worksForBox->addWidget(_worksForDir, 1);
454 worksForBox->addWidget(_worksForFile, 1);
455 worksForBox->addWidget(_worksForDotEntry, 1);
456
457 worksForBox->addSpacing(5);
458 _worksForProtocols = new QComboBox(worksFor);
459 _worksForProtocols->setEditable(false);
460 worksForBox->addWidget(_worksForProtocols, 1);
461
462 _worksForProtocols->insertItem(
463 0, i18n("On Local Machine Only ('file:/' Protocol)"));
464 _worksForProtocols->insertItem(
465 1, i18n("Network Transparent (ftp, smb, tar, ...)"));
466
467 // Grid layout for combo boxes at the bottom
468
469 grid = new QGridLayout();
470 grid->setSpacing(4);
471 fieldsBox->addLayout(grid, 0);
472 fieldsBox->addSpacing(5);
473 fieldsBox->addStretch();
474 int row = 0;
475
476 // The "Refresh policy" combo box
477
478 _refreshPolicy = new QComboBox(_fields);
479 _refreshPolicy->setEditable(false);
480 grid->addWidget(_refreshPolicy, row, 1);
481
482 label = new QLabel(i18n("Refresh &Policy:"), _fields);
483 label->setBuddy(_refreshPolicy);
484 grid->addWidget(label, row++, 0);
485
486 // Caution: The order of those entries must match the order of
487 // 'enum RefreshPolicy' in 'kcleanup.h'!
488 //
489 // I don't like this one bit. The ComboBox should provide something better
490 // than mere numeric IDs. One of these days I'm going to rewrite this
491 // thing!
492
493 _refreshPolicy->insertItem(0, i18n("No Refresh"));
494 _refreshPolicy->insertItem(1, i18n("Refresh This Entry"));
495 _refreshPolicy->insertItem(2, i18n("Refresh This Entry's Parent"));
496 _refreshPolicy->insertItem(3, i18n("Assume Entry Has Been Deleted"));
497
498 outerBox->activate();
499 setMinimumSize(sizeHint());
500 }
501
enableFields(bool active)502 void KCleanupPropertiesPage::enableFields(bool active) {
503 _fields->setEnabled(active);
504 }
505
setFields(const KCleanup * cleanup)506 void KCleanupPropertiesPage::setFields(const KCleanup *cleanup) {
507 _id = cleanup->id();
508 _enabled->setChecked(cleanup->enabled());
509 _title->setText(cleanup->title());
510 _command->setText(cleanup->command());
511 _recurse->setChecked(cleanup->recurse());
512 _askForConfirmation->setChecked(cleanup->askForConfirmation());
513 _worksForDir->setChecked(cleanup->worksForDir());
514 _worksForFile->setChecked(cleanup->worksForFile());
515 _worksForDotEntry->setChecked(cleanup->worksForDotEntry());
516 _worksForProtocols->setCurrentIndex(cleanup->worksLocalOnly() ? 0 : 1);
517 _refreshPolicy->setCurrentIndex(cleanup->refreshPolicy());
518
519 enableFields(cleanup->enabled());
520 }
521
fields() const522 KCleanup KCleanupPropertiesPage::fields() const {
523 KCleanup cleanup(_id, _command->text(), _title->text());
524
525 cleanup.setEnabled(_enabled->isChecked());
526 cleanup.setRecurse(_recurse->isChecked());
527 cleanup.setAskForConfirmation(_askForConfirmation->isChecked());
528 cleanup.setWorksForDir(_worksForDir->isChecked());
529 cleanup.setWorksForFile(_worksForFile->isChecked());
530 cleanup.setWorksLocalOnly(_worksForProtocols->currentIndex() == 0 ? true
531 : false);
532 cleanup.setWorksForDotEntry(_worksForDotEntry->isChecked());
533 cleanup.setRefreshPolicy(
534 (KCleanup::RefreshPolicy)_refreshPolicy->currentIndex());
535
536 return cleanup;
537 }
538
539 /*--------------------------------------------------------------------------*/
540
KGeneralSettingsPage(QWidget * parent,k4dirstat * mainWin)541 KGeneralSettingsPage::KGeneralSettingsPage(QWidget *parent, k4dirstat *mainWin)
542 : KSettingsPage(parent), _mainWin(mainWin), _treeView(mainWin->treeView()) {
543 // Create layout and widgets.
544
545 QVBoxLayout *layout = new QVBoxLayout(this);
546 QGroupBox *gbox = new QGroupBox(i18n("Directory Reading"), this);
547 layout->addWidget(gbox);
548 QVBoxLayout *gboxLayout = new QVBoxLayout(gbox);
549 gbox->setLayout(gboxLayout);
550
551 _crossFileSystems = new QCheckBox(i18n("Cross &File System Boundaries"));
552 _enableLocalDirReader =
553 new QCheckBox(i18n("Use Optimized &Local Directory Read Methods"));
554 gboxLayout->addWidget(_crossFileSystems);
555 gboxLayout->addWidget(_enableLocalDirReader);
556
557 connect(_enableLocalDirReader, SIGNAL(stateChanged(int)), this,
558 SLOT(checkEnabledState()));
559
560 layout->addSpacing(10);
561
562 QGroupBox *excludeBox = new QGroupBox(i18n("&Exclude Rules"));
563 layout->addWidget(excludeBox);
564 QVBoxLayout *excludeBoxLayout = new QVBoxLayout();
565 excludeBox->setLayout(excludeBoxLayout);
566 _excludeRulesListView = new QListWidget();
567 _excludeRuleContextMenu = 0;
568 excludeBoxLayout->addWidget(_excludeRulesListView);
569
570 QHBoxLayout *buttonBoxLayout = new QHBoxLayout();
571 excludeBoxLayout->addLayout(buttonBoxLayout);
572 _addExcludeRuleButton = new QPushButton(i18n("&Add"));
573 _editExcludeRuleButton = new QPushButton(i18n("&Edit"));
574 _deleteExcludeRuleButton = new QPushButton(i18n("&Delete"));
575 buttonBoxLayout->addWidget(_addExcludeRuleButton);
576 buttonBoxLayout->addWidget(_editExcludeRuleButton);
577 buttonBoxLayout->addWidget(_deleteExcludeRuleButton);
578
579 _excludeRulesListView->setContextMenuPolicy(Qt::CustomContextMenu);
580 connect(_excludeRulesListView,
581 SIGNAL(customContextMenuRequested(const QPoint &)), this,
582 SLOT(showExcludeRuleContextMenu(const QPoint &)));
583
584 connect(_addExcludeRuleButton, SIGNAL(clicked()), this,
585 SLOT(addExcludeRule()));
586
587 connect(_editExcludeRuleButton, SIGNAL(clicked()), this,
588 SLOT(editExcludeRule()));
589
590 connect(_deleteExcludeRuleButton, SIGNAL(clicked()), this,
591 SLOT(deleteExcludeRule()));
592
593 connect(_excludeRulesListView, SIGNAL(itemDoubleClicked(QListWidgetItem *)),
594 this, SLOT(editExcludeRule()));
595 }
596
~KGeneralSettingsPage()597 KGeneralSettingsPage::~KGeneralSettingsPage() {
598 if (_excludeRuleContextMenu)
599 delete _excludeRuleContextMenu;
600 }
601
showExcludeRuleContextMenu(const QPoint & localPos)602 void KGeneralSettingsPage::showExcludeRuleContextMenu(const QPoint &localPos) {
603 if (!_excludeRuleContextMenu) {
604 _excludeRuleContextMenu = new QMenu();
605 QAction *editAction = new QAction(i18n("&Edit"), _excludeRuleContextMenu);
606 connect(editAction, SIGNAL(triggered()), this, SLOT(editExcludeRule()));
607 _excludeRuleContextMenu->addAction(editAction);
608 QAction *deleteAction =
609 new QAction(i18n("&Delete"), _excludeRuleContextMenu);
610 connect(deleteAction, SIGNAL(triggered()), this, SLOT(deleteExcludeRule()));
611 _excludeRuleContextMenu->addAction(deleteAction);
612 }
613
614 if (_excludeRuleContextMenu && _excludeRulesListView->currentItem()) {
615 QPoint pos = _excludeRulesListView->viewport()->mapToGlobal(localPos);
616 _excludeRuleContextMenu->move(pos.x(), pos.y());
617 _excludeRuleContextMenu->show();
618 }
619 }
620
apply()621 void KGeneralSettingsPage::apply() {
622 KConfigGroup config = KSharedConfig::openConfig()->group("Directory Reading");
623
624 config.writeEntry("CrossFileSystems", _crossFileSystems->isChecked());
625 config.writeEntry("EnableLocalDirReader", _enableLocalDirReader->isChecked());
626
627 config = KSharedConfig::openConfig()->group("Exclude");
628 // config.setGroup( "Exclude" );
629
630 QStringList excludeRulesStringList;
631 KExcludeRules::excludeRules()->clear();
632
633 for (int i = 0; i < _excludeRulesListView->count(); i++) {
634 QListWidgetItem *item = _excludeRulesListView->item(i);
635 QString ruleText = item->text();
636 excludeRulesStringList.append(ruleText);
637 // qDebug() << "Adding exclude rule " << ruleText << endl;
638 KExcludeRules::excludeRules()->add(new KExcludeRule(QRegExp(ruleText)));
639 }
640
641 config.writeEntry("ExcludeRules", excludeRulesStringList);
642 }
643
revertToDefaults()644 void KGeneralSettingsPage::revertToDefaults() {
645 _crossFileSystems->setChecked(false);
646 _enableLocalDirReader->setChecked(true);
647 _excludeRulesListView->clear();
648 _editExcludeRuleButton->setEnabled(false);
649 _deleteExcludeRuleButton->setEnabled(false);
650 }
651
setup()652 void KGeneralSettingsPage::setup() {
653 KConfigGroup config = KSharedConfig::openConfig()->group("Directory Reading");
654
655 _crossFileSystems->setChecked(config.readEntry("CrossFileSystems", false));
656 _enableLocalDirReader->setChecked(
657 config.readEntry("EnableLocalDirReader", true));
658 _excludeRulesListView->clear();
659
660 foreach (KExcludeRule *excludeRule, KExcludeRules::excludeRules()->rules()) {
661 QListWidgetItem *n = new QListWidgetItem(_excludeRulesListView);
662 n->setText(excludeRule->regexp().pattern());
663 }
664
665 checkEnabledState();
666 }
667
checkEnabledState()668 void KGeneralSettingsPage::checkEnabledState() {
669 _crossFileSystems->setEnabled(_enableLocalDirReader->isChecked());
670
671 int excludeRulesCount = _excludeRulesListView->count();
672
673 _editExcludeRuleButton->setEnabled(excludeRulesCount > 0);
674 _deleteExcludeRuleButton->setEnabled(excludeRulesCount > 0);
675 }
676
addExcludeRule()677 void KGeneralSettingsPage::addExcludeRule() {
678 bool ok;
679 QString text =
680 QInputDialog::getText(this, i18n("New exclude rule"),
681 i18n("Regular expression for new exclude rule:"),
682 QLineEdit::Normal, QString(), &ok);
683 if (ok && !text.isEmpty()) {
684 QListWidgetItem *l = new QListWidgetItem(_excludeRulesListView);
685 l->setText(text);
686 _excludeRulesListView->addItem(l);
687 }
688
689 checkEnabledState();
690 }
691
editExcludeRule()692 void KGeneralSettingsPage::editExcludeRule() {
693 QListWidgetItem *item = _excludeRulesListView->currentItem();
694
695 if (item) {
696 bool ok;
697 QString text =
698 QInputDialog::getText(this, i18n("Edit exclude rule"),
699 i18n("Exclude rule (regular expression):"),
700 QLineEdit::Normal, item->text(), &ok);
701 if (ok) {
702 if (text.isEmpty())
703 _excludeRulesListView->takeItem(_excludeRulesListView->currentRow());
704 else
705 item->setText(text);
706 }
707 }
708
709 checkEnabledState();
710 }
711
deleteExcludeRule()712 void KGeneralSettingsPage::deleteExcludeRule() {
713 QListWidgetItem *item = _excludeRulesListView->currentItem();
714
715 if (item) {
716 QString excludeRule = item->text();
717 int result = KMessageBox::questionYesNo(
718 this, i18n("Really delete exclude rule \"%1\"?", excludeRule),
719 i18n("Delete?")); // Window title
720 if (result == KMessageBox::Yes) {
721 _excludeRulesListView->takeItem(_excludeRulesListView->currentRow());
722 }
723 }
724
725 checkEnabledState();
726 }
727
728 /*--------------------------------------------------------------------------*/
729
KTreemapPage(QWidget * parent,k4dirstat * mainWin)730 KTreemapPage::KTreemapPage(QWidget *parent, k4dirstat *mainWin)
731 : KSettingsPage(parent), _mainWin(mainWin) {
732 // qDebug() << Q_FUNC_INFO << endl;
733
734 QVBoxLayout *layout = new QVBoxLayout(this); // parent
735 setLayout(layout);
736 _squarify = new QCheckBox(i18n("S&quarify Treemap"), this);
737 _doCushionShading = new QCheckBox(i18n("Use C&ushion Shading"), this);
738 layout->addWidget(_squarify);
739 layout->addWidget(_doCushionShading);
740
741 // Cushion parameters
742
743 QGroupBox *gbox = new QGroupBox(i18n("Cushion Parameters"), this);
744 layout->addWidget(gbox);
745 _cushionParams = gbox;
746 QLabel *label = new QLabel(i18n("Ambient &Light"));
747 _ambientLight = new QSlider(Qt::Horizontal);
748 _ambientLight->setMinimum(MinAmbientLight);
749 _ambientLight->setMaximum(MaxAmbientLight);
750 _ambientLight->setPageStep(10);
751 _ambientLight->setValue(DefaultAmbientLight);
752 _ambientLightSB = new QSpinBox();
753 _ambientLightSB->setMinimum(MinAmbientLight);
754 _ambientLightSB->setMaximum(MaxAmbientLight);
755 label->setBuddy(_ambientLightSB);
756
757 QGridLayout *cushionLayout = new QGridLayout();
758 gbox->setLayout(cushionLayout);
759 cushionLayout->setColumnStretch(1, 1);
760 cushionLayout->addWidget(label, 0, 0, 1, 1);
761 cushionLayout->addWidget(_ambientLight, 0, 1, 1, 2);
762 cushionLayout->addWidget(_ambientLightSB, 0, 3, 1, 1);
763
764 label = new QLabel(i18n("&Height Scale"));
765 _heightScalePercent = new QSlider(Qt::Horizontal);
766 _heightScalePercent->setMinimum(MinHeightScalePercent);
767 _heightScalePercent->setMaximum(MaxHeightScalePercent);
768 _heightScalePercent->setPageStep(10);
769 _heightScalePercent->setValue(DefaultHeightScalePercent);
770 _heightScalePercent->setSizePolicy(QSizePolicy::Expanding,
771 QSizePolicy::Fixed);
772 _heightScalePercentSB = new QSpinBox();
773 _heightScalePercentSB->setMinimum(MinHeightScalePercent);
774 _heightScalePercentSB->setMaximum(MaxHeightScalePercent);
775 label->setBuddy(_heightScalePercentSB);
776
777 cushionLayout->addWidget(label, 1, 0, 1, 1);
778 cushionLayout->addWidget(_heightScalePercent, 1, 1, 1, 2);
779 cushionLayout->addWidget(_heightScalePercentSB, 1, 3, 1, 1);
780
781 _ensureContrast = new QCheckBox(i18n("Draw Lines if Lo&w Contrast"));
782
783 _forceCushionGrid = new QCheckBox(i18n("Always Draw &Grid"));
784 _cushionGridColorL = new QLabel(i18n("Gr&id Color: "));
785 _cushionGridColor = new KColorButton();
786 _cushionGridColorL->setBuddy(_cushionGridColor);
787 cushionLayout->addWidget(_forceCushionGrid, 4, 0, 1, 2);
788 cushionLayout->addWidget(_ensureContrast, 3, 0, 1, 2);
789 cushionLayout->addWidget(_cushionGridColorL, 4, 2, 1, 1, Qt::AlignRight);
790 cushionLayout->addWidget(_cushionGridColor, 4, 3, 1, 1);
791
792 // Plain treemaps parameters
793
794 _plainTileParams = new QGroupBox(i18n("Colors for Plain Treemaps"), this);
795 layout->addWidget(_plainTileParams);
796 QHBoxLayout *plainTileLayout = new QHBoxLayout();
797 _plainTileParams->setLayout(plainTileLayout);
798 label = new QLabel(i18n("&Files: "));
799 plainTileLayout->addWidget(label);
800 _fileFillColor = new KColorButton();
801 plainTileLayout->addWidget(_fileFillColor);
802 label->setBuddy(_fileFillColor);
803 label->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
804
805 label = new QLabel(" " + i18n("&Directories: "));
806 _dirFillColor = new KColorButton();
807 label->setBuddy(_dirFillColor);
808 label->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
809 plainTileLayout->addWidget(label);
810 plainTileLayout->addWidget(_dirFillColor);
811
812 label = new QLabel(i18n("Gr&id: "));
813 _outlineColor = new KColorButton();
814 label->setBuddy(_outlineColor);
815 label->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
816 plainTileLayout->addWidget(label);
817 plainTileLayout->addWidget(_outlineColor);
818
819 // Misc
820
821 QWidget *gridBox = new QWidget(this);
822 layout->addWidget(gridBox);
823 QGridLayout *grid = new QGridLayout(gridBox);
824 grid->setColumnStretch(0, 0); // (col, stretch) don't stretch this column
825 grid->setColumnStretch(1, 0); // don't stretch
826 grid->setColumnStretch(2, 1); // stretch this as you like
827
828 label = new QLabel(i18n("Highlight R&ectangle: "), gridBox);
829 _highlightColor = new KColorButton(gridBox);
830 label->setBuddy(_highlightColor);
831
832 grid->addWidget(label, 0, 0);
833 grid->addWidget(_highlightColor, 0, 1);
834
835 label = new QLabel(i18n("Minim&um Treemap Tile Size: "), gridBox);
836 _minTileSize = new QSpinBox(gridBox);
837 _minTileSize->setMinimum(0);
838 _minTileSize->setMaximum(30);
839 _minTileSize->setSingleStep(1);
840 label->setBuddy(_minTileSize);
841
842 grid->addWidget(label, 1, 0);
843 grid->addWidget(_minTileSize, 1, 1);
844
845 _autoResize = new QCheckBox(i18n("Auto-&Resize Treemap"), this);
846 layout->addWidget(_autoResize);
847
848 // Connections
849
850 connect(_ambientLight, SIGNAL(valueChanged(int)), _ambientLightSB,
851 SLOT(setValue(int)));
852
853 connect(_ambientLightSB, SIGNAL(valueChanged(int)), _ambientLight,
854 SLOT(setValue(int)));
855
856 connect(_heightScalePercent, SIGNAL(valueChanged(int)), _heightScalePercentSB,
857 SLOT(setValue(int)));
858
859 connect(_heightScalePercentSB, SIGNAL(valueChanged(int)), _heightScalePercent,
860 SLOT(setValue(int)));
861
862 connect(_doCushionShading, SIGNAL(stateChanged(int)), this,
863 SLOT(checkEnabledState()));
864 connect(_forceCushionGrid, SIGNAL(stateChanged(int)), this,
865 SLOT(checkEnabledState()));
866
867 checkEnabledState();
868 }
869
~KTreemapPage()870 KTreemapPage::~KTreemapPage() {
871 // NOP
872 }
873
apply()874 void KTreemapPage::apply() {
875 KConfigGroup config = KSharedConfig::openConfig()->group("Treemaps");
876
877 config.writeEntry("Squarify", _squarify->isChecked());
878 config.writeEntry("CushionShading", _doCushionShading->isChecked());
879 config.writeEntry("AmbientLight", _ambientLight->value());
880 config.writeEntry("HeightScaleFactor", _heightScalePercent->value() / 100.0);
881 config.writeEntry("EnsureContrast", _ensureContrast->isChecked());
882 config.writeEntry("ForceCushionGrid", _forceCushionGrid->isChecked());
883 config.writeEntry("MinTileSize", _minTileSize->value());
884 config.writeEntry("AutoResize", _autoResize->isChecked());
885 config.writeEntry("CushionGridColor", _cushionGridColor->color());
886 config.writeEntry("OutlineColor", _outlineColor->color());
887 config.writeEntry("FileFillColor", _fileFillColor->color());
888 config.writeEntry("DirFillColor", _dirFillColor->color());
889 config.writeEntry("HighlightColor", _highlightColor->color());
890
891 if (treemapView()) {
892 treemapView()->readConfig();
893 treemapView()->rebuildTreemap();
894 }
895 }
896
revertToDefaults()897 void KTreemapPage::revertToDefaults() {
898 _squarify->setChecked(true);
899 _doCushionShading->setChecked(true);
900
901 _ambientLight->setValue(DefaultAmbientLight);
902 _heightScalePercent->setValue(DefaultHeightScalePercent);
903 _ensureContrast->setChecked(true);
904 _forceCushionGrid->setChecked(false);
905 _minTileSize->setValue(DefaultMinTileSize);
906 _autoResize->setChecked(true);
907
908 _cushionGridColor->setColor(QColor(0x80, 0x80, 0x80));
909 _outlineColor->setColor(QColor(Qt::black));
910 _fileFillColor->setColor(QColor(0xde, 0x8d, 0x53));
911 _dirFillColor->setColor(QColor(0x10, 0x7d, 0xb4));
912 _highlightColor->setColor(QColor(Qt::red));
913 }
914
setup()915 void KTreemapPage::setup() {
916 KConfigGroup config = KSharedConfig::openConfig()->group("Treemaps");
917
918 _squarify->setChecked(config.readEntry("Squarify", true));
919 _doCushionShading->setChecked(config.readEntry("CushionShading", true));
920
921 _ambientLight->setValue(
922 config.readEntry("AmbientLight", DefaultAmbientLight));
923 _heightScalePercent->setValue(
924 (int)(100 *
925 config.readEntry("HeightScaleFactor", DefaultHeightScaleFactor)));
926 _ensureContrast->setChecked(config.readEntry("EnsureContrast", true));
927 _forceCushionGrid->setChecked(config.readEntry("ForceCushionGrid", false));
928 _minTileSize->setValue(config.readEntry("MinTileSize", DefaultMinTileSize));
929 _autoResize->setChecked(config.readEntry("AutoResize", true));
930
931 _cushionGridColor->setColor(
932 readColorEntry(config, "CushionGridColor", QColor(0x80, 0x80, 0x80)));
933 _outlineColor->setColor(
934 readColorEntry(config, "OutlineColor", QColor(Qt::black)));
935 _fileFillColor->setColor(
936 readColorEntry(config, "FileFillColor", QColor(0xde, 0x8d, 0x53)));
937 _dirFillColor->setColor(
938 readColorEntry(config, "DirFillColor", QColor(0x10, 0x7d, 0xb4)));
939 _highlightColor->setColor(
940 readColorEntry(config, "HighlightColor", QColor(Qt::red)));
941
942 _ambientLightSB->setValue(_ambientLight->value());
943 _heightScalePercentSB->setValue(_heightScalePercent->value());
944
945 checkEnabledState();
946 }
947
checkEnabledState()948 void KTreemapPage::checkEnabledState() {
949 _cushionParams->setEnabled(_doCushionShading->isChecked());
950 _plainTileParams->setEnabled(!_doCushionShading->isChecked());
951
952 if (_doCushionShading->isChecked()) {
953 _cushionGridColor->setEnabled(_forceCushionGrid->isChecked());
954 _cushionGridColorL->setEnabled(_forceCushionGrid->isChecked());
955 _ensureContrast->setEnabled(!_forceCushionGrid->isChecked());
956 }
957 }
958
readColorEntry(KConfigGroup config,const char * entryName,QColor defaultColor)959 QColor KTreemapPage::readColorEntry(KConfigGroup config, const char *entryName,
960 QColor defaultColor) {
961 return config.readEntry(entryName, defaultColor);
962 }
963
addHStretch(QWidget * parent)964 void addHStretch(QWidget *parent) {
965 QWidget *stretch = new QWidget(parent);
966 QSizePolicy sp(QSizePolicy::Expanding, QSizePolicy::Minimum);
967 sp.setHorizontalStretch(1);
968 sp.setVerticalStretch(0);
969 stretch->setSizePolicy(sp);
970 }
971
addVStretch(QWidget * parent)972 void addVStretch(QWidget *parent) {
973 QWidget *stretch = new QWidget(parent);
974 QSizePolicy sp(QSizePolicy::Minimum, QSizePolicy::Expanding);
975 sp.setHorizontalStretch(0);
976 sp.setVerticalStretch(1);
977 stretch->setSizePolicy(sp);
978 }
979
980