mirror of
https://bitbucket.org/smil3y/kde-playground.git
synced 2025-02-23 18:32:51 +00:00
620 lines
20 KiB
C++
620 lines
20 KiB
C++
/*
|
|
This file is part of Massif Visualizer
|
|
|
|
Copyright 2014 Milian Wolff <mail@milianw.de>
|
|
|
|
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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "charttab.h"
|
|
|
|
#include "KDChartChart"
|
|
#include "KDChartGridAttributes"
|
|
#include "KDChartHeaderFooter"
|
|
#include "KDChartCartesianCoordinatePlane"
|
|
#include "KDChartPlotter"
|
|
#include "KDChartLegend"
|
|
#include "KDChartDataValueAttributes"
|
|
#include "KDChartBackgroundAttributes"
|
|
#include <KDChartFrameAttributes.h>
|
|
|
|
#include "visualizer/totalcostmodel.h"
|
|
#include "visualizer/detailedcostmodel.h"
|
|
#include "visualizer/datatreemodel.h"
|
|
#include "visualizer/filtereddatatreemodel.h"
|
|
|
|
#include "massifdata/util.h"
|
|
#include "massifdata/snapshotitem.h"
|
|
#include "massifdata/treeleafitem.h"
|
|
#include "massifdata/filedata.h"
|
|
|
|
#include "massif-visualizer-settings.h"
|
|
|
|
#include <QVBoxLayout>
|
|
#include <QPrinter>
|
|
#include <QPrintPreviewDialog>
|
|
#include <QLabel>
|
|
#include <QMenu>
|
|
#include <QApplication>
|
|
#include <QDesktopWidget>
|
|
#include <QSvgGenerator>
|
|
|
|
#include <KColorScheme>
|
|
#include <KLocalizedString>
|
|
#include <KStandardAction>
|
|
#include <KActionCollection>
|
|
#include <KAction>
|
|
#include <KFileDialog>
|
|
#include <KMessageBox>
|
|
#include <KLocale>
|
|
|
|
using namespace KDChart;
|
|
using namespace Massif;
|
|
|
|
namespace {
|
|
|
|
class TimeAxis : public CartesianAxis
|
|
{
|
|
Q_OBJECT
|
|
public:
|
|
explicit TimeAxis(AbstractCartesianDiagram* diagram = 0)
|
|
: CartesianAxis(diagram)
|
|
{}
|
|
|
|
virtual const QString customizedLabel(const QString& label) const
|
|
{
|
|
// squeeze large numbers here
|
|
// TODO: when the unit is 'b' also use prettyCost() here
|
|
return QString::number(label.toDouble());
|
|
}
|
|
};
|
|
|
|
class SizeAxis : public CartesianAxis
|
|
{
|
|
Q_OBJECT
|
|
public:
|
|
explicit SizeAxis(AbstractCartesianDiagram* diagram = 0)
|
|
: CartesianAxis(diagram)
|
|
{}
|
|
|
|
virtual const QString customizedLabel(const QString& label) const
|
|
{
|
|
// TODO: change distance between labels to 1024 and simply use prettyCost() here
|
|
return KGlobal::locale()->formatByteSize(label.toDouble(), 1, KLocale::MetricBinaryDialect);
|
|
}
|
|
};
|
|
|
|
void markPeak(Plotter* p, const QModelIndex& peak, quint64 cost, const KColorScheme& scheme)
|
|
{
|
|
QBrush brush = p->model()->data(peak, DatasetBrushRole).value<QBrush>();
|
|
|
|
QColor outline = brush.color();
|
|
QColor foreground = scheme.foreground().color();
|
|
QBrush background = scheme.background();
|
|
|
|
DataValueAttributes dataAttributes = p->dataValueAttributes(peak);
|
|
dataAttributes.setDataLabel(prettyCost(cost));
|
|
dataAttributes.setVisible(true);
|
|
dataAttributes.setShowRepetitiveDataLabels(true);
|
|
dataAttributes.setShowOverlappingDataLabels(false);
|
|
|
|
FrameAttributes frameAttrs = dataAttributes.frameAttributes();
|
|
QPen framePen(outline);
|
|
framePen.setWidth(2);
|
|
frameAttrs.setPen(framePen);
|
|
frameAttrs.setVisible(true);
|
|
dataAttributes.setFrameAttributes(frameAttrs);
|
|
|
|
MarkerAttributes a = dataAttributes.markerAttributes();
|
|
a.setMarkerSize(QSizeF(7, 7));
|
|
a.setPen(outline);
|
|
a.setMarkerStyle(KDChart::MarkerAttributes::MarkerDiamond);
|
|
a.setVisible(true);
|
|
dataAttributes.setMarkerAttributes(a);
|
|
|
|
TextAttributes txtAttrs = dataAttributes.textAttributes();
|
|
txtAttrs.setPen(foreground);
|
|
txtAttrs.setFontSize(Measure(12));
|
|
dataAttributes.setTextAttributes(txtAttrs);
|
|
|
|
BackgroundAttributes bkgAtt = dataAttributes.backgroundAttributes();
|
|
|
|
bkgAtt.setBrush(background);
|
|
bkgAtt.setVisible(true);
|
|
dataAttributes.setBackgroundAttributes(bkgAtt);
|
|
|
|
p->setDataValueAttributes(peak, dataAttributes);
|
|
}
|
|
|
|
}
|
|
|
|
ChartTab::ChartTab(const FileData* data,
|
|
KXMLGUIClient* guiParent, QWidget* parent)
|
|
: DocumentTabInterface(data, guiParent, 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_print(0)
|
|
, m_saveAs(0)
|
|
, m_toggleTotal(0)
|
|
, m_toggleDetailed(0)
|
|
, m_hideFunction(0)
|
|
, m_hideOtherFunctions(0)
|
|
, m_box(new QSpinBox(this))
|
|
, m_settingSelection(false)
|
|
{
|
|
setXMLFile("charttabui.rc", true);
|
|
setupActions();
|
|
|
|
setLayout(new QVBoxLayout(this));
|
|
|
|
setupGui();
|
|
}
|
|
|
|
ChartTab::~ChartTab()
|
|
{
|
|
}
|
|
|
|
void ChartTab::setupActions()
|
|
{
|
|
m_print = KStandardAction::print(this, SLOT(showPrintPreviewDialog()), actionCollection());
|
|
actionCollection()->addAction("file_print", m_print);
|
|
|
|
m_saveAs = KStandardAction::saveAs(this, SLOT(saveCurrentDocument()), actionCollection());
|
|
actionCollection()->addAction("file_save_as", m_saveAs);
|
|
|
|
m_toggleTotal = new KAction(KIcon("office-chart-area"), i18n("Toggle total cost graph"), actionCollection());
|
|
m_toggleTotal->setCheckable(true);
|
|
m_toggleTotal->setChecked(true);
|
|
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->setCheckable(true);
|
|
m_toggleDetailed->setChecked(true);
|
|
connect(m_toggleDetailed, SIGNAL(toggled(bool)), SLOT(showDetailedGraph(bool)));
|
|
actionCollection()->addAction("toggle_detailed", m_toggleDetailed);
|
|
|
|
KAction* 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);
|
|
|
|
m_hideFunction = new KAction(i18n("hide function"), this);
|
|
connect(m_hideFunction, SIGNAL(triggered()),
|
|
this, SLOT(slotHideFunction()));
|
|
m_hideOtherFunctions = new KAction(i18n("hide other functions"), this);
|
|
connect(m_hideOtherFunctions, SIGNAL(triggered()),
|
|
this, SLOT(slotHideOtherFunctions()));
|
|
}
|
|
|
|
void ChartTab::setupGui()
|
|
{
|
|
layout()->addWidget(m_header);
|
|
layout()->addWidget(m_chart);
|
|
|
|
// 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());
|
|
|
|
// for axis labels to fit
|
|
m_chart->setGlobalLeadingRight(10);
|
|
m_chart->setGlobalLeadingLeft(10);
|
|
m_chart->setGlobalLeadingTop(20);
|
|
m_chart->setContextMenuPolicy(Qt::CustomContextMenu);
|
|
|
|
updateLegendPosition();
|
|
m_legend->setTitleText(QString());
|
|
m_legend->setSortOrder(Qt::DescendingOrder);
|
|
|
|
m_chart->addLegend(m_legend);
|
|
|
|
//NOTE: this has to be set _after_ the legend was added to the chart...
|
|
updateLegendFont();
|
|
m_legend->setTextAlignment(Qt::AlignLeft);
|
|
m_legend->hide();
|
|
|
|
connect(m_chart, SIGNAL(customContextMenuRequested(QPoint)),
|
|
this, SLOT(chartContextMenuRequested(QPoint)));
|
|
|
|
//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(this);
|
|
m_totalDiagram->setAntiAliasing(true);
|
|
|
|
CartesianAxis* bottomAxis = new TimeAxis(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 SizeAxis(m_totalDiagram);
|
|
rightAxis->setTextAttributes(axisTextAttributes);
|
|
rightAxis->setTitleTextAttributes(axisTitleTextAttributes);
|
|
rightAxis->setTitleText(i18n("memory heap size"));
|
|
rightAxis->setPosition ( CartesianAxis::Right );
|
|
m_totalDiagram->addAxis(rightAxis);
|
|
|
|
m_totalCostModel->setSource(m_data);
|
|
m_totalDiagram->setModel(m_totalCostModel);
|
|
|
|
CartesianCoordinatePlane* coordinatePlane = dynamic_cast<CartesianCoordinatePlane*>(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(KDChart::Plotter::Stacked);
|
|
|
|
m_detailedCostModel->setSource(m_data);
|
|
m_detailedDiagram->setModel(m_detailedCostModel);
|
|
|
|
updatePeaks();
|
|
|
|
m_chart->coordinatePlane()->addDiagram(m_detailedDiagram);
|
|
|
|
m_legend->addDiagram(m_detailedDiagram);
|
|
m_legend->show();
|
|
|
|
m_box->setValue(m_detailedCostModel->maximumDatasetCount());
|
|
|
|
connect(m_totalDiagram, SIGNAL(clicked(QModelIndex)),
|
|
this, SLOT(totalItemClicked(QModelIndex)));
|
|
connect(m_detailedDiagram, SIGNAL(clicked(QModelIndex)),
|
|
this, SLOT(detailedItemClicked(QModelIndex)));
|
|
}
|
|
|
|
void ChartTab::settingsChanged()
|
|
{
|
|
updateHeader();
|
|
updatePeaks();
|
|
updateLegendPosition();
|
|
updateLegendFont();
|
|
}
|
|
|
|
void ChartTab::setDetailedDiagramHidden(bool hidden)
|
|
{
|
|
m_detailedDiagram->setHidden(hidden);
|
|
}
|
|
|
|
void ChartTab::setDetailedDiagramVisible(bool visible)
|
|
{
|
|
m_detailedDiagram->setVisible(visible);
|
|
}
|
|
|
|
void ChartTab::setTotalDiagramHidden(bool hidden)
|
|
{
|
|
m_totalDiagram->setHidden(hidden);
|
|
}
|
|
|
|
void ChartTab::setTotalDiagramVisible(bool visible)
|
|
{
|
|
m_totalDiagram->setVisible(visible);
|
|
}
|
|
|
|
void ChartTab::updatePeaks()
|
|
{
|
|
KColorScheme scheme(QPalette::Active, KColorScheme::Window);
|
|
|
|
if (m_data->peak()) {
|
|
const QModelIndex peak = m_totalCostModel->peak();
|
|
Q_ASSERT(peak.isValid());
|
|
markPeak(m_totalDiagram, peak, m_data->peak()->cost(), scheme);
|
|
}
|
|
updateDetailedPeaks();
|
|
}
|
|
|
|
void ChartTab::updateLegendPosition()
|
|
{
|
|
KDChartEnums::PositionValue pos;
|
|
switch (Settings::self()->legendPosition()) {
|
|
case Settings::EnumLegendPosition::North:
|
|
pos = KDChartEnums::PositionNorth;
|
|
break;
|
|
case Settings::EnumLegendPosition::South:
|
|
pos = KDChartEnums::PositionSouth;
|
|
break;
|
|
case Settings::EnumLegendPosition::East:
|
|
pos = KDChartEnums::PositionEast;
|
|
break;
|
|
case Settings::EnumLegendPosition::West:
|
|
pos = KDChartEnums::PositionWest;
|
|
break;
|
|
case Settings::EnumLegendPosition::Floating:
|
|
pos = KDChartEnums::PositionFloating;
|
|
break;
|
|
default:
|
|
pos = KDChartEnums::PositionFloating;
|
|
kDebug() << "invalid legend position";
|
|
}
|
|
m_legend->setPosition(Position(pos));
|
|
|
|
Qt::Alignment align;
|
|
switch (Settings::self()->legendAlignment()) {
|
|
case Settings::EnumLegendAlignment::Left:
|
|
align = Qt::AlignLeft;
|
|
break;
|
|
case Settings::EnumLegendAlignment::Center:
|
|
align = Qt::AlignHCenter | Qt::AlignVCenter;
|
|
break;
|
|
case Settings::EnumLegendAlignment::Right:
|
|
align = Qt::AlignRight;
|
|
break;
|
|
case Settings::EnumLegendAlignment::Top:
|
|
align = Qt::AlignTop;
|
|
break;
|
|
case Settings::EnumLegendAlignment::Bottom:
|
|
align = Qt::AlignBottom;
|
|
break;
|
|
default:
|
|
align = Qt::AlignHCenter | Qt::AlignVCenter;
|
|
kDebug() << "invalid legend alignmemnt";
|
|
}
|
|
|
|
// do something reasonable since top,bottom have no effect
|
|
// when used with north,south, same for left,right used with
|
|
// east,west
|
|
if ((((pos == KDChartEnums::PositionNorth) || (pos == KDChartEnums::PositionSouth))
|
|
&& ((align == Qt::AlignTop) || (align == Qt::AlignBottom)))
|
|
|| (((pos == KDChartEnums::PositionEast) || (pos == KDChartEnums::PositionWest))
|
|
&& ((align == Qt::AlignLeft) || (align == Qt::AlignRight)))) {
|
|
|
|
align = Qt::AlignHCenter | Qt::AlignVCenter;
|
|
}
|
|
|
|
m_legend->setAlignment(align);
|
|
}
|
|
|
|
void ChartTab::updateLegendFont()
|
|
{
|
|
TextAttributes att = m_legend->textAttributes();
|
|
att.setAutoShrink(true);
|
|
att.setFontSize(Measure(Settings::self()->legendFontSize()));
|
|
QFont font("monospace");
|
|
font.setStyleHint(QFont::TypeWriter);
|
|
att.setFont(font);
|
|
m_legend->setTextAttributes(att);
|
|
}
|
|
|
|
void ChartTab::updateDetailedPeaks()
|
|
{
|
|
KColorScheme scheme(QPalette::Active, KColorScheme::Window);
|
|
|
|
const DetailedCostModel::Peaks& peaks = m_detailedCostModel->peaks();
|
|
DetailedCostModel::Peaks::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(), scheme);
|
|
++it;
|
|
}
|
|
}
|
|
|
|
void ChartTab::updateHeader()
|
|
{
|
|
const QString app = m_data->cmd().split(' ', QString::SkipEmptyParts).first();
|
|
|
|
m_header->setText(QString("<b>%1</b><br /><i>%2</i>")
|
|
.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 ChartTab::saveCurrentDocument()
|
|
{
|
|
QString saveFilename = KFileDialog::getSaveFileName(KUrl("kfiledialog:///massif-visualizer"),
|
|
QString("image/png image/jpeg image/tiff image/svg+xml"),
|
|
this, i18n("Save Current Visualization"), KFileDialog::ConfirmOverwrite);
|
|
|
|
if (!saveFilename.isEmpty()) {
|
|
|
|
// TODO: implement a dialog to expose more options to the user.
|
|
// for example we could expose dpi, size, and various format
|
|
// dependent options such as compressions settings.
|
|
|
|
// Vector graphic format
|
|
if (QFileInfo(saveFilename).suffix().compare(QLatin1String("svg")) == 0) {
|
|
QSvgGenerator generator;
|
|
generator.setFileName(saveFilename);
|
|
generator.setSize(m_chart->size());
|
|
generator.setViewBox(m_chart->rect());
|
|
|
|
QPainter painter;
|
|
painter.begin(&generator);
|
|
m_chart->paint(&painter, m_chart->rect());
|
|
painter.end();
|
|
}
|
|
|
|
// Other format
|
|
else if (!QPixmap::grabWidget(m_chart).save(saveFilename)) {
|
|
|
|
KMessageBox::sorry(this, QString(
|
|
i18n("Error, failed to save the image to %1.")
|
|
).arg(saveFilename));
|
|
}
|
|
}
|
|
}
|
|
|
|
void ChartTab::showPrintPreviewDialog()
|
|
{
|
|
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 ChartTab::printFile(QPrinter *printer)
|
|
{
|
|
QPainter painter;
|
|
painter.begin(printer);
|
|
m_chart->paint(&painter, printer->pageRect());
|
|
painter.end();
|
|
}
|
|
|
|
void ChartTab::showDetailedGraph(bool show)
|
|
{
|
|
m_detailedDiagram->setHidden(!show);
|
|
m_toggleDetailed->setChecked(show);
|
|
m_chart->update();
|
|
}
|
|
|
|
void ChartTab::showTotalGraph(bool show)
|
|
{
|
|
m_totalDiagram->setHidden(!show);
|
|
m_toggleTotal->setChecked(show);
|
|
m_chart->update();
|
|
}
|
|
|
|
void ChartTab::slotHideFunction()
|
|
{
|
|
m_detailedCostModel->hideFunction(m_hideFunction->data().value<const TreeLeafItem*>());
|
|
}
|
|
|
|
void ChartTab::slotHideOtherFunctions()
|
|
{
|
|
m_detailedCostModel->hideOtherFunctions(m_hideOtherFunctions->data().value<const TreeLeafItem*>());
|
|
}
|
|
|
|
void ChartTab::chartContextMenuRequested(const QPoint& pos)
|
|
{
|
|
const QPoint dPos = m_detailedDiagram->mapFromGlobal(m_chart->mapToGlobal(pos));
|
|
|
|
const QModelIndex idx = m_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_detailedCostModel->index(idx.row() + 1, idx.column(), idx.parent());
|
|
ModelItem item = m_detailedCostModel->itemForIndex(_idx);
|
|
|
|
if (!item.first) {
|
|
return;
|
|
}
|
|
|
|
QMenu menu;
|
|
|
|
m_hideFunction->setData(QVariant::fromValue(item.first));
|
|
menu.addAction(m_hideFunction);
|
|
|
|
m_hideOtherFunctions->setData(QVariant::fromValue(item.first));
|
|
menu.addAction(m_hideOtherFunctions);
|
|
|
|
menu.addSeparator();
|
|
|
|
emit contextMenuRequested(item, &menu);
|
|
|
|
menu.exec(m_detailedDiagram->mapToGlobal(dPos));
|
|
}
|
|
|
|
void ChartTab::setStackNum(int num)
|
|
{
|
|
m_detailedCostModel->setMaximumDatasetCount(num);
|
|
updatePeaks();
|
|
}
|
|
|
|
void ChartTab::detailedItemClicked(const QModelIndex& idx)
|
|
{
|
|
m_detailedCostModel->setSelection(idx);
|
|
m_totalCostModel->setSelection(QModelIndex());
|
|
m_chart->update();
|
|
|
|
// 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
|
|
m_settingSelection = true;
|
|
const QModelIndex _idx = m_detailedCostModel->index(idx.row() + 1, idx.column(), idx.parent());
|
|
emit modelItemSelected(m_detailedCostModel->itemForIndex(_idx));
|
|
m_settingSelection = false;
|
|
}
|
|
|
|
void ChartTab::totalItemClicked(const QModelIndex& idx)
|
|
{
|
|
const QModelIndex _idx = m_totalCostModel->index(idx.row() + 1, idx.column(), idx.parent());
|
|
m_totalCostModel->setSelection(_idx);
|
|
m_detailedCostModel->setSelection(QModelIndex());
|
|
m_chart->update();
|
|
|
|
m_settingSelection = true;
|
|
emit modelItemSelected(m_totalCostModel->itemForIndex(_idx));
|
|
m_settingSelection = false;
|
|
}
|
|
|
|
void ChartTab::selectModelItem(const ModelItem& item)
|
|
{
|
|
if (m_settingSelection) {
|
|
return;
|
|
}
|
|
|
|
if (item.first) {
|
|
m_detailedCostModel->setSelection(m_detailedCostModel->indexForItem(item));
|
|
m_totalCostModel->setSelection(QModelIndex());
|
|
} else {
|
|
m_totalCostModel->setSelection(m_totalCostModel->indexForItem(item));
|
|
m_detailedCostModel->setSelection(QModelIndex());
|
|
}
|
|
|
|
m_chart->update();
|
|
}
|
|
|
|
#include "charttab.moc"
|
|
#include "moc_charttab.cpp"
|