Commit 6dfd4ad8 authored by Josef Weidendorfer's avatar Josef Weidendorfer
Browse files

Load multiple files on command line into one window

Previously, if you had multiple profile data files in the
current directory, and did

	kcachegrind *

it loaded every file into a separate new toplevel window, which
for sure is not expected. It only works with local, uncompressed
files for now.
The change also is done for qcachegrind.

svn path=/trunk/KDE/kdesdk/kcachegrind/; revision=1320828
parent 802a3e21
......@@ -66,8 +66,8 @@ int main(int argc, char** argv)
bool sortByCount = false;
bool showCalls = false;
QString showEvent;
QStringList files;
TraceData* d = new TraceData(new Logger);
for(int arg = 0; arg<list.count(); arg++) {
if (list[arg] == "-h") showHelp(out);
else if (list[arg] == "-e") sortByExcl = true;
......@@ -76,8 +76,10 @@ int main(int argc, char** argv)
else if (list[arg] == "-c") sortByCount = true;
else if (list[arg] == "-s") showEvent = list[++arg];
else
d->load(list[arg]);
files << list[arg];
}
TraceData* d = new TraceData(new Logger);
d->load(files);
EventTypeSet* m = d->eventTypes();
if (m->realCount() == 0) {
......
......@@ -73,10 +73,10 @@ int main( int argc, char ** argv )
KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
int nbArgs = args->count();
if (nbArgs>0) {
for(int i = 0; i < nbArgs; i++) {
t = new TopLevel();
t->show();
t->loadDelayed(args->arg(i));
for(int i = 0; i < nbArgs; i++) {
t->loadDelayed(args->arg(i));
}
}
else {
......
......@@ -428,7 +428,7 @@ void TopLevel::createMiscActions()
action = actionCollection()->addAction( "file_add" );
action->setText( i18n( "&Add..." ) );
connect(action, SIGNAL(triggered(bool) ), SLOT(addTrace()));
connect(action, SIGNAL(triggered(bool) ), SLOT(add()));
hint = i18n("<b>Add Profile Data</b>"
"<p>This opens an additional profile data file in the current window.</p>");
action->setWhatsThis( hint );
......@@ -481,13 +481,13 @@ void TopLevel::createMiscActions()
"of the program.</p>");
_taDump->setWhatsThis( hint );
action = KStandardAction::open(this, SLOT(loadTrace()), actionCollection());
action = KStandardAction::open(this, SLOT(load()), actionCollection());
hint = i18n("<b>Open Profile Data</b>"
"<p>This opens a profile data file, with possible multiple parts</p>");
action->setToolTip( hint );
action->setWhatsThis( hint );
_openRecent = KStandardAction::openRecent(this, SLOT(loadTrace(const KUrl&)),
_openRecent = KStandardAction::openRecent(this, SLOT(load(const KUrl&)),
actionCollection());
KStandardAction::showStatusbar(this,
......@@ -911,11 +911,6 @@ void TopLevel::configureToolbars()
}
void TopLevel::newTrace()
{
// start cachegrind on command...
}
void TopLevel::newWindow()
{
TopLevel* t = new TopLevel();
......@@ -923,16 +918,16 @@ void TopLevel::newWindow()
}
void TopLevel::loadTrace()
void TopLevel::load()
{
KUrl url = KFileDialog::getOpenUrl(KUrl("kfiledialog:///"),
i18n("cachegrind.out* callgrind.out*|Callgrind Profile Data\n*|All Files"),
this,
i18n("Select Callgrind Profile Data"));
loadTrace(url);
load(url);
}
void TopLevel::loadTrace(const KUrl& url)
void TopLevel::load(const KUrl& url)
{
if (url.isEmpty()) return;
......@@ -943,7 +938,7 @@ void TopLevel::loadTrace(const KUrl& url)
_openRecent->addUrl(url);
_openRecent->saveEntries( KConfigGroup( KGlobal::config(), QString() ) );
loadTrace(tmpFile);
load(tmpFile);
KIO::NetAccess::removeTempFile( tmpFile );
} else {
KMessageBox::error(this, i18n("Could not open the file \"%1\". "
......@@ -955,7 +950,7 @@ void TopLevel::loadTrace(const KUrl& url)
/* if file name is ".": load first file found in current directory, but do
* not show an error message if nothing could be loaded
*/
void TopLevel::loadTrace(QString file)
void TopLevel::load(QString file)
{
if (file.isEmpty()) return;
......@@ -972,7 +967,6 @@ void TopLevel::loadTrace(QString file)
return;
}
// this constructor enables progress bar callbacks
bool loaded = openDataFile(file);
if (!loaded && showError)
KMessageBox::error(this, i18n("Could not open the file \"%1\". "
......@@ -981,16 +975,16 @@ void TopLevel::loadTrace(QString file)
}
void TopLevel::addTrace()
void TopLevel::add()
{
KUrl url = KFileDialog::getOpenUrl(KUrl(),
i18n("cachegrind.out* callgrind.out*|Callgrind Profile Data\n*|All Files"),
this,
i18n("Add Callgrind Profile Data"));
addTrace(url);
add(url);
}
void TopLevel::addTrace(const KUrl& url)
void TopLevel::add(const KUrl& url)
{
if (url.isEmpty()) return;
......@@ -1000,12 +994,12 @@ void TopLevel::addTrace(const KUrl& url)
_openRecent->addUrl(url);
_openRecent->saveEntries( KGlobal::config()->group( QString() ) );
addTrace(tmpFile);
add(tmpFile);
KIO::NetAccess::removeTempFile( tmpFile );
}
}
void TopLevel::addTrace(QString file)
void TopLevel::add(QString file)
{
if (file.isEmpty()) return;
......@@ -1017,7 +1011,6 @@ void TopLevel::addTrace(QString file)
return;
}
// this constructor enables progress bar callbacks
openDataFile(file);
}
......@@ -1025,20 +1018,36 @@ void TopLevel::addTrace(QString file)
void TopLevel::loadDelayed(QString file)
{
_loadTraceDelayed = file;
_loadFilesDelayed << file;
QTimer::singleShot(0, this, SLOT(loadTraceDelayed()));
}
void TopLevel::loadDelayed(QStringList files)
{
_loadFilesDelayed << files;
QTimer::singleShot(0, this, SLOT(loadTraceDelayed()));
}
void TopLevel::loadTraceDelayed()
{
if (_loadTraceDelayed.isEmpty()) return;
if (_loadFilesDelayed.isEmpty()) return;
// if URL scheme is missing (URL is relative), this is a local file
if (KUrl::isRelativeUrl(_loadTraceDelayed))
loadTrace(_loadTraceDelayed);
else
loadTrace(KUrl(_loadTraceDelayed));
_loadTraceDelayed = QString();
if (_loadFilesDelayed.count()>1) {
// FIXME: we expect all files to be local and existing
TraceData* d = new TraceData(this);
d->load(_loadFilesDelayed);
setData(d);
}
else {
QString file = _loadFilesDelayed[0];
// if URL scheme is missing (URL is relative), this is a local file
if (KUrl::isRelativeUrl(file))
load(file);
else
load(KUrl(file));
}
_loadFilesDelayed.clear();
}
......
......@@ -95,16 +95,16 @@ public:
virtual void loadFinished(const QString& msg); // msg could be error
public slots:
void newTrace();
void loadTrace();
void loadTrace(const KUrl&);
void loadTrace(QString);
void addTrace();
void addTrace(const KUrl&);
void addTrace(QString);
// for quick showing the main window...
void load();
void load(const KUrl&);
void load(QString);
void add();
void add(const KUrl&);
void add(QString);
// for quickly showing the main window...
void loadDelayed(QString);
void loadDelayed(QStringList);
void reload();
void exportGraph();
......@@ -278,7 +278,7 @@ private:
ProfileContext::Type _groupTypeDelayed;
TraceCostItem* _groupDelayed;
CostItem* _traceItemDelayed;
QString _loadTraceDelayed;
QStringList _loadFilesDelayed;
TraceItemView::Direction _directionDelayed;
// for status progress display
......
......@@ -3071,23 +3071,6 @@ TraceData::TraceData(Logger* l)
init();
}
TraceData::TraceData(const QString& base)
: ProfileCostArray(ProfileContext::context(ProfileContext::Data))
{
_logger = 0;
init();
load(base);
}
TraceData::TraceData(QIODevice* file, const QString& filename)
: ProfileCostArray(ProfileContext::context(ProfileContext::Data))
{
_logger = 0;
init();
load(file, filename);
}
void TraceData::init()
{
_functionCycleCount = 0;
......@@ -3138,75 +3121,52 @@ bool partLessThan(const TracePart* p1, const TracePart* p2)
}
/**
* Two cases:
* - <base> is a directory: Load first profile data file available
* - <base> is a file name without part/thread suffixes
* Load a list of files.
* If only one file is given, it is assumed to be a prefix, and all
* existing files with that prefix are loaded.
*
* Returns 0 if nothing found to load
*/
int TraceData::load(const QString& base)
{
bool baseExisting = true;
_traceName = base;
QFileInfo finfo(base);
QString file = finfo.fileName();
QDir dir = finfo.dir();
if (!finfo.exists()) {
baseExisting = false;
}
else if (finfo.isDir()) {
// search for first profile data file in directory
dir = QDir(base);
QStringList prefixList;
prefixList << "callgrind.out" << "cachegrind.out";
for ( QStringList::const_iterator it = prefixList.constBegin();
it != prefixList.constEnd(); ++it ) {
file = *it;
// search for ".pid"
QStringList strList = dir.entryList(QStringList() << file+".*", QDir::Files);
if (strList.count()>0) {
int l = file.length();
file = strList.first();
l++;
while(file[l] >= '0' && file[l] <= '9') l++;
file = file.left(l);
break;
}
}
_traceName = dir.path() + '/' + file;
}
int TraceData::load(QStringList files)
{
if (files.isEmpty()) return 0;
_traceName = files[0];
if (files.count() == 1) {
QString prefix = _traceName;
QFileInfo finfo(_traceName);
QDir dir = finfo.dir();
if (finfo.isDir()) {
prefix = "callgrind.out";
_traceName += "/callgrind.out";
}
QStringList strList;
strList += dir.entryList(QStringList() << file+".*" << file+"-*", QDir::Files);
files = dir.entryList(QStringList() << prefix + "*", QDir::Files);
}
baseExisting = QFile::exists(_traceName);
if (baseExisting)
strList << file;
if (files.isEmpty()) {
_traceName += ' ' + QObject::tr("(not found)");
return 0;
}
if (strList.count() == 0) {
_traceName = base + '/' + file + ' ' + QObject::tr("(not found)");
return 0;
}
QStringList::const_iterator it;
int partsLoaded = 0;
for (it = files.constBegin(); it != files.constEnd(); ++it ) {
QFile file(*it);
partsLoaded += internalLoad(&file, *it);
}
if (partsLoaded == 0) return 0;
QStringList::const_iterator it;
int partsLoaded = 0;
for (it = strList.constBegin(); it != strList.constEnd(); ++it ) {
QString filename = QString("%1/%2").arg(dir.path()).arg(*it);
QFile file(filename);
partsLoaded += internalLoad(&file, filename);
}
if (partsLoaded == 0) return 0;
qSort(_parts.begin(), _parts.end(), partLessThan);
invalidateDynamicCost();
updateFunctionCycles();
qSort(_parts.begin(), _parts.end(), partLessThan);
invalidateDynamicCost();
updateFunctionCycles();
return partsLoaded;
}
return partsLoaded;
int TraceData::load(QString file)
{
return load(QStringList(file));
}
int TraceData::load(QIODevice* file, const QString& filename)
......
......@@ -1364,20 +1364,20 @@ class TraceData: public ProfileCostArray
{
public:
TraceData(Logger* l = 0);
TraceData(const QString& base);
TraceData(QIODevice* file, const QString& filename);
virtual ~TraceData();
virtual TraceData* data() { return this; }
virtual const TraceData* data() const { return this; }
/**
* Loads a trace file.
* Loads profile data files.
* If a single file is given, it is assumed to be a prefix.
*
* This adjusts the EventTypeSet according to given cost types.
* Returns the number of parts loaded
*/
int load(const QString&);
int load(QStringList files);
int load(QString file);
int load(QIODevice*, const QString&);
/** returns true if something changed. These do NOT
......
......@@ -33,7 +33,6 @@
int main( int argc, char ** argv )
{
QApplication app(argc, argv);
QCGTopLevel* t;
Loader::initLoaders();
QCoreApplication::setOrganizationName("kcachegrind.sf.net");
......@@ -44,18 +43,15 @@ int main( int argc, char ** argv )
QStringList list = app.arguments();
list.pop_front();
if (!list.isEmpty()) {
foreach(const QString& file, list) {
t = new QCGTopLevel();
t->show();
t->loadDelayed( QDir::fromNativeSeparators(file) );
}
QCGTopLevel* t = new QCGTopLevel();
t->show();
if (list.isEmpty()) {
// load files in current dir
t->loadDelayed( ".", false);
}
else {
// load trace in current dir
t = new QCGTopLevel();
t->show();
t->loadDelayed(".", false);
foreach(const QString& file, list)
t->loadDelayed( QDir::fromNativeSeparators(file) );
}
int res = app.exec();
......
......@@ -254,7 +254,7 @@ void QCGTopLevel::recentFilesMenuAboutToShow()
void QCGTopLevel::recentFilesTriggered(QAction* action)
{
if (action)
loadTrace(QDir::fromNativeSeparators(action->text()));
load(QStringList(QDir::fromNativeSeparators(action->text())));
}
void QCGTopLevel::createDocks()
......@@ -332,11 +332,11 @@ void QCGTopLevel::createActions()
_openAction = new QAction(icon, tr("&Open..."), this);
_openAction->setShortcuts(QKeySequence::Open);
_openAction->setStatusTip(tr("Open profile data file"));
connect(_openAction, SIGNAL(triggered()), this, SLOT(loadTrace()));
connect(_openAction, SIGNAL(triggered()), this, SLOT(load()));
_addAction = new QAction(tr( "&Add..." ), this);
_addAction->setStatusTip(tr("Add profile data to current window"));
connect(_addAction, SIGNAL(triggered(bool)), SLOT(addTrace()));
connect(_addAction, SIGNAL(triggered(bool)), SLOT(add()));
_exportAction = new QAction(tr("Export Graph"), this);
_exportAction->setStatusTip(tr("Generate GraphViz file 'callgraph.dot'"));
......@@ -752,33 +752,33 @@ void QCGTopLevel::newWindow()
}
void QCGTopLevel::loadTrace()
void QCGTopLevel::load()
{
QString file;
file = QFileDialog::getOpenFileName(this,
QStringList files;
files = QFileDialog::getOpenFileNames(this,
tr("Open Callgrind Data"),
_lastFile,
tr("Callgrind Files (callgrind.*);;All Files (*)"));
loadTrace(file);
load(files);
}
void QCGTopLevel::loadTrace(QString file, bool addToRecentFiles)
void QCGTopLevel::load(QStringList files, bool addToRecentFiles)
{
if (file.isEmpty()) return;
_lastFile = file;
if (files.isEmpty()) return;
_lastFile = files[0];
if (_data && _data->parts().count()>0) {
// In new window
QCGTopLevel* t = new QCGTopLevel();
t->show();
t->loadDelayed(file, addToRecentFiles);
t->loadDelayed(files, addToRecentFiles);
return;
}
// this constructor enables progress bar callbacks
TraceData* d = new TraceData(this);
int filesLoaded = d->load(file);
int filesLoaded = d->load(files);
if (filesLoaded >0)
setData(d);
......@@ -789,34 +789,36 @@ void QCGTopLevel::loadTrace(QString file, bool addToRecentFiles)
ConfigGroup* generalConfig = ConfigStorage::group("GeneralSettings");
recentFiles = generalConfig->value("RecentFiles",
QStringList()).toStringList();
recentFiles.removeAll(file);
if (filesLoaded >0)
recentFiles.prepend(file);
if (recentFiles.count() >5)
recentFiles.removeLast();
foreach(QString file, files) {
recentFiles.removeAll(file);
if (filesLoaded >0)
recentFiles.prepend(file);
if (recentFiles.count() >5)
recentFiles.removeLast();
}
generalConfig->setValue("RecentFiles", recentFiles);
delete generalConfig;
}
void QCGTopLevel::addTrace()
void QCGTopLevel::add()
{
QString file;
file = QFileDialog::getOpenFileName(this,
QStringList files;
files = QFileDialog::getOpenFileNames(this,
tr("Add Callgrind Data"),
_lastFile,
tr("Callgrind Files (callgrind.*);;All Files (*)"));
addTrace(file);
add(files);
}
void QCGTopLevel::addTrace(QString file)
void QCGTopLevel::add(QStringList files)
{
if (file.isEmpty()) return;
_lastFile = file;
if (files.isEmpty()) return;
_lastFile = files[0];
if (_data) {
_data->load(file);
_data->load(files);
// GUI update for added data
configChanged();
......@@ -825,26 +827,33 @@ void QCGTopLevel::addTrace(QString file)
// this constructor enables progress bar callbacks
TraceData* d = new TraceData(this);
int filesLoaded = d->load(file);
int filesLoaded = d->load(files);
if (filesLoaded >0)
setData(d);
}
void QCGTopLevel::loadDelayed(QString file, bool addToRecentFiles)
{
_loadFilesDelayed << file;
_addToRecentFiles = addToRecentFiles;
QTimer::singleShot(0, this, SLOT(loadFilesDelayed()));
}
void QCGTopLevel::loadDelayed(QString file, bool addToRecentFiles)
void QCGTopLevel::loadDelayed(QStringList files, bool addToRecentFiles)
{
_loadTraceDelayed = file;
_loadFilesDelayed << files;
_addToRecentFiles = addToRecentFiles;
QTimer::singleShot(0, this, SLOT(loadTraceDelayed()));
QTimer::singleShot(0, this, SLOT(loadFilesDelayed()));
}
void QCGTopLevel::loadTraceDelayed()
void QCGTopLevel::loadFilesDelayed()
{
if (_loadTraceDelayed.isEmpty()) return;
if (_loadFilesDelayed.isEmpty()) return;
loadTrace(_loadTraceDelayed, _addToRecentFiles);
_loadTraceDelayed = QString();
load(_loadFilesDelayed, _addToRecentFiles);
_loadFilesDelayed.clear();
}
......
......@@ -85,13 +85,14 @@ public:
virtual void loadFinished(const QString& msg); // msg could be error
public slots:
void loadTrace();
void loadTrace(QString, bool addToRecentFiles = true);
void addTrace();
void addTrace(QString);
void load();
void load(QStringList files, bool addToRecentFiles = true);
void add();
void add(QStringList files);
// shows the main window before loading to see loading progress
void loadDelayed(QString, bool addToRecentFiles = true);
void loadDelayed(QString file, bool addToRecentFiles = true);
void loadDelayed(QStringList files, bool addToRecentFiles = true);
void exportGraph();
void newWindow();
......@@ -172,7 +173,7 @@ public slots:
void setGroupTypeDelayed();
void setGroupDelayed();