1 /*
2     This file is part of KCachegrind.
3 
4     SPDX-FileCopyrightText: 2009-2016 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
5 
6     SPDX-License-Identifier: GPL-2.0-only
7 */
8 
9 /*
10  * Source annotation directory settings config page
11  */
12 
13 #include "sourcesettings.h"
14 
15 #include <QTreeWidgetItem>
16 #include <QFileDialog>
17 
18 #include "tracedata.h"
19 #include "globalconfig.h"
20 
21 //
22 // SourceSettings
23 //
24 
SourceSettings(TraceData * data,QWidget * parent)25 SourceSettings::SourceSettings(TraceData* data, QWidget* parent)
26     : ConfigPage(parent,
27                  QObject::tr("Source Annotation"),
28                  QObject::tr("Directory Settings for Source Annotation"))
29 {
30     ui.setupUi(this);
31 
32     ui.dirList->setRootIsDecorated(false);
33 
34     GlobalConfig* c = GlobalConfig::config();
35     _always = tr("(always)");
36 
37     QTreeWidgetItem* i;
38     QStringList::const_iterator sit = c->generalSourceDirs().constBegin();
39     for(; sit != c->generalSourceDirs().constEnd(); ++sit ) {
40         QString d = (*sit);
41         if (d.isEmpty()) d = QStringLiteral("/");
42         i = new QTreeWidgetItem();
43         i->setText(0, _always);
44         i->setText(1, d);
45         ui.dirList->addTopLevelItem(i);
46     }
47 
48     QStringList objItems(_always);
49     if (data) {
50         TraceObjectMap::Iterator oit;
51         for ( oit = data->objectMap().begin();
52               oit != data->objectMap().end(); ++oit ) {
53             QString n = (*oit).name();
54             if (n.isEmpty()) continue;
55             objItems << n;
56 
57             const QStringList& dirs = c->objectSourceDirs(n);
58             sit = dirs.constBegin();
59             for(; sit != dirs.constEnd(); ++sit ) {
60                 QString d = (*sit);
61                 if (d.isEmpty()) d = QStringLiteral("/");
62                 i = new QTreeWidgetItem();
63                 i->setText(0, n);
64                 i->setText(1, d);
65                 ui.dirList->addTopLevelItem(i);
66             }
67         }
68     }
69 
70     ui.objectBox->addItems(objItems);
71     ui.objectBox->setCurrentIndex(0);
72 
73     connect(ui.addDirButton, &QAbstractButton::clicked,
74             this, &SourceSettings::addClicked);
75     connect(ui.deleteDirButton, &QAbstractButton::clicked,
76             this, &SourceSettings::deleteClicked);
77     connect(ui.browseDirButton, &QAbstractButton::clicked,
78             this, &SourceSettings::browseClicked);
79     connect(ui.dirList,
80             &QTreeWidget::currentItemChanged,
81             this,
82             &SourceSettings::dirListItemChanged);
83     connect(ui.objectBox,
84             SIGNAL(currentIndexChanged(QString)),
85             this, SLOT(objectChanged(QString)));
86     connect(ui.dirEdit, SIGNAL(textChanged(QString)),
87             this, SLOT(dirEditChanged(QString)));
88 
89     _current = nullptr;
90     update();
91 }
92 
activate(QString s)93 void SourceSettings::activate(QString s)
94 {
95     int idx = s.toInt();
96     if ((idx==0) || (idx>ui.dirList->topLevelItemCount())) return;
97 
98     ui.dirList->setCurrentItem(ui.dirList->topLevelItem(idx-1));
99     ui.dirEdit->setFocus();
100 }
101 
update()102 void SourceSettings::update()
103 {
104     if (!_current) {
105         ui.deleteDirButton->setEnabled(false);
106         ui.objectBox->setEnabled(false);
107         ui.dirEdit->setEnabled(false);
108         ui.browseDirButton->setEnabled(false);
109         return;
110     }
111     ui.deleteDirButton->setEnabled(true);
112     ui.objectBox->setEnabled(true);
113     ui.objectBox->setCurrentIndex(ui.objectBox->findText(_current->text(0)));
114     ui.dirEdit->setEnabled(true);
115     ui.dirEdit->setText(_current->text(1));
116     ui.browseDirButton->setEnabled(true);
117 }
118 
addClicked()119 void SourceSettings::addClicked()
120 {
121     int prevItemCount = ui.dirList->topLevelItemCount();
122     QTreeWidgetItem* i = new QTreeWidgetItem();
123     i->setText(0, ui.objectBox->currentText());
124     i->setText(1, tr("<insert valid directory>"));
125     ui.dirList->addTopLevelItem(i);
126     ui.dirList->setCurrentItem(i);
127     if (prevItemCount == 0 && ui.objectBox->currentText() == _always) {
128         // it's not obvious that you have to click browse after adding an item,
129         // but handle the case where we have no items and are looking for the
130         // default. give users an oppurtunity to select for multiple ELF objects
131         browseClicked();
132     }
133 }
134 
deleteClicked()135 void SourceSettings::deleteClicked()
136 {
137     if (!_current) return;
138 
139     QTreeWidgetItem* i = _current;
140     // the deletion removes the item
141     delete _current;
142     // deletion can trigger a call to dirListItemChanged() !
143     if (_current == i) {
144         _current = nullptr;
145         update();
146     }
147 }
148 
browseClicked()149 void SourceSettings::browseClicked()
150 {
151     QString d;
152     d = QFileDialog::getExistingDirectory(this,
153                                           tr("Choose Source Directory"),
154                                           ui.dirEdit->text());
155     if (!d.isEmpty())
156         ui.dirEdit->setText(d);
157 }
158 
dirListItemChanged(QTreeWidgetItem * current,QTreeWidgetItem *)159 void SourceSettings::dirListItemChanged(QTreeWidgetItem* current,
160                                         QTreeWidgetItem*)
161 {
162     _current = current;
163     update();
164 }
165 
objectChanged(QString obj)166 void SourceSettings::objectChanged(QString obj)
167 {
168     if (!_current) return;
169 
170     _current->setText(0, obj);
171 }
172 
dirEditChanged(QString dir)173 void SourceSettings::dirEditChanged(QString dir)
174 {
175     if (!_current) return;
176 
177     _current->setText(1, dir);
178 }
179 
check(QString & errorMsg,QString & errorItem)180 bool SourceSettings::check(QString& errorMsg, QString& errorItem)
181 {
182     for(int idx=0; idx< ui.dirList->topLevelItemCount(); idx++) {
183         QTreeWidgetItem* item = ui.dirList->topLevelItem(idx);
184         QString dir = item->text(1);
185         if (QDir(dir).exists()) continue;
186         errorMsg = tr("Directory does not exist");
187         errorItem = QStringLiteral("%1").arg(idx+1);
188         return false;
189     }
190     return true;
191 }
192 
accept()193 void SourceSettings::accept()
194 {
195     GlobalConfig* c = GlobalConfig::config();
196 
197     QHash<QString, QStringList> dirs;
198     for(int idx=0; idx< ui.dirList->topLevelItemCount(); idx++) {
199         QTreeWidgetItem* item = ui.dirList->topLevelItem(idx);
200         dirs[item->text(0)] << item->text(1);
201     }
202 
203     c->setGeneralSourceDirs(QStringList());
204     c->clearObjectSourceDirs();
205 
206     QHash<QString, QStringList>::const_iterator oit = dirs.constBegin();
207     for(;oit != dirs.constEnd(); ++oit) {
208         if (oit.key() == _always)
209             c->setGeneralSourceDirs(oit.value());
210         else
211             c->setObjectSourceDirs(oit.key(), oit.value());
212     }
213 }
214 
215