diff --git a/CMakeLists.txt b/CMakeLists.txt index 3fba6b5..ab42086 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,36 +1,60 @@ -cmake_minimum_required(VERSION 2.8.9) -PROJECT(massif-visualizer) +cmake_minimum_required(VERSION 2.8.12 FATAL_ERROR) +project(massif-visualizer) -enable_testing() +set(QT_MIN_VERSION "5.2.0") + +find_package(ECM 0.0.9 REQUIRED NO_MODULE) +set(CMAKE_MODULE_PATH + ${CMAKE_CURRENT_SOURCE_DIR}/cmake/ + ${CMAKE_MODULE_PATH} + ${ECM_MODULE_PATH} + ${ECM_KDE_MODULE_DIR} +) + +include(KDEInstallDirs) +include(KDECMakeSettings) +include(KDECompilerSettings) +include(ECMOptionalAddSubdirectory) +include(ECMInstallIcons) +include(FeatureSummary) -set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/ ${CMAKE_MODULE_PATH}) +enable_testing() -set(KDE_MIN_VERSION "4.7.0") -find_package(KDE4 4.7.0 REQUIRED) +find_package(KGraphViewer 2.1) +#macro_log_feature(KGRAPHVIEWER_FOUND "KGraphViewer" "KPart to view callgraph dot files." +# "http://extragear.kde.org/apps/kgraphviewer/" FALSE "" +# "Required for detailed snapshot analysis. From KDE SDK Extragear package, KGraphViewer 2.1 or higher is required.") -include (KDE4Defaults) -include (MacroLibrary) +# macro_display_feature_log() -macro_optional_find_package(KGraphViewer 2.1) -macro_log_feature(KGRAPHVIEWER_FOUND "KGraphViewer" "KPart to view callgraph dot files." - "http://extragear.kde.org/apps/kgraphviewer/" FALSE "" - "Required for detailed snapshot analysis. From KDE SDK Extragear package, KGraphViewer 2.1 or higher is required.") +find_package(Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED + Core + Widgets + Svg + XmlPatterns +) -macro_display_feature_log() +find_package(KF5 REQUIRED COMPONENTS + Archive + Config + CoreAddons + KIO + I18n + KDELibs4Support +) include_directories( - ${KDE4_INCLUDES} + ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/kdchart/include/KDChart ) add_definitions(-Wall) add_subdirectory(kdchart) add_subdirectory(massifdata) add_subdirectory(visualizer) add_subdirectory(app) add_subdirectory(pics) - -add_subdirectory(test) +#add_subdirectory(test) diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 086839a..d35a367 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -1,50 +1,49 @@ include_directories( ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ) if(KGRAPHVIEWER_FOUND) include_directories( ${KGRAPHVIEWER_INCLUDE_DIRECTORIES} ) add_definitions(-DHAVE_KGRAPHVIEWER) endif(KGRAPHVIEWER_FOUND) set(massif-visualizer_SRCS main.cpp mainwindow.cpp configdialog.cpp documentwidget.cpp ) -kde4_add_kcfg_files(massif-visualizer_SRCS massif-visualizer-settings.kcfgc) +kconfig_add_kcfg_files(massif-visualizer_SRCS massif-visualizer-settings.kcfgc) -kde4_add_ui_files(massif-visualizer_SRCS mainwindow.ui config.ui) +qt5_wrap_ui(massif-visualizer_SRCS mainwindow.ui config.ui) -kde4_add_executable(massif-visualizer ${massif-visualizer_SRCS}) +add_executable(massif-visualizer ${massif-visualizer_SRCS}) target_link_libraries(massif-visualizer - ${KDE4_KDEUI_LIBS} - ${KDE4_KIO_LIBS} - ${KDE4_KPARTS_LIBS} + KF5::KIOCore + KF5::KDELibs4Support mv-kdchart mv-massifdata mv-visualizer ) install( TARGETS massif-visualizer ${INSTALL_TARGETS_DEFAULT_ARGS} ) install( FILES massif-visualizerui.rc DESTINATION ${DATA_INSTALL_DIR}/massif-visualizer ) install(FILES massif-visualizer-settings.kcfg DESTINATION ${KCFG_INSTALL_DIR}) install(PROGRAMS massif-visualizer.desktop DESTINATION ${XDG_APPS_INSTALL_DIR}) # XML mime type set( SHARED_MIME_INFO_MINIMUM_VERSION "0.30" ) set( XDG_MIME_INSTALL_DIR "share/mime/packages" ) find_package( SharedMimeInfo ) if( SHARED_MIME_INFO_FOUND ) install( FILES massif.xml DESTINATION ${XDG_MIME_INSTALL_DIR} ) update_xdg_mimetypes( ${XDG_MIME_INSTALL_DIR} ) endif( SHARED_MIME_INFO_FOUND ) diff --git a/app/configdialog.cpp b/app/configdialog.cpp index 717bd18..2121201 100644 --- a/app/configdialog.cpp +++ b/app/configdialog.cpp @@ -1,52 +1,54 @@ /* This file is part of Massif Visualizer Copyright 2010 Milian Wolff 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) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "configdialog.h" #include "massif-visualizer-settings.h" #include "ui_config.h" +#include + using namespace Massif; ConfigDialog::ConfigDialog(QWidget* parent) : KConfigDialog(parent, "settings", Settings::self()) , m_ui(new Ui::Config) { setAttribute(Qt::WA_DeleteOnClose, true); QWidget* settingsPage = new QWidget(this); m_ui->setupUi(settingsPage); addPage(settingsPage, Settings::self(), i18n("Settings")); setFaceType(KPageDialog::Plain); } ConfigDialog::~ConfigDialog() { } bool ConfigDialog::isShown() { return KConfigDialog::showDialog("settings"); } #include "configdialog.moc" diff --git a/app/documentwidget.cpp b/app/documentwidget.cpp index b9d65c2..0011a79 100644 --- a/app/documentwidget.cpp +++ b/app/documentwidget.cpp @@ -1,612 +1,612 @@ /* This file is part of Massif Visualizer Copyright 2010 Milian Wolff Copyright 2013 Arnold Dumas 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) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "documentwidget.h" #include #include "KDChartChart" #include "KDChartGridAttributes" #include "KDChartHeaderFooter" #include "KDChartCartesianCoordinatePlane" #include "KDChartLegend" #include "KDChartDataValueAttributes" #include "KDChartBackgroundAttributes" #include "KDChartPlotter" #include "massifdata/filedata.h" #include "massifdata/parser.h" #include "massifdata/parseworker.h" #include "massifdata/snapshotitem.h" #include "massifdata/treeleafitem.h" #include "massifdata/util.h" #include "visualizer/totalcostmodel.h" #include "visualizer/detailedcostmodel.h" #include "visualizer/datatreemodel.h" #include "visualizer/filtereddatatreemodel.h" #include "visualizer/dotgraphgenerator.h" #include #include #include #include #include #include // forward include not available until later KDE versions... #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_KGRAPHVIEWER #include #endif using namespace Massif; using namespace KDChart; static void markPeak(Plotter* p, const QModelIndex& peak, quint64 cost, const QPen& foreground) { DataValueAttributes dataAttributes = p->dataValueAttributes(peak); dataAttributes.setDataLabel(prettyCost(cost)); dataAttributes.setVisible(true); MarkerAttributes a = dataAttributes.markerAttributes(); a.setMarkerSize(QSizeF(2, 2)); a.setPen(foreground); a.setMarkerStyle(MarkerAttributes::MarkerCircle); a.setVisible(true); dataAttributes.setMarkerAttributes(a); TextAttributes txtAttrs = dataAttributes.textAttributes(); txtAttrs.setPen(foreground); txtAttrs.setFontSize(Measure(12)); dataAttributes.setTextAttributes(txtAttrs); BackgroundAttributes bkgAtt = dataAttributes.backgroundAttributes(); QBrush brush = p->model()->data(peak, DatasetBrushRole).value(); QColor c = brush.color(); c.setAlpha(127); brush.setColor(c); bkgAtt.setBrush(brush); bkgAtt.setVisible(true); dataAttributes.setBackgroundAttributes(bkgAtt); p->setDataValueAttributes(peak, dataAttributes); } DocumentWidget::DocumentWidget(QWidget* parent) : QWidget(parent), m_chart(new Chart(this)) , m_header(new QLabel(this)) , m_totalDiagram(0) , m_totalCostModel(new TotalCostModel(m_chart)) , m_detailedDiagram(0) , m_detailedCostModel(new DetailedCostModel(m_chart)) , m_legend(new Legend(m_chart)) , m_dataTreeModel(new DataTreeModel(m_chart)) , m_dataTreeFilterModel(new FilteredDataTreeModel(m_dataTreeModel)) , m_data(0) , m_stackedWidget(new QStackedWidget(this)) , m_errorMessage(0) , m_loadingMessage(0) , m_loadingProgressBar(0) , m_stopParserButton(0) , m_isLoaded(false) #ifdef HAVE_KGRAPHVIEWER , m_graphViewerPart(0) , m_graphViewer(0) , m_dotGenerator(0) , m_displayTabWidget(0) #endif { // HACK: otherwise the legend becomes _really_ large and might even crash X... // to visualize the issue, try: m_chart->setMaximumSize(QSize(10000, 10000)); m_chart->setMaximumSize(qApp->desktop()->size()); m_chart->setContextMenuPolicy(Qt::CustomContextMenu); m_legend->setPosition(Position(KDChartEnums::PositionFloating)); m_legend->setTitleText(""); m_legend->setAlignment(Qt::AlignVCenter | Qt::AlignLeft); m_legend->setSortOrder(Qt::DescendingOrder); m_chart->addLegend(m_legend); //NOTE: this has to be set _after_ the legend was added to the chart... TextAttributes att = m_legend->textAttributes(); att.setAutoShrink(true); att.setFontSize(Measure(12)); QFont font("monospace"); font.setStyleHint(QFont::TypeWriter); att.setFont(font); m_legend->setTextAttributes(att); m_legend->setTextAlignment(Qt::AlignLeft); m_legend->hide(); // Set m_stackedWidget as the main widget. setLayout(new QVBoxLayout(this)); layout()->addWidget(m_stackedWidget); QWidget* memoryConsumptionWidget = new QWidget; memoryConsumptionWidget->setLayout(new QVBoxLayout(memoryConsumptionWidget)); memoryConsumptionWidget->layout()->addWidget(m_header); memoryConsumptionWidget->layout()->addWidget(m_chart); #ifdef HAVE_KGRAPHVIEWER static KPluginFactory *factory = KPluginLoader("kgraphviewerpart").factory(); if (factory) { m_graphViewerPart = factory->create("kgraphviewerpart", this); if (m_graphViewerPart) { m_displayTabWidget = new QTabWidget(m_stackedWidget); m_displayTabWidget->setTabPosition(QTabWidget::South); m_displayTabWidget->addTab(memoryConsumptionWidget, i18n("&Evolution of Memory Consumption")); m_graphViewer = qobject_cast< KGraphViewer::KGraphViewerInterface* >(m_graphViewerPart); QWidget* dotGraphWidget = new QWidget(m_displayTabWidget); dotGraphWidget->setLayout(new QVBoxLayout); dotGraphWidget->layout()->addWidget(m_graphViewerPart->widget()); m_displayTabWidget->addTab(dotGraphWidget, i18n("&Detailed Snapshot Analysis")); m_stackedWidget->addWidget(m_displayTabWidget); connect(m_graphViewerPart, SIGNAL(graphLoaded()), this, SLOT(slotGraphLoaded())); connect(m_displayTabWidget, SIGNAL(currentChanged(int)), this, SLOT(slotTabChanged(int))); slotTabChanged(m_displayTabWidget->currentIndex()); } } if (!m_graphViewerPart) { m_stackedWidget->addWidget(memoryConsumptionWidget); } #else m_stackedWidget->addWidget(memoryConsumptionWidget); #endif // Second widget : loadingPage QWidget* loadingPage = new QWidget(m_stackedWidget); QVBoxLayout* verticalLayout = new QVBoxLayout(loadingPage); QSpacerItem* upperSpacerItem = new QSpacerItem(20, 247, QSizePolicy::Minimum, QSizePolicy::Expanding); verticalLayout->addItem(upperSpacerItem); m_loadingMessage = new QLabel(loadingPage); m_loadingMessage->setText(i18n("loading...")); m_loadingMessage->setAlignment(Qt::AlignCenter); verticalLayout->addWidget(m_loadingMessage); m_loadingProgressBar = new QProgressBar(loadingPage); m_loadingProgressBar->setValue(24); m_loadingProgressBar->setRange(0, 0); verticalLayout->addWidget(m_loadingProgressBar); QWidget* stopParserWidget = new QWidget(loadingPage); stopParserWidget->setLayoutDirection(Qt::LeftToRight); QHBoxLayout* stopParserWidgetLayout = new QHBoxLayout(stopParserWidget); m_stopParserButton = new QToolButton(stopParserWidget); m_stopParserButton->setObjectName(QString::fromUtf8("stopParsing")); m_stopParserButton->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); m_stopParserButton->setIcon(KIcon("process-stop")); m_stopParserButton->setIconSize(QSize(48, 48)); connect(m_stopParserButton, SIGNAL(clicked()), this, SIGNAL(stopParser())); stopParserWidgetLayout->addWidget(m_stopParserButton); verticalLayout->addWidget(stopParserWidget); QSpacerItem* bottomSpacerItem = new QSpacerItem(20, 230, QSizePolicy::Minimum, QSizePolicy::Expanding); verticalLayout->addItem(bottomSpacerItem); m_stackedWidget->addWidget(loadingPage); // By default we show the loadingPage. m_stackedWidget->setCurrentIndex(1); } DocumentWidget::~DocumentWidget() { if (m_data) { #ifdef HAVE_KGRAPHVIEWER if (m_dotGenerator) { if (m_dotGenerator->isRunning()) { disconnect(m_dotGenerator.data(), 0, this, 0); connect(m_dotGenerator.data(), SIGNAL(finished()), m_dotGenerator.data(), SLOT(deleteLater())); m_dotGenerator->cancel(); m_dotGenerator.take(); } m_dotGenerator.reset(); } if (m_graphViewer) { m_graphViewerPart->closeUrl(); } m_lastDotItem.first = 0; m_lastDotItem.second = 0; #endif m_chart->replaceCoordinatePlane(new CartesianCoordinatePlane); m_legend->removeDiagrams(); foreach(CartesianAxis* axis, m_detailedDiagram->axes()) { m_detailedDiagram->takeAxis(axis); delete axis; } m_detailedDiagram->deleteLater(); m_detailedDiagram = 0; foreach(CartesianAxis* axis, m_totalDiagram->axes()) { m_totalDiagram->takeAxis(axis); delete axis; } m_totalDiagram->deleteLater(); m_totalDiagram = 0; m_dataTreeModel->setSource(0); m_dataTreeFilterModel->setFilter(""); m_detailedCostModel->setSource(0); m_totalCostModel->setSource(0); delete m_data; m_data = 0; m_file.clear(); } } -KUrl DocumentWidget::file() const +QUrl DocumentWidget::file() const { return m_file; } FileData* DocumentWidget::data() const { return m_data; } Chart* DocumentWidget::chart() const { return m_chart; } Plotter* DocumentWidget::totalDiagram() const { return m_totalDiagram; } TotalCostModel* DocumentWidget::totalCostModel() const { return m_totalCostModel; } Plotter* DocumentWidget::detailedDiagram() const { return m_detailedDiagram; } DetailedCostModel* DocumentWidget::detailedCostModel() const { return m_detailedCostModel; } DataTreeModel* DocumentWidget::dataTreeModel() const { return m_dataTreeModel; } FilteredDataTreeModel* DocumentWidget::dataTreeFilterModel() const { return m_dataTreeFilterModel; } #ifdef HAVE_KGRAPHVIEWER KGraphViewer::KGraphViewerInterface* DocumentWidget::graphViewer() { return m_graphViewer; } void DocumentWidget::focusExpensiveGraphNode() { Q_ASSERT(m_graphViewer); Q_ASSERT(m_dotGenerator); m_graphViewer->centerOnNode(m_dotGenerator->mostCostIntensiveGraphvizId()); } int DocumentWidget::currentIndex() { if (!m_displayTabWidget) { // happens when kgraphviewer part is not available at runtime return 0; } return m_displayTabWidget->currentIndex(); } #endif bool DocumentWidget::isLoaded() const { return m_isLoaded; } -void DocumentWidget::parserFinished(const KUrl& file, FileData* data) +void DocumentWidget::parserFinished(const QUrl &file, FileData* data) { Q_ASSERT(data->peak()); // give the progress bar one last chance to update QApplication::processEvents(); kDebug() << "loaded massif file:" << file; qDebug() << "description:" << data->description(); qDebug() << "command:" << data->cmd(); qDebug() << "time unit:" << data->timeUnit(); qDebug() << "snapshots:" << data->snapshots().size(); qDebug() << "peak: snapshot #" << data->peak()->number() << "after" << QString("%1%2").arg(data->peak()->time()).arg(data->timeUnit()); qDebug() << "peak cost:" << prettyCost(data->peak()->memHeap()) << " heap" << prettyCost(data->peak()->memHeapExtra()) << " heap extra" << prettyCost(data->peak()->memStacks()) << " stacks"; m_data = data; m_file = file; #ifdef HAVE_KGRAPHVIEWER if (m_graphViewer) { showDotGraph(QPair(0, m_data->peak())); } #endif //BEGIN KDChart KColorScheme scheme(QPalette::Active, KColorScheme::Window); QPen foreground(scheme.foreground().color()); //Begin Legend BackgroundAttributes bkgAtt = m_legend->backgroundAttributes(); QColor background = scheme.background(KColorScheme::AlternateBackground).color(); background.setAlpha(200); bkgAtt.setBrush(QBrush(background)); bkgAtt.setVisible(true); m_legend->setBackgroundAttributes(bkgAtt); TextAttributes txtAttrs = m_legend->textAttributes(); txtAttrs.setPen(foreground); m_legend->setTextAttributes(txtAttrs); m_header->setAlignment(Qt::AlignCenter); updateHeader(); //BEGIN TotalDiagram m_totalDiagram = new Plotter; m_totalDiagram->setAntiAliasing(true); CartesianAxis* bottomAxis = new CartesianAxis(m_totalDiagram); TextAttributes axisTextAttributes = bottomAxis->textAttributes(); axisTextAttributes.setPen(foreground); axisTextAttributes.setFontSize(Measure(10)); bottomAxis->setTextAttributes(axisTextAttributes); TextAttributes axisTitleTextAttributes = bottomAxis->titleTextAttributes(); axisTitleTextAttributes.setPen(foreground); axisTitleTextAttributes.setFontSize(Measure(12)); bottomAxis->setTitleTextAttributes(axisTitleTextAttributes); bottomAxis->setTitleText(i18n("time in %1", m_data->timeUnit())); bottomAxis->setPosition ( CartesianAxis::Bottom ); m_totalDiagram->addAxis(bottomAxis); CartesianAxis* rightAxis = new CartesianAxis(m_totalDiagram); rightAxis->setTextAttributes(axisTextAttributes); rightAxis->setTitleTextAttributes(axisTitleTextAttributes); rightAxis->setTitleText(i18n("memory heap size in kilobytes")); rightAxis->setPosition ( CartesianAxis::Right ); m_totalDiagram->addAxis(rightAxis); m_totalCostModel->setSource(m_data); m_totalDiagram->setModel(m_totalCostModel); CartesianCoordinatePlane* coordinatePlane = dynamic_cast(m_chart->coordinatePlane()); Q_ASSERT(coordinatePlane); coordinatePlane->addDiagram(m_totalDiagram); GridAttributes gridAttributes = coordinatePlane->gridAttributes(Qt::Horizontal); gridAttributes.setAdjustBoundsToGrid(false, false); coordinatePlane->setGridAttributes(Qt::Horizontal, gridAttributes); m_legend->addDiagram(m_totalDiagram); m_detailedDiagram = new Plotter; m_detailedDiagram->setAntiAliasing(true); m_detailedDiagram->setType(Plotter::Stacked); m_detailedCostModel->setSource(m_data); m_detailedDiagram->setModel(m_detailedCostModel); updatePeaks(); coordinatePlane->addDiagram(m_detailedDiagram); m_legend->addDiagram(m_detailedDiagram); m_legend->show(); m_dataTreeModel->setSource(m_data); m_isLoaded = true; // Switch to the display page and notify that everything is setup. m_stackedWidget->setCurrentIndex(0); emit loadingFinished(); } void DocumentWidget::setDetailedDiagramHidden(bool hidden) { m_detailedDiagram->setHidden(hidden); } void DocumentWidget::setDetailedDiagramVisible(bool visible) { m_detailedDiagram->setVisible(visible); } void DocumentWidget::setTotalDiagramHidden(bool hidden) { m_totalDiagram->setHidden(hidden); } void DocumentWidget::setTotalDiagramVisible(bool visible) { m_totalDiagram->setVisible(visible); } void DocumentWidget::setProgress(int value) { m_loadingProgressBar->setValue(value); } void DocumentWidget::setRange(int minimum, int maximum) { m_loadingProgressBar->setRange(minimum, maximum); } void DocumentWidget::setLoadingMessage(const QString& message) { m_loadingMessage->setText(message); } void DocumentWidget::showError(const QString& title, const QString& error) { if (!m_errorMessage) { m_errorMessage = new KMessageWidget(m_stackedWidget); m_stackedWidget->addWidget(m_errorMessage); m_errorMessage->setWordWrap(true); m_errorMessage->setMessageType(KMessageWidget::Error); m_errorMessage->setCloseButtonVisible(false); } m_errorMessage->setText(QString("%1

%2

").arg(title).arg(error)); m_stackedWidget->setCurrentWidget(m_errorMessage); } void DocumentWidget::updateHeader() { const QString app = m_data->cmd().split(' ', QString::SkipEmptyParts).first(); m_header->setText(QString("%1
%2") .arg(i18n("Memory consumption of %1", app)) .arg(i18n("Peak of %1 at snapshot #%2", prettyCost(m_data->peak()->cost()), m_data->peak()->number())) ); m_header->setToolTip(i18n("Command: %1\nValgrind Options: %2", m_data->cmd(), m_data->description())); } void DocumentWidget::updatePeaks() { KColorScheme scheme(QPalette::Active, KColorScheme::Window); QPen foreground(scheme.foreground().color()); if (m_data->peak()) { const QModelIndex peak = m_totalCostModel->peak(); Q_ASSERT(peak.isValid()); markPeak(m_totalDiagram, peak, m_data->peak()->cost(), foreground); } updateDetailedPeaks(); } void DocumentWidget::updateDetailedPeaks() { KColorScheme scheme(QPalette::Active, KColorScheme::Window); QPen foreground(scheme.foreground().color()); QMap< QModelIndex, TreeLeafItem* > peaks = m_detailedCostModel->peaks(); QMap< QModelIndex, TreeLeafItem* >::const_iterator it = peaks.constBegin(); while (it != peaks.constEnd()) { const QModelIndex peak = it.key(); Q_ASSERT(peak.isValid()); markPeak(m_detailedDiagram, peak, it.value()->cost(), foreground); ++it; } } #ifdef HAVE_KGRAPHVIEWER void DocumentWidget::slotTabChanged(int index) { emit tabChanged(index); if (index == 1) { // if we parsed a dot graph we might want to show it now showDotGraph(); } } void DocumentWidget::showDotGraph(const QPair& item) { if (item == m_lastDotItem) { return; } m_lastDotItem = item; Q_ASSERT(m_graphViewer); kDebug() << "new dot graph requested" << item; if (m_dotGenerator) { kDebug() << "existing generator is running:" << m_dotGenerator->isRunning(); if (m_dotGenerator->isRunning()) { disconnect(m_dotGenerator.data(), 0, this, 0); connect(m_dotGenerator.data(), SIGNAL(finished()), m_dotGenerator.data(), SLOT(deleteLater())); m_dotGenerator->cancel(); m_dotGenerator.take(); } m_dotGenerator.reset(); } if (!item.first && !item.second) { return; } if (item.second) { m_dotGenerator.reset(new DotGraphGenerator(item.second, m_data->timeUnit(), this)); } else { m_dotGenerator.reset(new DotGraphGenerator(item.first, m_data->timeUnit(), this)); } m_dotGenerator->start(); connect(m_dotGenerator.data(), SIGNAL(finished()), this, SLOT(showDotGraph())); } void DocumentWidget::showDotGraph() { if (!m_dotGenerator || !m_graphViewerPart || !m_graphViewerPart->widget()->isVisible()) { return; } kDebug() << "show dot graph in output file" << m_dotGenerator->outputFile(); - if (!m_dotGenerator->outputFile().isEmpty() && m_graphViewerPart->url() != KUrl(m_dotGenerator->outputFile())) { - m_graphViewerPart->openUrl(KUrl(m_dotGenerator->outputFile())); + if (!m_dotGenerator->outputFile().isEmpty() && m_graphViewerPart->url() != QUrl(m_dotGenerator->outputFile())) { + m_graphViewerPart->openUrl(QUrl(m_dotGenerator->outputFile())); } } void DocumentWidget::slotGraphLoaded() { Q_ASSERT(m_graphViewer); if (!m_dotGenerator) { return; } m_graphViewer->setZoomFactor(0.75); m_graphViewer->setPannerPosition(KGraphViewer::KGraphViewerInterface::BottomRight); m_graphViewer->setPannerEnabled(true); m_graphViewer->centerOnNode(m_dotGenerator->mostCostIntensiveGraphvizId()); } #endif diff --git a/app/documentwidget.h b/app/documentwidget.h index bcbc939..150788e 100644 --- a/app/documentwidget.h +++ b/app/documentwidget.h @@ -1,163 +1,163 @@ /* This file is part of Massif Visualizer Copyright 2010 Milian Wolff Copyright 2013 Arnold Dumas 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) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef DOCUMENTWIDGET_H #define DOCUMENTWIDGET_H #include -#include +#include namespace KDChart { class Chart; class HeaderFooter; class CartesianAxis; class Legend; class BarDiagram; class Plotter; } class QLabel; class QProgressBar; class QToolButton; class QStackedWidget; class QTabWidget; class KMessageWidget; namespace KParts { class ReadOnlyPart; } namespace Massif { class FileData; class TotalCostModel; class DetailedCostModel; class DataTreeModel; class FilteredDataTreeModel; class TreeLeafItem; class SnapshotItem; class DotGraphGenerator; } #ifdef HAVE_KGRAPHVIEWER namespace KGraphViewer { class KGraphViewerInterface; } #endif class DocumentWidget : public QWidget { Q_OBJECT public: explicit DocumentWidget(QWidget* parent = 0); ~DocumentWidget(); void updateHeader(); void updatePeaks(); - KUrl file() const; + QUrl file() const; Massif::FileData* data() const; KDChart::Chart* chart() const; KDChart::Plotter* totalDiagram() const; Massif::TotalCostModel* totalCostModel() const; KDChart::Plotter* detailedDiagram() const; Massif::DetailedCostModel* detailedCostModel() const; Massif::DataTreeModel* dataTreeModel() const; Massif::FilteredDataTreeModel* dataTreeFilterModel() const; #ifdef HAVE_KGRAPHVIEWER KGraphViewer::KGraphViewerInterface* graphViewer(); void showDotGraph(const QPair& item); void focusExpensiveGraphNode(); int currentIndex(); #endif bool isLoaded() const; signals: void stopParser(); void loadingFinished(); void tabChanged(int); -public slots: - void parserFinished(const KUrl& file, Massif::FileData* data); +public Q_SLOTS: + void parserFinished(const QUrl& file, Massif::FileData* data); void setDetailedDiagramHidden(bool hidden); void setDetailedDiagramVisible(bool visible); void setTotalDiagramHidden(bool hidden); void setTotalDiagramVisible(bool visible); void setProgress(int value); void setRange(int minimum, int maximum); void setLoadingMessage(const QString& message); void showError(const QString& title, const QString& error); #ifdef HAVE_KGRAPHVIEWER void showDotGraph(); #endif -private slots: +private Q_SLOTS: #ifdef HAVE_KGRAPHVIEWER void slotTabChanged(int index); void slotGraphLoaded(); #endif private: void updateDetailedPeaks(); KDChart::Chart* m_chart; QLabel* m_header; KDChart::Plotter* m_totalDiagram; Massif::TotalCostModel* m_totalCostModel; KDChart::Plotter* m_detailedDiagram; Massif::DetailedCostModel* m_detailedCostModel; KDChart::Legend* m_legend; Massif::DataTreeModel* m_dataTreeModel; Massif::FilteredDataTreeModel* m_dataTreeFilterModel; Massif::FileData* m_data; - KUrl m_file; + QUrl m_file; QStackedWidget* m_stackedWidget; KMessageWidget* m_errorMessage; QLabel* m_loadingMessage; QProgressBar* m_loadingProgressBar; QToolButton* m_stopParserButton; bool m_isLoaded; #ifdef HAVE_KGRAPHVIEWER KParts::ReadOnlyPart* m_graphViewerPart; KGraphViewer::KGraphViewerInterface* m_graphViewer; QScopedPointer m_dotGenerator; QPair m_lastDotItem; QTabWidget* m_displayTabWidget; #endif }; #endif // DOCUMENTWIDGET_H diff --git a/app/main.cpp b/app/main.cpp index 43c81da..ca80f14 100644 --- a/app/main.cpp +++ b/app/main.cpp @@ -1,65 +1,79 @@ /* This file is part of Massif Visualizer Copyright 2010 Milian Wolff 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) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ +#include + #include #include -#include #include #include -#include #include #include "mainwindow.h" int main( int argc, char *argv[] ) { - KAboutData aboutData( "massif-visualizer", 0, ki18n( "Massif Visualizer" ), - "0.4", ki18n("A visualizer for output generated by Valgrind's massif tool."), KAboutData::License_LGPL, - ki18n( "Copyright 2010-2014, Milian Wolff " ), - KLocalizedString(), "", "massif-visualizer@kde.org" ); + QApplication app(argc, argv); + + KAboutData aboutData(QStringLiteral("massif-visualizer"), i18n("Massif Visualizer"), QStringLiteral("0.4"), + i18n("A visualizer for output generated by Valgrind's massif tool."), KAboutData::License_GPL_V2, + i18n("Copyright 2010-2014, Milian Wolff "), QString(), QStringLiteral("massif-visualizer@kde.org")); - aboutData.addAuthor(ki18n("Milian Wolff"), ki18n("Original author, maintainer"), - "mail@milianw.de", "http://milianw.de"); + aboutData.addAuthor(i18n("Milian Wolff"), i18n("Original author, maintainer"), + QStringLiteral("mail@milianw.de"), QStringLiteral("http://milianw.de")); - aboutData.addAuthor(ki18n("Arnold Dumas"), ki18n("Multiple document interface, bug fixes"), - "contact@arnolddumas.fr", "http://arnolddumas.fr"); + aboutData.addAuthor(i18n("Arnold Dumas"), i18n("Multiple document interface, bug fixes"), + QStringLiteral("contact@arnolddumas.fr"), QStringLiteral("http://arnolddumas.fr")); + aboutData.setOrganizationDomain("kde.org"); aboutData.setProgramIconName("office-chart-area"); + KAboutData::setApplicationData(aboutData); + + app.setApplicationName(aboutData.componentName()); + app.setApplicationDisplayName(aboutData.displayName()); + app.setOrganizationDomain(aboutData.organizationDomain()); + app.setApplicationVersion(aboutData.version()); + + // FIXME: Port to KF5 +#if 0 KCmdLineArgs::init( argc, argv, &aboutData, KCmdLineArgs::CmdLineArgNone ); KCmdLineOptions options; options.add("+file", ki18n("Opens given output file and visualize it.")); KCmdLineArgs::addCmdLineOptions( options ); KCmdLineArgs* args = KCmdLineArgs::parsedArgs(); - KApplication app; +#endif Massif::MainWindow* window = new Massif::MainWindow; + // FIXME: Port to KF5 +#if 0 for (int i = 0; i < args->count(); ++i) { window->openFile(args->url(i)); } +#endif window->show(); return app.exec(); } diff --git a/app/mainwindow.cpp b/app/mainwindow.cpp index 9d52afa..4545089 100644 --- a/app/mainwindow.cpp +++ b/app/mainwindow.cpp @@ -1,858 +1,859 @@ /* This file is part of Massif Visualizer Copyright 2010 Milian Wolff Copyright 2013 Arnold Dumas 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) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "mainwindow.h" #include "KDChartChart" #include "KDChartPlotter" #include "massifdata/filedata.h" #include "massifdata/parser.h" #include "massifdata/parseworker.h" #include "massifdata/snapshotitem.h" #include "massifdata/treeleafitem.h" #include "massifdata/util.h" #include "visualizer/totalcostmodel.h" #include "visualizer/detailedcostmodel.h" #include "visualizer/datatreemodel.h" #include "visualizer/filtereddatatreemodel.h" #include "visualizer/dotgraphgenerator.h" #include "massif-visualizer-settings.h" #include "configdialog.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_KGRAPHVIEWER #include #endif using namespace Massif; using namespace KDChart; // Helper function static KConfigGroup allocatorConfig() { return KGlobal::config()->group("Allocators"); } MainWindow::MainWindow(QWidget* parent, Qt::WindowFlags f) : KParts::MainWindow(parent, f) , m_toggleTotal(0) , m_selectPeak(0) , m_recentFiles(0) , m_box(new QSpinBox(this)) , m_zoomIn(0) , m_zoomOut(0) , m_focusExpensive(0) , m_close(0) , m_print(0) , m_stopParser(0) , m_allocatorModel(new QStringListModel(this)) , m_newAllocator(0) , m_removeAllocator(0) , m_shortenTemplates(0) , m_currentDocument(0) { ui.setupUi(this); setWindowTitle(i18n("Massif Visualizer")); //BEGIN KGraphViewer bool haveGraphViewer = false; // NOTE: just check if kgraphviewer is available at runtime. // The former logic has been moved to DocumentWidget constructor. #ifdef HAVE_KGRAPHVIEWER KPluginFactory *factory = KPluginLoader("kgraphviewerpart").factory(); if (factory) { KParts::ReadOnlyPart* readOnlyPart = factory->create("kgraphviewerpart", this); if (readOnlyPart) { readOnlyPart->widget()->hide(); haveGraphViewer = true; } } #endif if (!haveGraphViewer) { // cleanup UI when we installed with kgraphviewer but it's not available at runtime KToolBar* callgraphToolbar = toolBar("callgraphToolBar"); removeToolBar(callgraphToolbar); delete callgraphToolbar; } //END KGraphViewer connect(ui.documents, SIGNAL(currentChanged(int)), this, SLOT(documentChanged())); //BEGIN custom allocators tabifyDockWidget(ui.allocatorDock, ui.dataTreeDock); ui.allocatorView->setModel(m_allocatorModel); int iconSize = style()->pixelMetric(QStyle::PM_SmallIconSize); ui.dockMenuBar->setIconSize(QSize(iconSize, iconSize)); ui.dockMenuBar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); ui.dockMenuBar->setFloatable(false); ui.dockMenuBar->setMovable(false); KConfigGroup cfg = allocatorConfig(); m_allocatorModel->setStringList(cfg.entryMap().values()); connect(m_allocatorModel, SIGNAL(modelReset()), this, SLOT(allocatorsChanged())); connect(m_allocatorModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(allocatorsChanged())); connect(ui.dataTreeView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(dataTreeContextMenuRequested(QPoint))); ui.dataTreeView->setContextMenuPolicy(Qt::CustomContextMenu); connect(ui.allocatorView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(allocatorViewContextMenuRequested(QPoint))); ui.allocatorView->setContextMenuPolicy(Qt::CustomContextMenu); //END custom allocators setupActions(); setupGUI(StandardWindowOptions(Default ^ StatusBar)); statusBar()->hide(); // open page ui.stackedWidget->setCurrentWidget(ui.openPage); } MainWindow::~MainWindow() { while (ui.documents->count()) { closeCurrentFile(); } m_recentFiles->saveEntries(KGlobal::config()->group( QString() )); } void MainWindow::setupActions() { - KAction* openFile = KStandardAction::open(this, SLOT(openFile()), actionCollection()); - KAction* reload = KStandardAction::redisplay(this, SLOT(reloadCurrentFile()), actionCollection()); + QAction* openFile = KStandardAction::open(this, SLOT(openFile()), actionCollection()); + QAction* reload = KStandardAction::redisplay(this, SLOT(reloadCurrentFile()), actionCollection()); actionCollection()->addAction("file_reload", reload); - m_recentFiles = KStandardAction::openRecent(this, SLOT(openFile(KUrl)), actionCollection()); + m_recentFiles = KStandardAction::openRecent(this, SLOT(openFile(QUrl)), actionCollection()); m_recentFiles->loadEntries(KGlobal::config()->group( QString() )); m_close = KStandardAction::close(this, SLOT(closeCurrentFile()), actionCollection()); m_close->setEnabled(false); m_print = KStandardAction::print(this, SLOT(showPrintPreviewDialog()), actionCollection()); actionCollection()->addAction("file_print", m_print); m_print->setEnabled(false); - m_stopParser = new KAction(i18n("Stop Parser"), actionCollection()); - m_stopParser->setIcon(KIcon("process-stop")); + m_stopParser = new QAction(i18n("Stop Parser"), actionCollection()); + m_stopParser->setIcon(QIcon::fromTheme("process-stop")); connect(m_stopParser, SIGNAL(triggered(bool)), this, SLOT(stopParser())); m_stopParser->setEnabled(false); actionCollection()->addAction("file_stopparser", m_stopParser); KStandardAction::quit(qApp, SLOT(closeAllWindows()), actionCollection()); KStandardAction::preferences(this, SLOT(preferences()), actionCollection()); - m_shortenTemplates = new KAction(KIcon("shortentemplates"), i18n("Shorten Templates"), actionCollection()); + m_shortenTemplates = new QAction(QIcon::fromTheme("shortentemplates"), i18n("Shorten Templates"), actionCollection()); m_shortenTemplates->setCheckable(true); m_shortenTemplates->setChecked(Settings::shortenTemplates()); connect(m_shortenTemplates, SIGNAL(toggled(bool)), SLOT(slotShortenTemplates(bool))); actionCollection()->addAction("shorten_templates", m_shortenTemplates); - m_toggleTotal = new KAction(KIcon("office-chart-area"), i18n("Toggle total cost graph"), actionCollection()); + m_toggleTotal = new QAction(QIcon::fromTheme("office-chart-area"), i18n("Toggle total cost graph"), actionCollection()); m_toggleTotal->setCheckable(true); m_toggleTotal->setChecked(true); m_toggleTotal->setEnabled(false); connect(m_toggleTotal, SIGNAL(toggled(bool)), SLOT(showTotalGraph(bool))); actionCollection()->addAction("toggle_total", m_toggleTotal); - m_toggleDetailed = new KAction(KIcon("office-chart-area-stacked"), i18n("Toggle detailed cost graph"), actionCollection()); + m_toggleDetailed = new QAction(QIcon::fromTheme("office-chart-area-stacked"), i18n("Toggle detailed cost graph"), actionCollection()); m_toggleDetailed->setCheckable(true); m_toggleDetailed->setChecked(true); m_toggleDetailed->setEnabled(false); connect(m_toggleDetailed, SIGNAL(toggled(bool)), SLOT(showDetailedGraph(bool))); actionCollection()->addAction("toggle_detailed", m_toggleDetailed); // If the toolbar is still there, kgraphviewer is available at runtime. #ifdef HAVE_KGRAPHVIEWER if (toolBar("callgraphToolBar")) { m_zoomIn = KStandardAction::zoomIn(this, SLOT(zoomIn()), actionCollection()); actionCollection()->addAction("zoomIn", m_zoomIn); m_zoomOut = KStandardAction::zoomOut(this, SLOT(zoomOut()), actionCollection()); actionCollection()->addAction("zoomOut", m_zoomOut); - m_focusExpensive = new KAction(KIcon("flag-red"), i18n("Focus most expensive node"), actionCollection()); + m_focusExpensive = new QAction(QIcon::fromTheme("flag-red"), i18n("Focus most expensive node"), actionCollection()); m_toggleDetailed->setEnabled(false); connect(m_focusExpensive, SIGNAL(triggered()), this, SLOT(focusExpensiveGraphNode())); actionCollection()->addAction("focusExpensive", m_focusExpensive); } #endif - m_selectPeak = new KAction(KIcon("flag-red"), i18n("Select peak snapshot"), ui.dataTreeDock); + m_selectPeak = new QAction(QIcon::fromTheme("flag-red"), i18n("Select peak snapshot"), ui.dataTreeDock); m_selectPeak->setEnabled(false); connect(m_selectPeak, SIGNAL(triggered()), this, SLOT(selectPeakSnapshot())); actionCollection()->addAction("selectPeak", m_selectPeak); - KAction* stackNumAction = actionCollection()->addAction("stackNum"); + QAction* stackNumAction = actionCollection()->addAction("stackNum"); stackNumAction->setText(i18n("Stacked diagrams")); QWidget *stackNumWidget = new QWidget; QHBoxLayout* stackNumLayout = new QHBoxLayout; stackNumLayout->addWidget(new QLabel(i18n("Stacked diagrams:"))); m_box->setMinimum(0); m_box->setMaximum(50); m_box->setValue(10); connect(m_box, SIGNAL(valueChanged(int)), this, SLOT(setStackNum(int))); stackNumLayout->addWidget(m_box); stackNumWidget->setLayout(stackNumLayout); - stackNumAction->setDefaultWidget(stackNumWidget); + // FIXME: Port to KF5 + //stackNumAction->setDefaultWidget(stackNumWidget); //BEGIN custom allocators - m_newAllocator = new KAction(KIcon("list-add"), i18n("add"), ui.allocatorDock); + m_newAllocator = new QAction(QIcon::fromTheme("list-add"), i18n("add"), ui.allocatorDock); m_newAllocator->setToolTip(i18n("add custom allocator")); connect(m_newAllocator, SIGNAL(triggered()), this, SLOT(slotNewAllocator())); ui.dockMenuBar->addAction(m_newAllocator); - m_removeAllocator = new KAction(KIcon("list-remove"), i18n("remove"), + m_removeAllocator = new QAction(QIcon::fromTheme("list-remove"), i18n("remove"), ui.allocatorDock); m_newAllocator->setToolTip(i18n("remove selected allocator")); connect(m_removeAllocator, SIGNAL(triggered()), this, SLOT(slotRemoveAllocator())); connect(ui.allocatorView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SLOT(allocatorSelectionChanged())); m_removeAllocator->setEnabled(false); ui.dockMenuBar->addAction(m_removeAllocator); - m_markCustomAllocator = new KAction(i18n("mark as custom allocator"), ui.allocatorDock); + m_markCustomAllocator = new QAction(i18n("mark as custom allocator"), ui.allocatorDock); connect(m_markCustomAllocator, SIGNAL(triggered()), this, SLOT(slotMarkCustomAllocator()), Qt::QueuedConnection); //END custom allocators //BEGIN hiding functions - m_hideFunction = new KAction(i18n("hide function"), this); + m_hideFunction = new QAction(i18n("hide function"), this); connect(m_hideFunction, SIGNAL(triggered()), this, SLOT(slotHideFunction())); - m_hideOtherFunctions = new KAction(i18n("hide other functions"), this); + m_hideOtherFunctions = new QAction(i18n("hide other functions"), this); connect(m_hideOtherFunctions, SIGNAL(triggered()), this, SLOT(slotHideOtherFunctions())); //END hiding functions //dock actions actionCollection()->addAction("toggleDataTree", ui.dataTreeDock->toggleViewAction()); actionCollection()->addAction("toggleAllocators", ui.allocatorDock->toggleViewAction()); //open page actions ui.openFile->setDefaultAction(openFile); ui.openFile->setText(i18n("Open Massif Data File")); ui.openFile->setIconSize(QSize(48, 48)); } void MainWindow::preferences() { if (ConfigDialog::isShown()) { return; } ConfigDialog* dlg = new ConfigDialog(this); connect(dlg, SIGNAL(settingsChanged(QString)), this, SLOT(settingsChanged())); dlg->show(); } void MainWindow::settingsChanged() { if (Settings::self()->shortenTemplates() != m_shortenTemplates->isChecked()) { m_shortenTemplates->setChecked(Settings::self()->shortenTemplates()); } Settings::self()->writeConfig(); if (m_currentDocument) { m_currentDocument->updateHeader(); m_currentDocument->updatePeaks(); } ui.dataTreeView->viewport()->update(); } void MainWindow::openFile() { - const KUrl::List files = KFileDialog::getOpenUrls(KUrl("kfiledialog:///massif-visualizer"), + const QList files = KFileDialog::getOpenUrls(QUrl("kfiledialog:///massif-visualizer"), QString("application/x-valgrind-massif"), this, i18n("Open Massif Output File")); - foreach (const KUrl& file, files) { + foreach (const QUrl& file, files) { openFile(file); } } void MainWindow::reloadCurrentFile() { if (m_currentDocument->file().isValid()) { - openFile(KUrl(m_currentDocument->file())); + openFile(QUrl(m_currentDocument->file())); } } void MainWindow::stopParser() { Q_ASSERT(m_currentDocument); ParseWorker* parseWorker = m_documentsParseWorkers.take(m_currentDocument); QThread* thread = parseWorker->thread(); parseWorker->stop(); parseWorker->deleteLater(); thread->quit(); thread->wait(); m_stopParser->setEnabled(!m_documentsParseWorkers.isEmpty()); } -void MainWindow::openFile(const KUrl& file) +void MainWindow::openFile(const QUrl &file) { Q_ASSERT(file.isValid()); // Is file already opened ? int indexToInsert = -1; for (int i = 0; i < ui.documents->count(); ++i) { if (qobject_cast(ui.documents->widget(i))->file() == file) { indexToInsert = i; break; } } DocumentWidget* documentWidget = new DocumentWidget(this); - documentWidget->setLoadingMessage(i18n("loading file %1...", file.pathOrUrl())); + documentWidget->setLoadingMessage(i18n("loading file %1...", file.toString())); m_changingSelections.insert(documentWidget, false); // Create dedicated thread for this document. ParseWorker* parseWorker = new ParseWorker; QThread* thread = new QThread(this); thread->start(); parseWorker->moveToThread(thread); // Register thread in the hash map. m_documentsParseWorkers.insert(documentWidget, parseWorker); if (indexToInsert != -1) { // Remove existing instance of the file. ui.documents->setCurrentIndex(indexToInsert); closeCurrentFile(); // Insert the new tab at the correct position. ui.documents->insertTab(indexToInsert, documentWidget, file.fileName()); ui.documents->setCurrentIndex(indexToInsert); } else { ui.documents->addTab(documentWidget, file.fileName()); } - connect(parseWorker, SIGNAL(finished(KUrl, Massif::FileData*)), - documentWidget, SLOT(parserFinished(KUrl, Massif::FileData*))); + connect(parseWorker, SIGNAL(finished(QUrl, Massif::FileData*)), + documentWidget, SLOT(parserFinished(QUrl, Massif::FileData*))); connect(parseWorker, SIGNAL(error(QString, QString)), documentWidget, SLOT(showError(QString, QString))); connect(parseWorker, SIGNAL(progressRange(int, int)), documentWidget, SLOT(setRange(int,int))); connect(parseWorker, SIGNAL(progress(int)), documentWidget, SLOT(setProgress(int))); connect(documentWidget, SIGNAL(loadingFinished()), this, SLOT(documentChanged())); parseWorker->parse(file, m_allocatorModel->stringList()); m_stopParser->setEnabled(true); m_recentFiles->addUrl(file); ui.stackedWidget->setCurrentWidget(ui.displayPage); } void MainWindow::treeSelectionChanged(const QModelIndex& now, const QModelIndex& before) { if (!m_currentDocument || currentChangingSelections()) { return; } if (now == before) { return; } setCurrentChangingSelections(true); const QPair< TreeLeafItem*, SnapshotItem* >& item = m_currentDocument->dataTreeModel()->itemForIndex( m_currentDocument->dataTreeFilterModel()->mapToSource(now) ); if (now.parent().isValid()) { m_currentDocument->detailedCostModel()->setSelection(m_currentDocument->detailedCostModel()->indexForItem(item)); m_currentDocument->totalCostModel()->setSelection(QModelIndex()); } else { m_currentDocument->totalCostModel()->setSelection(m_currentDocument->totalCostModel()->indexForItem(item)); m_currentDocument->detailedCostModel()->setSelection(QModelIndex()); } m_currentDocument->chart()->update(); #ifdef HAVE_KGRAPHVIEWER if (m_currentDocument->graphViewer()) { m_currentDocument->showDotGraph(item); } #endif setCurrentChangingSelections(false); } void MainWindow::detailedItemClicked(const QModelIndex& idx) { if (!m_currentDocument || currentChangingSelections()) { return; } setCurrentChangingSelections(true); m_currentDocument->detailedCostModel()->setSelection(idx); m_currentDocument->totalCostModel()->setSelection(QModelIndex()); // hack: the ToolTip will only be queried by KDChart and that one uses the // left index, but we want it to query the right one const QModelIndex _idx = m_currentDocument->detailedCostModel()->index(idx.row() + 1, idx.column(), idx.parent()); ui.dataTreeView->selectionModel()->clearSelection(); QPair< TreeLeafItem*, SnapshotItem* > item = m_currentDocument->detailedCostModel()->itemForIndex(_idx); const QModelIndex& newIndex = m_currentDocument->dataTreeFilterModel()->mapFromSource( m_currentDocument->dataTreeModel()->indexForItem(item) ); ui.dataTreeView->selectionModel()->setCurrentIndex(newIndex, QItemSelectionModel::Select | QItemSelectionModel::Rows); ui.dataTreeView->scrollTo(ui.dataTreeView->selectionModel()->currentIndex()); m_currentDocument->chart()->update(); #ifdef HAVE_KGRAPHVIEWER if (m_currentDocument->graphViewer()) { m_currentDocument->showDotGraph(item); } #endif setCurrentChangingSelections(false); } void MainWindow::totalItemClicked(const QModelIndex& idx_) { if (!m_currentDocument || currentChangingSelections()) { return; } setCurrentChangingSelections(true); QModelIndex idx = idx_.model()->index(idx_.row() + 1, idx_.column(), idx_.parent()); m_currentDocument->detailedCostModel()->setSelection(QModelIndex()); m_currentDocument->totalCostModel()->setSelection(idx); QPair< TreeLeafItem*, SnapshotItem* > item = m_currentDocument->totalCostModel()->itemForIndex(idx); ui.dataTreeView->selectionModel()->clearSelection(); const QModelIndex& newIndex = m_currentDocument->dataTreeFilterModel()->mapFromSource( m_currentDocument->dataTreeModel()->indexForItem(item) ); ui.dataTreeView->selectionModel()->setCurrentIndex(newIndex, QItemSelectionModel::Select | QItemSelectionModel::Rows); ui.dataTreeView->scrollTo(ui.dataTreeView->selectionModel()->currentIndex()); m_currentDocument->chart()->update(); setCurrentChangingSelections(false); } void MainWindow::closeCurrentFile() { stopParser(); // Tab is now removed int tabToCloseIndex = ui.documents->currentIndex(); m_changingSelections.remove(m_currentDocument); ui.documents->widget(tabToCloseIndex)->deleteLater(); ui.documents->removeTab(tabToCloseIndex); } void MainWindow::showDetailedGraph(bool show) { if (!m_currentDocument) { return; } m_currentDocument->detailedDiagram()->setHidden(!show); m_toggleDetailed->setChecked(show); m_currentDocument->chart()->update(); } void MainWindow::showTotalGraph(bool show) { if (!m_currentDocument) { return; } m_currentDocument->totalDiagram()->setHidden(!show); m_toggleTotal->setChecked(show); m_currentDocument->chart()->update(); } #ifdef HAVE_KGRAPHVIEWER void MainWindow::zoomIn() { Q_ASSERT(m_currentDocument->graphViewer()); m_currentDocument->graphViewer()->zoomIn(); } void MainWindow::zoomOut() { Q_ASSERT(m_currentDocument->graphViewer()); m_currentDocument->graphViewer()->zoomOut(); } void MainWindow::focusExpensiveGraphNode() { Q_ASSERT(m_currentDocument); m_currentDocument->focusExpensiveGraphNode(); } #endif void MainWindow::selectPeakSnapshot() { Q_ASSERT(m_currentDocument); ui.dataTreeView->selectionModel()->clearSelection(); ui.dataTreeView->selectionModel()->setCurrentIndex( m_currentDocument->dataTreeFilterModel()->mapFromSource( m_currentDocument->dataTreeModel()->indexForSnapshot(m_currentDocument->data()->peak())), QItemSelectionModel::Select | QItemSelectionModel::Rows ); } void MainWindow::setStackNum(int num) { if (!m_currentDocument || !m_currentDocument->isLoaded()) { return; } m_currentDocument->detailedCostModel()->setMaximumDatasetCount(num); m_currentDocument->updatePeaks(); } void MainWindow::allocatorsChanged() { KConfigGroup cfg = allocatorConfig(); cfg.deleteGroup(); int i = 0; foreach(const QString& allocator, m_allocatorModel->stringList()) { if (allocator.isEmpty()) { m_allocatorModel->removeRow(i); continue; } cfg.writeEntry(QString::number(i++), allocator); } cfg.sync(); if (m_currentDocument) { reloadCurrentFile(); } } void MainWindow::allocatorSelectionChanged() { m_removeAllocator->setEnabled(ui.allocatorView->selectionModel()->hasSelection()); } void MainWindow::slotNewAllocator() { QString allocator = QInputDialog::getText(this, i18n("Add Custom Allocator"), i18n("allocator:")); if (allocator.isEmpty()) { return; } if (!m_allocatorModel->stringList().contains(allocator)) { m_allocatorModel->setStringList(m_allocatorModel->stringList() << allocator); } } void MainWindow::slotRemoveAllocator() { Q_ASSERT(ui.allocatorView->selectionModel()->hasSelection()); foreach(const QModelIndex& idx, ui.allocatorView->selectionModel()->selectedRows()) { m_allocatorModel->removeRow(idx.row(), idx.parent()); } allocatorsChanged(); } void MainWindow::slotMarkCustomAllocator() { const QString allocator = m_markCustomAllocator->data().toString(); Q_ASSERT(!allocator.isEmpty()); if (!m_allocatorModel->stringList().contains(allocator)) { m_allocatorModel->setStringList(m_allocatorModel->stringList() << allocator); } } void MainWindow::allocatorViewContextMenuRequested(const QPoint& pos) { const QModelIndex idx = ui.allocatorView->indexAt(pos); QMenu menu; menu.addAction(m_newAllocator); if (idx.isValid()) { menu.addAction(m_removeAllocator); } menu.exec(ui.allocatorView->mapToGlobal(pos)); } void MainWindow::dataTreeContextMenuRequested(const QPoint& pos) { const QModelIndex idx = m_currentDocument->dataTreeFilterModel()->mapToSource( ui.dataTreeView->indexAt(pos)); if (!idx.isValid()) { return; } if (!idx.parent().isValid()) { // snapshot item return; } QMenu menu; TreeLeafItem* item = m_currentDocument->dataTreeModel()->itemForIndex(idx).first; Q_ASSERT(item); prepareActions(&menu, item); menu.exec(ui.dataTreeView->mapToGlobal(pos)); } void MainWindow::chartContextMenuRequested(const QPoint& pos) { const QPoint dPos = m_currentDocument->detailedDiagram()->mapFromGlobal(m_currentDocument->chart()->mapToGlobal(pos)); const QModelIndex idx = m_currentDocument->detailedDiagram()->indexAt(dPos); if (!idx.isValid()) { return; } // hack: the ToolTip will only be queried by KDChart and that one uses the // left index, but we want it to query the right one const QModelIndex _idx = m_currentDocument->detailedCostModel()->index(idx.row() + 1, idx.column(), idx.parent()); QPair< TreeLeafItem*, SnapshotItem* > item = m_currentDocument->detailedCostModel()->itemForIndex(_idx); if (!item.first) { return; } QMenu menu; menu.addAction(m_markCustomAllocator); prepareActions(&menu, item.first); menu.exec(m_currentDocument->detailedDiagram()->mapToGlobal(dPos)); } void MainWindow::prepareActions(QMenu* menu, TreeLeafItem* item) { QString func = functionInLabel(item->label()); if (func.length() > 40) { func.resize(40); func.append("..."); } menu->setTitle(func); m_markCustomAllocator->setData(item->label()); menu->addAction(m_markCustomAllocator); m_hideFunction->setData(QVariant::fromValue(item)); menu->addAction(m_hideFunction); m_hideOtherFunctions->setData(QVariant::fromValue(item)); menu->addAction(m_hideOtherFunctions); } void MainWindow::slotHideFunction() { m_currentDocument->detailedCostModel()->hideFunction(m_hideFunction->data().value()); } void MainWindow::slotHideOtherFunctions() { m_currentDocument->detailedCostModel()->hideOtherFunctions(m_hideOtherFunctions->data().value()); } void MainWindow::slotShortenTemplates(bool shorten) { if (shorten == Settings::self()->shortenTemplates()) { return; } Settings::self()->setShortenTemplates(shorten); settingsChanged(); } void MainWindow::showPrintPreviewDialog() { Q_ASSERT(m_currentDocument); QPrinter printer; QPrintPreviewDialog *ppd = new QPrintPreviewDialog(&printer, this); ppd->setAttribute(Qt::WA_DeleteOnClose); connect(ppd, SIGNAL(paintRequested(QPrinter*)), SLOT(printFile(QPrinter*))); ppd->setWindowTitle(i18n("Massif Chart Print Preview")); ppd->resize(800, 600); ppd->exec(); } void MainWindow::printFile(QPrinter *printer) { QPainter painter; painter.begin(printer); m_currentDocument->chart()->paint(&painter, printer->pageRect()); painter.end(); } void MainWindow::updateWindowTitle() { if (m_currentDocument && m_currentDocument->isLoaded()) { setWindowTitle(i18n("Massif Visualizer - evaluation of %1 (%2)", m_currentDocument->data()->cmd(), m_currentDocument->file().fileName())); } else { setWindowTitle(i18n("Massif Visualizer")); } } void MainWindow::documentChanged() { if (m_currentDocument) { if (m_currentDocument->totalDiagram()) { disconnect(m_currentDocument->totalDiagram(), SIGNAL(clicked(QModelIndex)), this, SLOT(totalItemClicked(QModelIndex))); } if (m_currentDocument->detailedDiagram()) { disconnect(m_currentDocument->detailedDiagram(), SIGNAL(clicked(QModelIndex)), this, SLOT(detailedItemClicked(QModelIndex))); } if (m_currentDocument->chart()) { disconnect(m_currentDocument->chart(), SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(chartContextMenuRequested(QPoint))); } disconnect(m_currentDocument, SIGNAL(tabChanged(int)), this, SLOT(documentTabChanged(int))); disconnect(ui.filterDataTree, SIGNAL(textChanged(QString)), m_currentDocument->dataTreeFilterModel(), SLOT(setFilter(QString))); disconnect(ui.dataTreeView->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(treeSelectionChanged(QModelIndex,QModelIndex))); } m_currentDocument = qobject_cast(ui.documents->currentWidget()); updateWindowTitle(); #ifdef HAVE_KGRAPHVIEWER if (toolBar("callgraphToolBar")) { m_zoomIn->setEnabled(m_currentDocument && m_currentDocument->graphViewer()); m_zoomOut->setEnabled(m_currentDocument && m_currentDocument->graphViewer()); m_focusExpensive->setEnabled(m_currentDocument && m_currentDocument->graphViewer()); } #endif m_print->setEnabled(m_currentDocument && m_currentDocument->isLoaded()); m_selectPeak->setEnabled(m_currentDocument && m_currentDocument->data()); actionCollection()->action("file_reload")->setEnabled(m_currentDocument); m_toggleDetailed->setEnabled(m_currentDocument && m_currentDocument->detailedDiagram()); m_toggleTotal->setEnabled(m_currentDocument && m_currentDocument->totalDiagram()); m_close->setEnabled(m_currentDocument); if (!m_currentDocument) { ui.dataTreeView->setModel(0); ui.stackedWidget->setCurrentWidget(ui.openPage); return; } ui.dataTreeView->setModel(m_currentDocument->dataTreeFilterModel()); if (m_currentDocument->totalDiagram()) { connect(m_currentDocument->totalDiagram(), SIGNAL(clicked(QModelIndex)), this, SLOT(totalItemClicked(QModelIndex))); } if (m_currentDocument->detailedDiagram()) { connect(m_currentDocument->detailedDiagram(), SIGNAL(clicked(QModelIndex)), this, SLOT(detailedItemClicked(QModelIndex))); } if (m_currentDocument->detailedCostModel()) { m_box->setValue(m_currentDocument->detailedCostModel()->maximumDatasetCount()); } if (m_currentDocument->chart()) { connect(m_currentDocument->chart(), SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(chartContextMenuRequested(QPoint))); } connect(ui.filterDataTree, SIGNAL(textChanged(QString)), m_currentDocument->dataTreeFilterModel(), SLOT(setFilter(QString))); connect(ui.dataTreeView->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(treeSelectionChanged(QModelIndex,QModelIndex))); connect(m_currentDocument, SIGNAL(tabChanged(int)), this, SLOT(documentTabChanged(int))); if (m_toggleDetailed->isEnabled()) { m_toggleDetailed->setChecked(!m_currentDocument->detailedDiagram()->isHidden()); } if (m_toggleTotal->isEnabled()) { m_toggleTotal->setChecked(!m_currentDocument->totalDiagram()->isHidden()); } #ifdef HAVE_KGRAPHVIEWER documentTabChanged(m_currentDocument->currentIndex()); #else documentTabChanged(0); #endif } bool MainWindow::currentChangingSelections() const { return m_changingSelections[m_currentDocument]; } void MainWindow::setCurrentChangingSelections(bool changingSelections) { m_changingSelections[m_currentDocument] = changingSelections; } void MainWindow::documentTabChanged(int index) { Q_ASSERT(m_currentDocument); toolBar("chartToolBar")->setVisible(index == 0); foreach(QAction* action, toolBar("chartToolBar")->actions()) { action->setEnabled(m_currentDocument->data() && index == 0); } toolBar("callgraphToolBar")->setVisible(index == 1); foreach(QAction* action, toolBar("callgraphToolBar")->actions()) { action->setEnabled(m_currentDocument->data() && index == 1); } } #include "mainwindow.moc" diff --git a/app/mainwindow.h b/app/mainwindow.h index d2204e5..69cda04 100644 --- a/app/mainwindow.h +++ b/app/mainwindow.h @@ -1,194 +1,194 @@ /* This file is part of Massif Visualizer Copyright 2010 Milian Wolff Copyright 2013 Arnold Dumas 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) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef MASSIF_MAINWINDOW_H #define MASSIF_MAINWINDOW_H #include #include #include "ui_mainwindow.h" #include "documentwidget.h" class QSpinBox; class QStringListModel; namespace KDChart { class Chart; class HeaderFooter; class Plotter; class CartesianAxis; class Legend; class BarDiagram; } -class KAction; +class QAction; class KRecentFilesAction; #ifdef HAVE_KGRAPHVIEWER namespace KGraphViewer { class KGraphViewerInterface; } #endif namespace Massif { class ParseWorker; class FileData; class DetailedCostModel; class TotalCostModel; class FilteredDataTreeModel; class SnapshotItem; class TreeLeafItem; class MainWindow : public KParts::MainWindow { Q_OBJECT public: MainWindow(QWidget* parent = 0, Qt::WindowFlags f = 0); virtual ~MainWindow(); void setupActions(); public slots: /** * Open a dialog to pick a massif output file(s) to display. */ void openFile(); /** * Opens @p file as massif output file and visualize it. */ - void openFile(const KUrl& file); + void openFile(const QUrl& file); /** * reload currently opened file */ void reloadCurrentFile(); /** * Close currently opened file. */ void closeCurrentFile(); /** * Depending on @p show, the total cost graph is shown or hidden. */ void showTotalGraph(bool show); /** * Depending on @p show, the detailed cost graph is shown or hidden. */ void showDetailedGraph(bool show); /** * Show the print preview dialog. */ void showPrintPreviewDialog(); /** * Create a preview of the printed file in the @p printer. */ void printFile(QPrinter *printer); private slots: void preferences(); void settingsChanged(); void treeSelectionChanged(const QModelIndex& now, const QModelIndex& before); void detailedItemClicked(const QModelIndex& item); void totalItemClicked(const QModelIndex& item); void selectPeakSnapshot(); void setStackNum(int num); void documentChanged(); #ifdef HAVE_KGRAPHVIEWER void zoomIn(); void zoomOut(); void focusExpensiveGraphNode(); #endif void allocatorsChanged(); void allocatorSelectionChanged(); void dataTreeContextMenuRequested(const QPoint &pos); void slotNewAllocator(); void slotRemoveAllocator(); /// operates on data of @c m_markCustomAllocator void slotMarkCustomAllocator(); void allocatorViewContextMenuRequested(const QPoint &pos); void chartContextMenuRequested(const QPoint &pos); void slotHideFunction(); void slotHideOtherFunctions(); void slotShortenTemplates(bool); void stopParser(); void documentTabChanged(int index); private: void updateDetailedPeaks(); void updateWindowTitle(); void prepareActions(QMenu* menu, TreeLeafItem* item); // Helper Ui::MainWindow ui; - KAction* m_toggleTotal; - KAction* m_toggleDetailed; - KAction* m_selectPeak; + QAction* m_toggleTotal; + QAction* m_toggleDetailed; + QAction* m_selectPeak; KRecentFilesAction* m_recentFiles; QSpinBox* m_box; QHash m_changingSelections; bool currentChangingSelections() const; void setCurrentChangingSelections(bool changingSelections); - KAction* m_zoomIn; - KAction* m_zoomOut; - KAction* m_focusExpensive; - KAction* m_close; - KAction* m_print; - KAction* m_stopParser; + QAction* m_zoomIn; + QAction* m_zoomOut; + QAction* m_focusExpensive; + QAction* m_close; + QAction* m_print; + QAction* m_stopParser; QStringListModel* m_allocatorModel; - KAction* m_newAllocator; - KAction* m_removeAllocator; - KAction* m_markCustomAllocator; + QAction* m_newAllocator; + QAction* m_removeAllocator; + QAction* m_markCustomAllocator; - KAction* m_hideFunction; - KAction* m_hideOtherFunctions; + QAction* m_hideFunction; + QAction* m_hideOtherFunctions; - KAction* m_shortenTemplates; + QAction* m_shortenTemplates; DocumentWidget* m_currentDocument; QHash m_documentsParseWorkers; }; } #endif // MASSIF_MAINWINDOW_H diff --git a/kdchart/src/CMakeLists.txt b/kdchart/src/CMakeLists.txt index f6c6ec0..6035814 100644 --- a/kdchart/src/CMakeLists.txt +++ b/kdchart/src/CMakeLists.txt @@ -1,126 +1,125 @@ include_directories( - ${KDE4_INCLUDES} ${CMAKE_CURRENT_SOURCE_DIR}/../include ${CMAKE_CURRENT_SOURCE_DIR}/../kdablibfakes/include ${CMAKE_CURRENT_SOURCE_DIR}/KDChart ${CMAKE_CURRENT_SOURCE_DIR}/KDChart/Cartesian ${CMAKE_CURRENT_SOURCE_DIR}/KDChart/Cartesian/DiagramFlavors ${CMAKE_CURRENT_SOURCE_DIR}/KDChart/Polar ${CMAKE_CURRENT_SOURCE_DIR}/KDChart/Ternary ) ADD_DEFINITIONS(-DKDCHART_BUILD_KDCHART_LIB) ########### next target ############### set(kdchart_LIB_SRCS KDChart/Cartesian/DiagramFlavors/KDChartNormalBarDiagram_p.cpp KDChart/Cartesian/DiagramFlavors/KDChartNormalLineDiagram_p.cpp KDChart/Cartesian/DiagramFlavors/KDChartNormalLyingBarDiagram_p.cpp KDChart/Cartesian/DiagramFlavors/KDChartNormalPlotter_p.cpp KDChart/Cartesian/DiagramFlavors/KDChartPercentBarDiagram_p.cpp KDChart/Cartesian/DiagramFlavors/KDChartPercentLineDiagram_p.cpp KDChart/Cartesian/DiagramFlavors/KDChartPercentLyingBarDiagram_p.cpp KDChart/Cartesian/DiagramFlavors/KDChartPercentPlotter_p.cpp KDChart/Cartesian/DiagramFlavors/KDChartStackedPlotter_p.cpp KDChart/Cartesian/DiagramFlavors/KDChartStackedBarDiagram_p.cpp KDChart/Cartesian/DiagramFlavors/KDChartStackedLineDiagram_p.cpp KDChart/Cartesian/DiagramFlavors/KDChartStackedLyingBarDiagram_p.cpp KDChart/Cartesian/KDChartAbstractCartesianDiagram.cpp KDChart/Cartesian/KDChartBarAttributes.cpp KDChart/Cartesian/KDChartBarDiagram.cpp KDChart/Cartesian/KDChartBarDiagram_p.cpp KDChart/Cartesian/KDChartCartesianAxis.cpp KDChart/Cartesian/KDChartCartesianCoordinatePlane.cpp KDChart/Cartesian/KDChartCartesianDiagramDataCompressor_p.cpp KDChart/Cartesian/KDChartCartesianGrid.cpp KDChart/Cartesian/KDChartLeveyJenningsAxis.cpp KDChart/Cartesian/KDChartLeveyJenningsCoordinatePlane.cpp KDChart/Cartesian/KDChartLeveyJenningsDiagram.cpp KDChart/Cartesian/KDChartLeveyJenningsDiagram_p.cpp KDChart/Cartesian/KDChartLeveyJenningsGridAttributes.cpp KDChart/Cartesian/KDChartLeveyJenningsGrid.cpp KDChart/Cartesian/KDChartLineDiagram.cpp KDChart/Cartesian/KDChartLineDiagram_p.cpp KDChart/Cartesian/KDChartPlotter.cpp KDChart/Cartesian/KDChartPlotterDiagramCompressor.cpp KDChart/Cartesian/KDChartPlotter_p.cpp KDChart/Cartesian/KDChartStockBarAttributes.cpp KDChart/Cartesian/KDChartStockDiagram.cpp KDChart/Cartesian/KDChartStockDiagram_p.cpp KDChart/Cartesian/KDChartThreeDBarAttributes.cpp KDChart/Cartesian/PaintingHelpers_p.cpp KDChart/ChartGraphicsItem.cpp KDChart/KDChartAbstractAreaBase.cpp KDChart/KDChartAbstractArea.cpp KDChart/KDChartAbstractAreaWidget.cpp KDChart/KDChartAbstractAxis.cpp KDChart/KDChartAbstractCoordinatePlane.cpp KDChart/KDChartAbstractDiagram.cpp KDChart/KDChartAbstractDiagram_p.cpp KDChart/KDChartAbstractGrid.cpp KDChart/KDChartAbstractProxyModel.cpp KDChart/KDChartAbstractThreeDAttributes.cpp KDChart/KDChartAttributesModel.cpp KDChart/KDChartBackgroundAttributes.cpp KDChart/KDChartChart.cpp KDChart/KDChartDatasetProxyModel.cpp KDChart/KDChartDatasetSelector.cpp KDChart/KDChartDataValueAttributes.cpp KDChart/KDChartDiagramObserver.cpp KDChart/KDChartFrameAttributes.cpp KDChart/KDChartGridAttributes.cpp KDChart/KDChartHeaderFooter.cpp KDChart/KDChartLayoutItems.cpp KDChart/KDChartLegend.cpp KDChart/KDChartLineAttributes.cpp KDChart/KDChartMarkerAttributes.cpp KDChart/KDChartMeasure.cpp KDChart/KDChartModelDataCache_p.cpp KDChart/KDChartPaintContext.cpp KDChart/KDChartPalette.cpp KDChart/KDChartPosition.cpp KDChart/KDChartPrintingParameters.cpp KDChart/KDChartRelativePosition.cpp KDChart/KDChartRulerAttributes.cpp KDChart/KDChartSignalCompressor.cpp KDChart/KDChartTextArea.cpp KDChart/KDChartTextAttributes.cpp KDChart/KDChartTextLabelCache.cpp KDChart/KDChartThreeDLineAttributes.cpp KDChart/KDChartValueTrackerAttributes.cpp KDChart/KDChartWidget.cpp KDChart/KDTextDocument.cpp KDChart/Polar/KDChartAbstractPieDiagram.cpp KDChart/Polar/KDChartAbstractPolarDiagram.cpp KDChart/Polar/KDChartPieAttributes.cpp KDChart/Polar/KDChartPieDiagram.cpp KDChart/Polar/KDChartPolarCoordinatePlane.cpp KDChart/Polar/KDChartPolarDiagram.cpp KDChart/Polar/KDChartPolarGrid.cpp KDChart/Polar/KDChartRadarCoordinatePlane.cpp KDChart/Polar/KDChartRadarDiagram.cpp KDChart/Polar/KDChartRadarGrid.cpp KDChart/Polar/KDChartRingDiagram.cpp KDChart/Polar/KDChartThreeDPieAttributes.cpp KDChart/ReverseMapper.cpp KDChart/Ternary/KDChartAbstractTernaryDiagram.cpp KDChart/Ternary/KDChartTernaryAxis.cpp KDChart/Ternary/KDChartTernaryCoordinatePlane.cpp KDChart/Ternary/KDChartTernaryGrid.cpp KDChart/Ternary/KDChartTernaryLineDiagram.cpp KDChart/Ternary/KDChartTernaryPointDiagram.cpp KDChart/Ternary/TernaryConstants.cpp KDChart/Ternary/TernaryPoint.cpp ) -qt4_wrap_ui(kdchart_LIB_SRCS +qt5_wrap_ui(kdchart_LIB_SRCS KDChart/KDChartDatasetSelector.ui ) qt_wrap_cpp(mv-kdchart kdchart_LIB_SRCS KDChart/KDChartEnums.h) -kde4_add_library(mv-kdchart STATIC ${kdchart_LIB_SRCS}) +add_library(mv-kdchart STATIC ${kdchart_LIB_SRCS}) #target_link_libraries(kdchart ${QT_QT3SUPPORT_LIBRARY} ${QT_QTXML_LIBRARY} ${QT_QTGUI_LIBRARY} ${QT_QTCORE_LIBRARY} ${ZLIB_LIBRARY} ) target_link_libraries(mv-kdchart ${QT_QTSVG_LIBRARY} ${QT_QTXML_LIBRARY} ${QT_QTGUI_LIBRARY} ${QT_QTCORE_LIBRARY} ${ZLIB_LIBRARY} ) diff --git a/massifdata/CMakeLists.txt b/massifdata/CMakeLists.txt index ecfd73f..d1b0678 100644 --- a/massifdata/CMakeLists.txt +++ b/massifdata/CMakeLists.txt @@ -1,22 +1,26 @@ include_directories( ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ) set(massifdata_SRCS filedata.cpp snapshotitem.cpp treeleafitem.cpp parser.cpp parserprivate.cpp parseworker.cpp util.cpp ) -kde4_add_library(mv-massifdata ${massifdata_SRCS}) +add_library(mv-massifdata ${massifdata_SRCS}) target_link_libraries(mv-massifdata - ${QT_QTCORE_LIBRARY} + KF5::Archive + KF5::KIOCore + KF5::I18n + KF5::CoreAddons + Qt5::Core # required for Qt::escape() in QTextDocument - ${QT_QTGUI_LIBRARY} + Qt5::Gui ) diff --git a/massifdata/parserprivate.cpp b/massifdata/parserprivate.cpp index a2d535c..f02ab3d 100644 --- a/massifdata/parserprivate.cpp +++ b/massifdata/parserprivate.cpp @@ -1,432 +1,432 @@ /* This file is part of Massif Visualizer Copyright 2010 Milian Wolff This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #include "parserprivate.h" #include "filedata.h" #include "snapshotitem.h" #include "treeleafitem.h" #include "util.h" #include "parser.h" #include #include using namespace Massif; #define VALIDATE(x) if (!(x)) { m_error = Invalid; return; } #define VALIDATE_RETURN(x, y) if (!(x)) { m_error = Invalid; return y; } ParserPrivate::ParserPrivate(Parser* parser, QIODevice* file, FileData* data, const QStringList& customAllocators, QAtomicInt* shouldStop) : m_parser(parser) , m_file(file) , m_data(data) , m_nextLine(FileDesc) , m_currentLine(0) , m_error(NoError) , m_snapshot(0) , m_parentItem(0) , m_hadCustomAllocators(false) , m_expectedSnapshots(100) { foreach(const QString& allocator, customAllocators) { m_allocators << QRegExp(allocator, Qt::CaseSensitive, QRegExp::Wildcard); } QByteArray line; while (!file->atEnd()) { - if (shouldStop && *shouldStop) { + if (shouldStop && shouldStop->load()) { m_error = Stopped; return; } if (file->size()) { // use pos to determine progress when reading the file, won't work for compressed files parser->setProgress(static_cast(double(file->pos() * 100) / file->size())); } line = m_file->readLine(); // remove trailing \n line.chop(1); switch (m_nextLine) { case FileDesc: parseFileDesc(line); break; case FileCmd: parseFileCmd(line); break; case FileTimeUnit: parseFileTimeUnit(line); break; case Snapshot: parseSnapshot(line); break; case SnapshotHeapTree: parseSnapshotHeapTree(line); break; case SnapshotMemHeap: parseSnapshotMemHeap(line); break; case SnapshotMemHeapExtra: parseSnapshotMemHeapExtra(line); break; case SnapshotTime: parseSnapshotTime(line); break; case SnapshotMemStacks: parseSnapshotMemStacks(line); break; case HeapTreeLeaf: parseHeapTreeLeaf(line); break; } if (m_error != NoError) { qWarning() << "invalid line" << (m_currentLine + 1) << line; m_error = Invalid; m_errorLineString = line; break; } ++m_currentLine; } if (!file->atEnd()) { m_error = Invalid; } } ParserPrivate::~ParserPrivate() { } ParserPrivate::Error ParserPrivate::error() const { return m_error; } int ParserPrivate::errorLine() const { if (m_error == Invalid) { return m_currentLine; } else { return -1; } } QByteArray ParserPrivate::errorLineString() const { return m_errorLineString; } //BEGIN Parser Functions void ParserPrivate::parseFileDesc(const QByteArray& line) { // desc: ... VALIDATE(line.startsWith("desc: ")) m_data->setDescription(line.mid(6)); m_nextLine = FileCmd; if (!m_file->size()) { // for zipped files, parse the desc line for a --max-snapshots parameter // and use that number for the progress bar. read the manual to know that // this might not be a good measure, but better than nothing. QRegExp pattern("--max-snapshots=([0-9]+)", Qt::CaseSensitive, QRegExp::RegExp2); if (pattern.indexIn(m_data->description()) != -1) { m_expectedSnapshots = pattern.cap(1).toInt(); } } } void ParserPrivate::parseFileCmd(const QByteArray& line) { // cmd: ... VALIDATE(line.startsWith("cmd: ")) m_data->setCmd(line.mid(5)); m_nextLine = FileTimeUnit; } void ParserPrivate::parseFileTimeUnit(const QByteArray& line) { // time_unit: ... VALIDATE(line.startsWith("time_unit: ")) m_data->setTimeUnit(line.mid(11)); m_nextLine = Snapshot; } void ParserPrivate::parseSnapshot(const QByteArray& line) { VALIDATE(line == "#-----------") // snapshot=N QByteArray nextLine = m_file->readLine(1024); ++m_currentLine; VALIDATE(nextLine.startsWith("snapshot=")) nextLine.chop(1); QByteArray i(nextLine.mid(9)); bool ok; uint number = i.toUInt(&ok); VALIDATE(ok) nextLine = m_file->readLine(1024); ++m_currentLine; VALIDATE(nextLine == "#-----------\n") m_snapshot = new SnapshotItem; m_data->addSnapshot(m_snapshot); m_snapshot->setNumber(number); m_nextLine = SnapshotTime; if (!m_file->size()) { // see above: progress calculation for compressed files m_parser->setProgress(number * 100 / m_expectedSnapshots); } } void ParserPrivate::parseSnapshotTime(const QByteArray& line) { VALIDATE(line.startsWith("time=")) QByteArray timeStr(line.mid(5)); bool ok; double time = timeStr.toDouble(&ok); VALIDATE(ok) m_snapshot->setTime(time); m_nextLine = SnapshotMemHeap; } void ParserPrivate::parseSnapshotMemHeap(const QByteArray& line) { VALIDATE(line.startsWith("mem_heap_B=")) QByteArray byteStr(line.mid(11)); bool ok; quint64 bytes = byteStr.toULongLong(&ok); VALIDATE(ok) m_snapshot->setMemHeap(bytes); m_nextLine = SnapshotMemHeapExtra; } void ParserPrivate::parseSnapshotMemHeapExtra(const QByteArray& line) { VALIDATE(line.startsWith("mem_heap_extra_B=")) QByteArray byteStr(line.mid(17)); bool ok; quint64 bytes = byteStr.toULongLong(&ok); VALIDATE(ok) m_snapshot->setMemHeapExtra(bytes); m_nextLine = SnapshotMemStacks; } void ParserPrivate::parseSnapshotMemStacks(const QByteArray& line) { VALIDATE(line.startsWith("mem_stacks_B=")) QByteArray byteStr(line.mid(13)); bool ok; quint64 bytes = byteStr.toULongLong(&ok); VALIDATE(ok) m_snapshot->setMemStacks(bytes); m_nextLine = SnapshotHeapTree; } void ParserPrivate::parseSnapshotHeapTree(const QByteArray& line) { VALIDATE(line.startsWith("heap_tree=")) QByteArray value = line.mid(10); if (value == "empty") { m_nextLine = Snapshot; } else if (value == "detailed") { m_nextLine = HeapTreeLeaf; } else if (value == "peak") { m_nextLine = HeapTreeLeaf; m_data->setPeak(m_snapshot); } else { m_error = Invalid; return; } } bool sortLeafsByCost(TreeLeafItem* l, TreeLeafItem* r) { return l->cost() > r->cost(); } void ParserPrivate::parseHeapTreeLeaf(const QByteArray& line) { parseheapTreeLeafInternal(line, 0); m_nextLine = Snapshot; // we need to do some post processing if we had custom allocators: // - sort by cost // - merge "in XYZ places all below threshold" if (m_hadCustomAllocators) { Q_ASSERT(m_snapshot->heapTree()); QVector newChildren = m_snapshot->heapTree()->children(); TreeLeafItem* belowThreshold = 0; uint places = 0; QString oldPlaces; ///TODO: is massif translateable? QRegExp matchBT("in ([0-9]+) places, all below massif's threshold", Qt::CaseSensitive, QRegExp::RegExp2); QVector::iterator it = newChildren.begin(); while(it != newChildren.end()) { TreeLeafItem* child = *it; if (matchBT.indexIn(QString::fromLatin1(child->label())) != -1) { places += matchBT.cap(1).toUInt(); if (belowThreshold) { // merge with previously found node belowThreshold->setCost(belowThreshold->cost() + child->cost()); delete child; it = newChildren.erase(it); continue; } else { belowThreshold = child; oldPlaces = matchBT.cap(1); // no break, see above } } ++it; } if (belowThreshold) { QByteArray label = belowThreshold->label(); label.replace(oldPlaces, QByteArray::number(places)); belowThreshold->setLabel(label); } qSort(newChildren.begin(), newChildren.end(), sortLeafsByCost); m_snapshot->heapTree()->setChildren(newChildren); } m_parentItem = 0; } struct SaveAndRestoreItem { SaveAndRestoreItem(TreeLeafItem** item, TreeLeafItem* val) : m_item(item) { m_oldVal = *m_item; *m_item = val; } ~SaveAndRestoreItem() { *m_item = m_oldVal; } TreeLeafItem** m_item; TreeLeafItem* m_oldVal; }; QByteArray ParserPrivate::getLabel(const QByteArray& original) { QSet::const_iterator it = m_labels.constFind(original); if (it != m_labels.constEnd()) { // reuse known label to leverage implit sharing return *it; } else { m_labels.insert(original); return original; } } bool ParserPrivate::parseheapTreeLeafInternal(const QByteArray& line, int depth) { VALIDATE_RETURN(line.length() > depth + 1 && line.at(depth) == 'n', false) int colonPos = line.indexOf(':', depth); VALIDATE_RETURN(colonPos != -1, false) bool ok; QByteArray tmpStr = line.mid(depth + 1, colonPos - depth - 1); unsigned int children = tmpStr.toUInt(&ok); VALIDATE_RETURN(ok, false) int spacePos = line.indexOf(' ', colonPos + 2); VALIDATE_RETURN(spacePos != -1, false) tmpStr = line.mid(colonPos + 2, spacePos - colonPos - 2); quint64 cost = tmpStr.toULongLong(&ok); VALIDATE_RETURN(ok, false) if (!cost && !children) { // ignore these empty entries return true; } const QByteArray label = getLabel(line.mid(spacePos + 1)); bool isCustomAlloc = false; if (depth > 0 && !m_allocators.isEmpty()) { const QByteArray func = functionInLabel(label); foreach(const QRegExp& allocator, m_allocators) { if (allocator.pattern().contains('*')) { if (allocator.indexIn(func) != -1) { isCustomAlloc = true; break; } } else if (func.contains(allocator.pattern().toLatin1())) { isCustomAlloc = true; break; } } } TreeLeafItem* newParent = 0; if (!isCustomAlloc) { TreeLeafItem* leaf = new TreeLeafItem; leaf->setCost(cost); leaf->setLabel(label); if (!depth) { m_snapshot->setHeapTree(leaf); } else { Q_ASSERT(m_parentItem); m_parentItem->addChild(leaf); } newParent = leaf; } else { // the first line/heaptree start must never be a custom allocator, e.g.: // n11: 1776070 (heap allocation functions) malloc/new/new[], --alloc-fns, etc. Q_ASSERT(depth); Q_ASSERT(m_snapshot->heapTree()); newParent = m_snapshot->heapTree(); m_hadCustomAllocators = true; } SaveAndRestoreItem lastParent(&m_parentItem, newParent); for (unsigned int i = 0; i < children; ++i) { ++m_currentLine; QByteArray nextLine = m_file->readLine(); if (nextLine.isEmpty()) { // fail gracefully if the tree is not complete, esp. useful for cases where // an app run with massif crashes and massif doesn't finish the full tree dump. return true; } // remove trailing \n nextLine.chop(1); if (!parseheapTreeLeafInternal(nextLine, depth + 1)) { return false; } } return true; } //END Parser Functions diff --git a/massifdata/parseworker.cpp b/massifdata/parseworker.cpp index 9aa9050..684bd54 100644 --- a/massifdata/parseworker.cpp +++ b/massifdata/parseworker.cpp @@ -1,100 +1,103 @@ /* This file is part of Massif Visualizer Copyright 2012 Milian Wolff 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) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "parseworker.h" #include "parser.h" #include "filedata.h" -#include +#include #include -#include #include namespace Massif { ParseWorker::ParseWorker(QObject* parent) : QObject(parent) { } -void ParseWorker::parse(const KUrl& url, const QStringList& allocators) +void ParseWorker::parse(const QUrl &url, const QStringList& allocators) { // process in background thread if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "parse", Q_ARG(KUrl, url), Q_ARG(QStringList, allocators)); + QMetaObject::invokeMethod(this, "parse", Q_ARG(QUrl, url), Q_ARG(QStringList, allocators)); return; } m_shouldStop = 0; QString file; + // FIXME: KF5 +#if 0 if (!url.isLocalFile()) { if (!KIO::NetAccess::download(url, file, 0)) { emit error(i18n("Download Failed"), i18n("Failed to download remote massif data file %1.", url.pathOrUrl())); return; } } else { file = url.toLocalFile(); } +#endif + file = url.toLocalFile(); QScopedPointer device(KFilterDev::deviceForFile(file)); if (!device->open(QIODevice::ReadOnly)) { emit error(i18n("Read Failed"), i18n("Could not open file %1 for reading.", file)); return; } Parser p; emit progressRange(0, 100); connect(&p, SIGNAL(progress(int)), this, SIGNAL(progress(int))); QScopedPointer data(p.parse(device.data(), allocators, &m_shouldStop)); if (!data) { - if (!m_shouldStop) { + if (!m_shouldStop.load()) { emit error(i18n("Parser Failed"), i18n("Could not parse file %1.
" "Parse error in line %2:
%3", - url.pathOrUrl(), p.errorLine() + 1, + url.toString(), p.errorLine() + 1, QString::fromLatin1(p.errorLineString()))); } return; } else if (data->snapshots().isEmpty()) { - emit error(i18n("Empty data file %1.", url.pathOrUrl()), + emit error(i18n("Empty data file %1.", url.toString()), i18n("Empty Data File")); return; } emit progress(100); // success! emit finished(url, data.take()); } void ParseWorker::stop() { m_shouldStop = 1; } } #include "parseworker.moc" diff --git a/massifdata/parseworker.h b/massifdata/parseworker.h index 547b8a3..df16767 100644 --- a/massifdata/parseworker.h +++ b/massifdata/parseworker.h @@ -1,67 +1,69 @@ /* This file is part of Massif Visualizer Copyright 2012 Milian Wolff 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) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef MASSIFDATA_PARSETHREAD_H #define MASSIFDATA_PARSETHREAD_H +#include + #include #include -#include +#include namespace Massif { class FileData; -class ParseWorker : public QObject +class MASSIFDATA_EXPORT ParseWorker : public QObject { Q_OBJECT public: explicit ParseWorker(QObject* parent = 0); void stop(); public slots: - void parse(const KUrl& url, const QStringList& allocators); + void parse(const QUrl& url, const QStringList& allocators); signals: /** * Emitted once a file was properly parsed. */ - void finished(const KUrl& url, Massif::FileData* data); + void finished(const QUrl& url, Massif::FileData* data); /** * Emitted if a file could not be parsed. */ void error(const QString& error, const QString& message); void progressRange(int min, int max); void progress(int value); private: QAtomicInt m_shouldStop; }; } #endif // MASSIFDATA_PARSETHREAD_H diff --git a/massifdata/util.cpp b/massifdata/util.cpp index 6916297..59eb7c2 100644 --- a/massifdata/util.cpp +++ b/massifdata/util.cpp @@ -1,159 +1,162 @@ /* This file is part of Massif Visualizer Copyright 2010 Milian Wolff This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #include "util.h" #include "snapshotitem.h" #include "treeleafitem.h" -#include -#include #include +#include +#include +#include #include namespace Massif { QString prettyCost(quint64 cost) { - Q_ASSERT(KGlobal::config()); - KConfigGroup conf = KGlobal::config()->group(QLatin1String("Settings")); + Q_ASSERT(KSharedConfig::openConfig()); + KConfigGroup conf = KSharedConfig::openConfig()->group(QLatin1String("Settings")); int precision = conf.readEntry(QLatin1String("prettyCostPrecision"), 1); - return KGlobal::locale()->formatByteSize(cost, precision); + + KFormat format(QLocale::system()); + return format.formatByteSize(cost, precision); } void shortenTemplates(QByteArray& function) { Q_ASSERT(KGlobal::config()); - KConfigGroup conf = KGlobal::config()->group(QLatin1String("Settings")); + KConfigGroup conf = KSharedConfig::openConfig()->group(QLatin1String("Settings")); if (conf.readEntry(QLatin1String("shortenTemplates"), false)) { // remove template arguments between <...> int depth = 0; int open = 0; for (int i = 0; i < function.length(); ++i) { if (function.at(i) == '<') { if (!depth) { open = i; } ++depth; } else if (function.at(i) == '>') { --depth; if (!depth) { function.remove(open + 1, i - open - 1); i = open + 1; open = 0; } } } } } struct ParsedLabel { QByteArray address; QByteArray function; QByteArray location; }; ParsedLabel parseLabel(const QByteArray& label) { ParsedLabel ret; int functionStart = 0; int functionEnd = label.length(); if (label.startsWith("0x")) { int colonPos = label.indexOf(": "); if (colonPos != -1) { ret.address = label.left(colonPos); functionStart = colonPos + 2; } } if (label.endsWith(')')) { int locationPos = label.lastIndexOf(" ("); if (locationPos != -1) { ret.location = label.mid(locationPos + 2, label.length() - locationPos - 3); functionEnd = locationPos; } } ret.function = label.mid(functionStart, functionEnd - functionStart); return ret; } QByteArray prettyLabel(const QByteArray& label) { ParsedLabel parsed = parseLabel(label); shortenTemplates(parsed.function); if (!parsed.location.isEmpty()) { return parsed.function + " (" + parsed.location + ")"; } else { return parsed.function; } } QByteArray functionInLabel(const QByteArray& label) { return parseLabel(label).function; } QByteArray addressInLabel(const QByteArray& label) { return parseLabel(label).address; } QByteArray locationInLabel(const QByteArray& label) { return parseLabel(label).location; } bool isBelowThreshold(const QByteArray& label) { return label.indexOf("all below massif's threshold") != -1; } QString formatLabel(const QByteArray& label) { ParsedLabel parsed = parseLabel(label); QString ret; if (!parsed.function.isEmpty()) { ret += i18n("
function:
%1
\n", Qt::escape(parsed.function)); } if (!parsed.location.isEmpty()) { ret += i18n("
location:
%1
\n", Qt::escape(parsed.location)); } if (!parsed.address.isEmpty()) { ret += i18n("
address:
%1
\n", Qt::escape(parsed.address)); } return ret; } QString tooltipForTreeLeaf(TreeLeafItem* node, SnapshotItem* snapshot, const QByteArray& label) { QString tooltip = "
\n"; tooltip += i18n("
cost:
%1, i.e. %2% of snapshot #%3
", prettyCost(node ? node->cost() : 0), // yeah nice how I round to two decimals, right? :D double(int(double(node ? node->cost() : 0)/snapshot->cost()*10000))/100, snapshot->number()); tooltip += formatLabel(label); tooltip += "
"; return tooltip; } } diff --git a/pics/hicolor/CMakeLists.txt b/pics/hicolor/CMakeLists.txt index b78ce8a..d8b3781 100644 --- a/pics/hicolor/CMakeLists.txt +++ b/pics/hicolor/CMakeLists.txt @@ -1 +1 @@ -kde4_install_icons( ${DATA_INSTALL_DIR}/massif-visualizer/icons ) +ecm_install_icons(${DATA_INSTALL_DIR}/massif-visualizer/icons) diff --git a/visualizer/CMakeLists.txt b/visualizer/CMakeLists.txt index df7d32f..115ee3f 100644 --- a/visualizer/CMakeLists.txt +++ b/visualizer/CMakeLists.txt @@ -1,22 +1,22 @@ include_directories( ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ) set(visualizer_SRCS totalcostmodel.cpp detailedcostmodel.cpp datatreemodel.cpp filtereddatatreemodel.cpp dotgraphgenerator.cpp ) -kde4_add_library(mv-visualizer ${visualizer_SRCS}) +add_library(mv-visualizer ${visualizer_SRCS}) target_link_libraries(mv-visualizer mv-massifdata mv-kdchart - ${QT_QTCORE_LIBRARY} - ${QT_QTGUI_LIBRARY} - ${KDE4_KDECORE_LIBS} + Qt5::Core + Qt5::Gui + KF5::KDELibs4Support ) diff --git a/visualizer/filtereddatatreemodel.h b/visualizer/filtereddatatreemodel.h index 8da38fd..d5c1407 100644 --- a/visualizer/filtereddatatreemodel.h +++ b/visualizer/filtereddatatreemodel.h @@ -1,68 +1,68 @@ /* This file is part of Massif Visualizer Copyright 2010 Milian Wolff This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #ifndef MASSIF_FILTEREDDATATREEMODEL_H #define MASSIF_FILTEREDDATATREEMODEL_H -#include +#include #include #include "visualizer_export.h" namespace Massif { class DataTreeModel; /** * Filter class for DataTreeModel */ class VISUALIZER_EXPORT FilteredDataTreeModel : public QSortFilterProxyModel { Q_OBJECT public: explicit FilteredDataTreeModel(DataTreeModel* parent); public slots: void setFilter(const QString& needle); protected: /// true for any branch that has an item in it that matches m_needle virtual bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const; /// always true virtual bool filterAcceptsColumn(int source_column, const QModelIndex& source_parent) const; private slots: void timeout(); private: /// we don't want that virtual void setSourceModel(QAbstractItemModel* sourceModel); /// search string that should be contained in the data (case insensitively) QString m_needle; QTimer m_timer; }; } #endif // MASSIF_FILTEREDDATATREEMODEL_H