added a context menu to histogram (QWT)
authorAlexey Chernobaev <achernobaev@dev.rtsoft.ru>
Sat, 24 Mar 2018 22:48:26 +0000 (01:48 +0300)
committerAlexey Chernobaev <achernobaev@dev.rtsoft.ru>
Sat, 24 Mar 2018 22:48:26 +0000 (01:48 +0300)
16 files changed:
src/analyze/gui/chartwidget.cpp
src/analyze/gui/chartwidget.h
src/analyze/gui/chartwidgetqwtplot.cpp
src/analyze/gui/chartwidgetqwtplot.h
src/analyze/gui/contextmenuqwt.cpp
src/analyze/gui/contextmenuqwt.h
src/analyze/gui/histogrammodel.cpp
src/analyze/gui/histogrammodel.h
src/analyze/gui/histogramwidget.cpp
src/analyze/gui/histogramwidget.h
src/analyze/gui/histogramwidgetqwtplot.cpp
src/analyze/gui/histogramwidgetqwtplot.h
src/analyze/gui/mainwindow.cpp
src/analyze/gui/mainwindow.h
src/analyze/gui/util.cpp
src/analyze/gui/util.h

index bf4e3a56099a2cfb20ca5f45ff922a4f3010b241..95baca741b6cd509dc33ac292dcef02752b856e1 100644 (file)
 #elif defined(QWT_FOUND)
 #include <QAction>
 #include <QContextMenuEvent>
-#include <QFileDialog>
-#include <QFileInfo>
 #include <QMenu>
-#include <QMessageBox>
-#include <QRegularExpression>
 #endif
 
 #ifdef NO_K_LIB
@@ -132,15 +128,10 @@ protected:
     virtual void closeEvent(QCloseEvent *event) override
     {
         QMainWindow::closeEvent(event);
-        ChartWidget::GlobalOptions = ChartOptions::setOption(ChartWidget::GlobalOptions, ChartOptions::ShowHelp, false);
+        ChartOptions::GlobalOptions = ChartOptions::setOption(ChartOptions::GlobalOptions, ChartOptions::ShowHelp, false);
     }
 };
 
-ChartOptions::Options ChartWidget::GlobalOptions(
-    ChartOptions::ShowHelp |
-    ChartOptions::ShowTotal | ChartOptions::ShowUnresolved |
-    ChartOptions::ShowLegend | ChartOptions::ShowCurveBorders);
-
 QWidget* ChartWidget::HelpWindow;
 QWidget* ChartWidget::MainWindow;
 #endif // QWT_FOUND
@@ -150,7 +141,7 @@ ChartWidget::ChartWidget(QWidget* parent)
 #if defined(KChart_FOUND)
     , m_chart(new Chart(this))
 #elif defined(QWT_FOUND)
-    , m_plot(new ChartWidgetQwtPlot(this, GlobalOptions))
+    , m_plot(new ChartWidgetQwtPlot(this, ChartOptions::GlobalOptions))
     , m_contextMenuQwt(new ContextMenuQwt(this, false))
 #endif
 #ifdef SHOW_TABLES
@@ -164,7 +155,7 @@ ChartWidget::ChartWidget(QWidget* parent)
 #elif defined(QWT_FOUND)
     layout->addWidget(m_plot);
 
-    createActions();
+    connectContextMenu();
 #endif
 #ifdef SHOW_TABLES
     auto hLayout = new QHBoxLayout();
@@ -190,14 +181,14 @@ ChartWidget::~ChartWidget() = default;
 void ChartWidget::updateOnSelected(QWidget *mainWindow)
 {
     MainWindow = mainWindow;
-    m_plot->setOptions(GlobalOptions);
-    if (m_plot->hasOption(ChartWidgetQwtPlot::ShowHelp))
+    m_plot->setOptions(ChartOptions::GlobalOptions);
+    if (m_plot->hasOption(ChartOptions::ShowHelp))
     {
         showHelp();
     }
 }
 
-void ChartWidget::createActions()
+void ChartWidget::connectContextMenu()
 {
     connect(m_contextMenuQwt->resetZoomAction(), &QAction::triggered, this, &ChartWidget::resetZoom);
     connect(m_contextMenuQwt->showTotalAction(), &QAction::triggered, this, &ChartWidget::toggleShowTotal);
@@ -206,7 +197,9 @@ void ChartWidget::createActions()
     connect(m_contextMenuQwt->showCurveBordersAction(), &QAction::triggered, this, &ChartWidget::toggleShowCurveBorders);
     connect(m_contextMenuQwt->showSymbolsAction(), &QAction::triggered, this, &ChartWidget::toggleShowSymbols);
     connect(m_contextMenuQwt->showVLinesAction(), &QAction::triggered, this, &ChartWidget::toggleShowVLines);
-    connect(m_contextMenuQwt->exportChartAction(), &QAction::triggered, this, &ChartWidget::exportChart);
+    connect(m_contextMenuQwt->exportChartAction(), &QAction::triggered, this, [=]() {
+        Util::exportChart(this, *m_plot, m_plot->model()->headerData(1, Qt::Horizontal).toString());
+    });
     connect(m_contextMenuQwt->showHelpAction(), &QAction::triggered, this, &ChartWidget::toggleShowHelp);
 
     setFocusPolicy(Qt::StrongFocus);
@@ -347,8 +340,8 @@ void ChartWidget::modelReset()
 void ChartWidget::contextMenuEvent(QContextMenuEvent *event)
 {
     QMenu menu(this);
-    m_plot->setOption(ChartWidgetQwtPlot::ShowHelp,
-                      ChartWidgetQwtPlot::hasOption(GlobalOptions, ChartWidgetQwtPlot::ShowHelp));
+    m_plot->setOption(ChartOptions::ShowHelp,
+                      ChartOptions::hasOption(ChartOptions::GlobalOptions, ChartOptions::ShowHelp));
     m_contextMenuQwt->initializeMenu(menu, m_plot->options());
     menu.exec(event->globalPos());
 }
@@ -356,7 +349,7 @@ void ChartWidget::contextMenuEvent(QContextMenuEvent *event)
 
 void ChartWidget::keyPressEvent(QKeyEvent *event)
 {
-    m_contextMenuQwt->handleKeyPress(event, m_plot->options());
+    m_contextMenuQwt->handleKeyPress(event);
 }
 
 void ChartWidget::resetZoom()
@@ -366,37 +359,37 @@ void ChartWidget::resetZoom()
 
 void ChartWidget::toggleShowTotal()
 {
-    GlobalOptions = m_plot->toggleOption(ChartWidgetQwtPlot::ShowTotal);
+    ChartOptions::GlobalOptions = m_plot->toggleOption(ChartOptions::ShowTotal);
 }
 
 void ChartWidget::toggleShowUnresolved()
 {
-    GlobalOptions = m_plot->toggleOption(ChartWidgetQwtPlot::ShowUnresolved);
+    ChartOptions::GlobalOptions = m_plot->toggleOption(ChartOptions::ShowUnresolved);
 }
 
 void ChartWidget::toggleShowLegend()
 {
-    GlobalOptions = m_plot->toggleOption(ChartWidgetQwtPlot::ShowLegend);
+    ChartOptions::GlobalOptions = m_plot->toggleOption(ChartOptions::ShowLegend);
 }
 
 void ChartWidget::toggleShowCurveBorders()
 {
-    GlobalOptions = m_plot->toggleOption(ChartWidgetQwtPlot::ShowCurveBorders);
+    ChartOptions::GlobalOptions = m_plot->toggleOption(ChartOptions::ShowCurveBorders);
 }
 
 void ChartWidget::toggleShowSymbols()
 {
-    GlobalOptions = m_plot->toggleOption(ChartWidgetQwtPlot::ShowSymbols);
+    ChartOptions::GlobalOptions = m_plot->toggleOption(ChartOptions::ShowSymbols);
 }
 
 void ChartWidget::toggleShowVLines()
 {
-    GlobalOptions = m_plot->toggleOption(ChartWidgetQwtPlot::ShowVLines);
+    ChartOptions::GlobalOptions = m_plot->toggleOption(ChartOptions::ShowVLines);
 }
 
 void ChartWidget::toggleShowHelp()
 {
-    bool checked = !ChartOptions::hasOption(GlobalOptions, ChartOptions::ShowHelp);
+    bool checked = !ChartOptions::hasOption(ChartOptions::GlobalOptions, ChartOptions::ShowHelp);
     if (checked)
     {
         showHelp();
@@ -409,7 +402,8 @@ void ChartWidget::toggleShowHelp()
             HelpWindow = nullptr;
         }
     }
-    GlobalOptions = ChartOptions::setOption(GlobalOptions, ChartOptions::ShowHelp, checked);
+    ChartOptions::GlobalOptions = ChartOptions::setOption(ChartOptions::GlobalOptions,
+        ChartOptions::ShowHelp, checked);
 }
 
 void ChartWidget::showHelp()
@@ -422,39 +416,6 @@ void ChartWidget::showHelp()
     }
     HelpWindow->show();
 }
-
-void ChartWidget::exportChart()
-{
-    QString selectedFilter;
-    QString saveFilename = QFileDialog::getSaveFileName(this, "Save Chart As",
-        m_plot->model()->headerData(1, Qt::Horizontal).toString(),
-        "PNG (*.png);; BMP (*.bmp);; JPEG (*.jpg *.jpeg)", &selectedFilter);
-    if (!saveFilename.isEmpty())
-    {
-        QFileInfo fi(saveFilename);
-        if (fi.suffix().isEmpty()) // can be on some platforms
-        {
-            int i = selectedFilter.indexOf("*.");
-            if (i >= 0)
-            {
-                static QRegularExpression delimiters("[ )]");
-                i += 2;
-                int j = selectedFilter.indexOf(delimiters, i);
-                if (j > i)
-                {
-                    --i;
-                    QString suffix = selectedFilter.mid(i, j - i);
-                    saveFilename += suffix;
-                }
-            }
-        }
-        if (!m_plot->grab().save(saveFilename))
-        {
-            QMessageBox::warning(this, "Error",
-                QString("Cannot save the chart to \"%1\".").arg(saveFilename), QMessageBox::Ok);
-        }
-    }
-}
 #endif // QWT_FOUND
 
 #include "chartwidget.moc"
index c7976133b575fb175cab20207b7025ba601ad425..74ab07c06f9edfd8243a00c721d13a93a116b518 100644 (file)
@@ -23,7 +23,6 @@
 #include "contextmenuqwt.h"
 
 #include <memory>
-
 #include <QWidget>
 
 //!! for debugging
@@ -57,17 +56,16 @@ public:
 
     QSize sizeHint() const override;
 
-#if defined(QWT_FOUND)
+#ifdef QWT_FOUND
     void updateOnSelected(QWidget *mainWindow);
 
-    static ChartOptions::Options GlobalOptions;
     static QWidget* HelpWindow;
     static QWidget* MainWindow;
 
 public slots:
     void modelReset();
-#ifndef QT_NO_CONTEXTMENU
 protected:
+#ifndef QT_NO_CONTEXTMENU
     virtual void contextMenuEvent(QContextMenuEvent *event) override;
 #endif
     // workaround for handling the context menu shortcuts
@@ -87,9 +85,8 @@ private slots:
     void toggleShowSymbols();
     void toggleShowVLines();
     void toggleShowHelp();
-    void exportChart();
 private:
-    void createActions();
+    void connectContextMenu();
 
     void showHelp();
 
index eab0613eef2e7b74f7f1390460747ff61332092f..08cefeb53b9e885846ccd8935238f092afd79475 100644 (file)
 
 #include <limits>
 
+ChartOptions::Options ChartOptions::GlobalOptions(
+    ChartOptions::ShowHelp |
+    ChartOptions::ShowTotal | ChartOptions::ShowUnresolved |
+    ChartOptions::ShowLegend | ChartOptions::ShowCurveBorders);
+
 class TimeScaleDraw: public QwtScaleDraw
 {
     virtual QwtText label(double value) const
@@ -99,6 +104,17 @@ ChartOptions::Options ChartOptions::setOption(Options options, Options option, b
     return (isOn ? (options | option) : Options(options & ~option));
 }
 
+ChartOptions::Options ChartOptions::setOption(Options option, bool isOn)
+{
+    setOptions(ChartOptions::setOption(m_options, option, isOn));
+    return m_options;
+}
+
+ChartOptions::Options ChartOptions::toggleOption(Options option)
+{
+    return setOption(option, !hasOption(option));
+}
+
 ChartWidgetQwtPlot::ChartWidgetQwtPlot(QWidget *parent, Options options)
     : QwtPlot(parent), m_model(nullptr), m_isSizeModel(false), ChartOptions(options),
       m_zoomer(new Zoomer(this))
@@ -130,17 +146,6 @@ void ChartWidgetQwtPlot::setModel(ChartModel* model)
           model->type() == ChartModel::Temporary);
 }
 
-ChartOptions::Options ChartWidgetQwtPlot::setOption(Options option, bool isOn)
-{
-    setOptions(ChartOptions::setOption(m_options, option, isOn));
-    return m_options;
-}
-
-ChartOptions::Options ChartWidgetQwtPlot::toggleOption(Options option)
-{
-    return setOption(option, !hasOption(option));
-}
-
 void ChartWidgetQwtPlot::setOptions(Options options)
 {
     if (m_options != options)
@@ -200,7 +205,8 @@ void ChartWidgetQwtPlot::rebuild(bool resetZoomAndPan)
     for (; column < columns; column += 2)
     {
         QString columnLabel = m_model->getColumnLabel(column);
-        if (!hasOption(ShowUnresolved) && columnLabel.startsWith("<unresolved function>"))
+        if (!hasOption(ShowUnresolved) &&
+            Util::isUnresolvedFunction(columnLabel)) // column label starts with a function name
         {
             continue;
         }
@@ -313,7 +319,7 @@ bool ChartWidgetQwtPlot::getCurveTooltip(const QPointF &position, QString &toolt
     for (; column < columns; column += 2)
     {
         if (!hasOption(ShowUnresolved) &&
-            m_model->getColumnLabel(column).startsWith("<unresolved function>"))
+            Util::isUnresolvedFunction(m_model->getColumnLabel(column))) // column label starts with a function name
         {
             continue;
         }
index e64410e2ac9e878bd51a1009026065ca44334607..3bffea54a741e0cf49b6008ff5223a249b67ebfa 100644 (file)
@@ -24,6 +24,8 @@ public:
         ShowVLines = 0x80
     };
 
+    static Options GlobalOptions;
+
     explicit ChartOptions(Options options) { m_options = options; }
 
     static bool hasOption(Options options, Options option) { return (options & option) != 0; }
@@ -34,8 +36,17 @@ public:
 
     bool hasOption(Options option) const { return hasOption(m_options, option); }
 
+    Options setOption(Options option, bool isOn);
+
+    Options toggleOption(Options option);
+
+    virtual void setOptions(Options options) = 0;
+
 protected:
     Options m_options;
+
+private:
+    ChartOptions() { }
 };
 
 class ChartWidgetQwtPlot : public QwtPlot, public ChartOptions
@@ -49,11 +60,7 @@ public:
 
     bool isSizeModel() const { return m_isSizeModel; }
 
-    Options setOption(Options option, bool isOn);
-
-    Options toggleOption(Options option);
-
-    void setOptions(Options options);
+    virtual void setOptions(Options options) override;
 
     void rebuild(bool resetZoomAndPan);
 
index 3defe7e3f3ad602d4bf5791b6c6cd6dca33a11a9..d8448032201185b1235165383b3dfa75f1de9265 100644 (file)
@@ -133,7 +133,7 @@ void ContextMenuQwt::initializeMenu(QMenu& menu, ChartOptions::Options options)
     }
 }
 
-void ContextMenuQwt::handleKeyPress(QKeyEvent *event, ChartOptions::Options options)
+void ContextMenuQwt::handleKeyPress(QKeyEvent *event)
 {
     if (event->modifiers() & Qt::AltModifier)
     {
index e15fa80314bd8e5de3697a3a0255eecf06d670a2..b2327da2ea03c8e511217b80d4257f6057ae526a 100644 (file)
@@ -24,7 +24,7 @@ public:
 
     void initializeMenu(QMenu& menu, ChartOptions::Options options) const;
 
-    void handleKeyPress(QKeyEvent *event, ChartOptions::Options options);
+    void handleKeyPress(QKeyEvent *event);
 
 private:
     QAction* m_resetZoomAction;
index 0ddb112c4114f5a482c4cd3872977c8712a5a65a..3367922b7f8605481282498da914294704cd9c25 100644 (file)
@@ -148,3 +148,10 @@ QColor HistogramModel::getColumnColor(int column) const
 {
     return colorForColumn(column, columnCount());
 }
+
+LocationData::Ptr HistogramModel::getLocationData(int row, int column) const
+{
+    const auto& rowData = m_data.at(row);
+    const auto& columnData = rowData.columns[column];
+    return columnData.location;
+}
index d6054233d9c0751d47033e79f06499546cf9e469..d91f27020659531f31c78d7fb13d5ba803c3ab36 100644 (file)
@@ -66,6 +66,8 @@ public:
 
     QColor getColumnColor(int column) const;
 
+    LocationData::Ptr getLocationData(int row, int column) const;
+
 private:
     HistogramData m_data;
 };
index d67bfa3de75a82c60426acce279c8b3b4895ed6f..45d97a5d5a66f6929b2d71bc7b10c1be5b9a9eb6 100644 (file)
@@ -17,6 +17,7 @@
  */
 
 #include "histogramwidget.h"
+#include "chartwidget.h"
 
 #include <QSortFilterProxyModel>
 #include <QVBoxLayout>
@@ -32,6 +33,8 @@
 #include <KChartGridAttributes>
 #include <KChartHeaderFooter>
 #include <KChartLegend>
+#elif defined(QWT_FOUND)
+#include <QMenu>
 #endif
 
 #ifdef NO_K_LIB
@@ -63,7 +66,6 @@ public:
 
     const QString customizedLabel(const QString& label) const override
     {
-//!!        KFormat format(QLocale::system());
         return Util::formatByteSize(label.toDouble(), 1);
     }
 };
@@ -102,7 +104,8 @@ HistogramWidget::HistogramWidget(QWidget* parent)
     , m_total(new BarDiagram(this))
     , m_detailed(new BarDiagram(this))
 #elif defined(QWT_FOUND)
-    , m_plot(new HistogramWidgetQwtPlot(this))
+    , m_plot(new HistogramWidgetQwtPlot(this, ChartOptions::GlobalOptions))
+    , m_contextMenuQwt(new ContextMenuQwt(this, true))
 #endif
 #ifdef SHOW_TABLES
     , m_tableViewTotal(new QTableView(this))
@@ -114,6 +117,8 @@ HistogramWidget::HistogramWidget(QWidget* parent)
     layout->addWidget(m_chart);
 #elif defined(QWT_FOUND)
     layout->addWidget(m_plot);
+
+    connectContextMenu();
 #endif
 #ifdef SHOW_TABLES
     auto hLayout = new QHBoxLayout();
@@ -209,11 +214,51 @@ void HistogramWidget::setModel(HistogramModel *model)
 #endif
 }
 
-#if defined(QWT_FOUND)
+void HistogramWidget::updateOnSelected()
+{
+    m_plot->setOptions(ChartOptions::GlobalOptions);
+}
+
+#ifdef QWT_FOUND
 void HistogramWidget::modelReset()
 {
     m_plot->rebuild();
 }
+
+void HistogramWidget::connectContextMenu()
+{
+    connect(m_contextMenuQwt->showTotalAction(), &QAction::triggered, this, &HistogramWidget::toggleShowTotal);
+    connect(m_contextMenuQwt->showUnresolvedAction(), &QAction::triggered, this, &HistogramWidget::toggleShowUnresolved);
+    connect(m_contextMenuQwt->exportChartAction(), &QAction::triggered, this, [=]() {
+        Util::exportChart(this, *m_plot, "Allocation Histogram");
+    });
+
+    setFocusPolicy(Qt::StrongFocus);
+}
+
+#ifndef QT_NO_CONTEXTMENU
+void HistogramWidget::contextMenuEvent(QContextMenuEvent *event)
+{
+    QMenu menu(this);
+    m_contextMenuQwt->initializeMenu(menu, m_plot->options());
+    menu.exec(event->globalPos());
+}
 #endif
 
+void HistogramWidget::keyPressEvent(QKeyEvent *event)
+{
+    m_contextMenuQwt->handleKeyPress(event);
+}
+
+void HistogramWidget::toggleShowTotal()
+{
+    ChartOptions::GlobalOptions = m_plot->toggleOption(ChartOptions::ShowTotal);
+}
+
+void HistogramWidget::toggleShowUnresolved()
+{
+    ChartOptions::GlobalOptions = m_plot->toggleOption(ChartOptions::ShowUnresolved);
+}
+#endif // QWT_FOUND
+
 #include "histogramwidget.moc"
index c05bd1317e4e38565ce0a808b5a84061b83e2e7f..f2f96629cbdf8f1cbc3690356f70414e0cd3928d 100644 (file)
@@ -20,7 +20,9 @@
 #define HISTOGRAMWIDGET_H
 
 #include "gui_config.h"
+#include "contextmenuqwt.h"
 
+#include <memory>
 #include <QWidget>
 
 //!! for debugging
@@ -50,10 +52,18 @@ public:
 
     void setModel(HistogramModel* model);
 
-#if defined(QWT_FOUND)
+    void updateOnSelected();
+
+#ifdef QWT_FOUND
 public slots:
     void modelReset();
+protected:
+#ifndef QT_NO_CONTEXTMENU
+    virtual void contextMenuEvent(QContextMenuEvent *event) override;
 #endif
+    // workaround for handling the context menu shortcuts
+    virtual void keyPressEvent(QKeyEvent *event) override;
+#endif // QWT_FOUND
 
 private:
 #if defined(KChart_FOUND)
@@ -61,7 +71,15 @@ private:
     KChart::BarDiagram* m_total;
     KChart::BarDiagram* m_detailed;
 #elif defined(QWT_FOUND)
+private slots:
+    void toggleShowTotal();
+    void toggleShowUnresolved();
+
+    void connectContextMenu();
+
+private:
     HistogramWidgetQwtPlot* m_plot;
+    std::unique_ptr<ContextMenuQwt> m_contextMenuQwt;
 #endif
 #ifdef SHOW_TABLES
     QTableView* m_tableViewTotal;
index 3c99a4b94c8c27df7d9621f825f8e727e2f5c76a..13a692e10d535dd62bc4938daa51702f90280456 100644 (file)
@@ -1,6 +1,7 @@
 #include "histogramwidgetqwtplot.h"
 #include "histogrammodel.h"
 #include "noklib.h"
+#include "util.h"
 
 #include <math.h>
 
@@ -43,6 +44,12 @@ public:
         m_barLeftRight.reserve(BarCount);
     }
 
+    void clear()
+    {
+        m_barRects.clear();
+        m_barLeftRight.clear();
+    }
+
     void setBarSize(int sampleIndex, int barIndex, const QwtColumnRect &qwtRect)
     {
         if (m_barRects.size() <= sampleIndex)
@@ -116,6 +123,13 @@ public:
         setTrackerMode(QwtPlotPicker::AlwaysOn);
     }
 
+    virtual void reset() override
+    {
+        QwtPlotPicker::reset();
+        m_totalBarSizes.clear();
+        m_barSizes.clear();
+    }
+
     BarSizes m_totalBarSizes;
     BarSizes m_barSizes;
 
@@ -123,7 +137,6 @@ protected:
     virtual QwtText trackerText(const QPoint &pos) const
     {
 //        qDebug() << "Picker: (" << pos.x() << "; " << pos.y() << ")";
-//        QString s = QString(" (%1, %2) ").arg(pos.x()).arg(pos.y());
         HistogramModel *model = m_plot->model();
         if (!model)
         {
@@ -133,13 +146,14 @@ protected:
         QString s;
         if (m_barSizes.findBar(pos, sampleIndex, barIndex))
         {
-//            s = QString("<br> Sample: %1. Bar: %2").arg(sampleIndex).arg(barIndex);
-            s = model->data(model->index(sampleIndex, barIndex + 1), Qt::ToolTipRole).toString();
+            s = m_plot->getBarText(false, sampleIndex, barIndex);
+//            s += QString("<br> Sample: %1. Bar: %2").arg(sampleIndex).arg(barIndex);
         }
-        else if (m_totalBarSizes.findBar(pos, sampleIndex, barIndex))
+        else if (m_plot->hasOption(ChartOptions::ShowTotal) &&
+                 m_totalBarSizes.findBar(pos, sampleIndex, barIndex))
         {
-//            s = QString("<br> (Total) Sample: %1. Bar: %2").arg(sampleIndex).arg(barIndex);
-            s = model->data(model->index(sampleIndex, 0), Qt::ToolTipRole).toString();
+            s = m_plot->getBarText(true, sampleIndex, barIndex);
+//            s += QString("<br> (Total) Sample: %1. Bar: %2").arg(sampleIndex).arg(barIndex);
         }
         else
         {
@@ -172,8 +186,7 @@ protected:
     virtual void drawBar( QPainter *painter, int sampleIndex,
         int barIndex, const QwtColumnRect &rect) const
     {
-//        qDebug() << "drawBar: (sampleIndex=" << sampleIndex << "; barIndex=" << barIndex
-//                 << "; " << rect.toRect() << ")";
+//        qDebug() << "drawBar: (sampleIndex=" << sampleIndex << "; barIndex=" << barIndex << "; " << rect.toRect() << ")";
         QwtPlotMultiBarChart::drawBar(painter, sampleIndex, barIndex, rect);
 
         m_barSizes->setBarSize(sampleIndex, barIndex, rect);
@@ -183,8 +196,8 @@ private:
     BarSizes *m_barSizes;
 };
 
-HistogramWidgetQwtPlot::HistogramWidgetQwtPlot(QWidget *parent)
-    : QwtPlot(parent), m_model(nullptr), m_picker(new Picker(this))
+HistogramWidgetQwtPlot::HistogramWidgetQwtPlot(QWidget *parent, Options options)
+    : QwtPlot(parent), ChartOptions(options), m_model(nullptr), m_picker(new Picker(this))
 {
     setCanvasBackground(Qt::white);
     enableAxis(QwtPlot::yRight);
@@ -193,9 +206,21 @@ HistogramWidgetQwtPlot::HistogramWidgetQwtPlot(QWidget *parent)
     setAxisTitle(QwtPlot::xBottom, i18n("Requested Allocation Size"));
 }
 
+void HistogramWidgetQwtPlot::setOptions(Options options)
+{
+    if (m_options != options)
+    {
+        m_options = options;
+        rebuild();
+    }
+}
+
 void HistogramWidgetQwtPlot::rebuild()
 {
+    const double BarLayoutHint = 0.33;
+
     detachItems();
+    m_picker->reset();
 
     if (!m_model)
     {
@@ -208,14 +233,18 @@ void HistogramWidgetQwtPlot::rebuild()
 
     setAxisAutoScale(QwtPlot::yRight);
 
-    auto totalBarChart = new MultiBarChart(&m_picker->m_totalBarSizes);
-    totalBarChart->setStyle(QwtPlotMultiBarChart::Stacked);
-    totalBarChart->setLayoutHint(0.33);
-    totalBarChart->setLayoutPolicy(QwtPlotMultiBarChart::ScaleSamplesToAxes);
+    MultiBarChart *totalBarChart = nullptr;
+    if (hasOption(ShowTotal))
+    {
+        totalBarChart = new MultiBarChart(&m_picker->m_totalBarSizes);
+        totalBarChart->setStyle(QwtPlotMultiBarChart::Stacked);
+        totalBarChart->setLayoutHint(BarLayoutHint);
+        totalBarChart->setLayoutPolicy(QwtPlotMultiBarChart::ScaleSamplesToAxes);
+    }
 
     auto barChart = new MultiBarChart(&m_picker->m_barSizes);
     barChart->setStyle(QwtPlotMultiBarChart::Stacked);
-    barChart->setLayoutHint(totalBarChart->layoutHint());
+    barChart->setLayoutHint(BarLayoutHint);
     barChart->setLayoutPolicy(QwtPlotMultiBarChart::ScaleSamplesToAxes);
 
     QVector<QString> rowNames;
@@ -228,15 +257,26 @@ void HistogramWidgetQwtPlot::rebuild()
     {
         rowNames.append(m_model->headerData(row, Qt::Vertical).toString());
 
-        QVector<double> totalValues;
-        totalValues.append(m_model->data(m_model->index(row, 0)).toDouble());
-        totalSeries.append(totalValues);
+        if (totalBarChart)
+        {
+            QVector<double> totalValues;
+            totalValues.append(m_model->data(m_model->index(row, 0)).toDouble());
+            totalSeries.append(totalValues);
+        }
 
         QVector<double> values;
         for (int column = 1; column < columns; ++column)
         {
+            if (!hasOption(ShowUnresolved))
+            {
+                LocationData::Ptr locData = m_model->getLocationData(row, column);
+                if (locData && Util::isUnresolvedFunction(locData->function))
+                {
+                    continue;
+                }
+            }
             double allocations = m_model->data(m_model->index(row, column)).toDouble();
-            if ((allocations == 0) && (column > 1))
+            if (allocations == 0) // columns are sorted by allocations descending
             {
                 break;
             }
@@ -246,10 +286,14 @@ void HistogramWidgetQwtPlot::rebuild()
                 maxColumn = column;
             }
         }
+        if (values.isEmpty())
+        {
+            values.append(0);
+        }
         series.append(values);
     }
 
-    for (int column = 0; column <= maxColumn; ++column)
+    for (int column = (totalBarChart ? 0 : 1); column <= maxColumn; ++column)
     {
         auto symbol = new QwtColumnSymbol(QwtColumnSymbol::Box);
         symbol->setLineWidth(2);
@@ -264,7 +308,13 @@ void HistogramWidgetQwtPlot::rebuild()
         }
     }
 
-    totalBarChart->setSamples(totalSeries);
+    if (totalBarChart)
+    {
+        totalBarChart->setSamples(totalSeries);
+        totalBarChart->setAxes(QwtPlot::xBottom, QwtPlot::yRight);
+        totalBarChart->attach(this);
+    }
+
     barChart->setSamples(series);
 
     auto bottomScale = new HistogramScaleDraw(rowNames);
@@ -272,9 +322,45 @@ void HistogramWidgetQwtPlot::rebuild()
     bottomScale->enableComponent(QwtScaleDraw::Ticks, false);
     setAxisScaleDraw(QwtPlot::xBottom, bottomScale);
 
-    totalBarChart->setAxes(QwtPlot::xBottom, QwtPlot::yRight);
     barChart->setAxes(QwtPlot::xBottom, QwtPlot::yRight);
 
-    totalBarChart->attach(this);
     barChart->attach(this);
+
+    replot();
+}
+
+QString HistogramWidgetQwtPlot::getBarText(bool isTotal, int sampleIndex, int barIndex) const
+{
+    QString result;
+    if (isTotal)
+    {
+        result = m_model->data(m_model->index(sampleIndex, 0), Qt::ToolTipRole).toString();
+    }
+    else
+    {
+        if (hasOption(ShowUnresolved))
+        {
+            result = m_model->data(m_model->index(sampleIndex, barIndex + 1), Qt::ToolTipRole).toString();
+        }
+        else // skip unresolved functions
+        {
+            int indexOfResolved = 0;
+            int columns = m_model->columnCount();
+            for (int column = 1; column < columns; ++column)
+            {
+                LocationData::Ptr locData = m_model->getLocationData(sampleIndex, column);
+                if (locData && Util::isUnresolvedFunction(locData->function))
+                {
+                    continue;
+                }
+                if (indexOfResolved == barIndex)
+                {
+                    result = m_model->data(m_model->index(sampleIndex, column), Qt::ToolTipRole).toString();
+                    break;
+                }
+                ++indexOfResolved;
+            }
+        }
+    }
+    return result;
 }
index 6a20014ad129a8a88b967e46018c57ad8b46af88..e42aad66fffddf75204003c6ebec95f0cf934618 100644 (file)
@@ -1,23 +1,33 @@
 #ifndef HISTOGRAMWIDGETQWTPLOT_H
 #define HISTOGRAMWIDGETQWTPLOT_H
 
+#include "chartwidgetqwtplot.h"
+
 #include <qwt_plot.h>
 
+#include <QString>
+
 class HistogramModel;
 class Picker;
 
-class HistogramWidgetQwtPlot : public QwtPlot
+class HistogramWidgetQwtPlot : public QwtPlot, public ChartOptions
 {
 public:
-    explicit HistogramWidgetQwtPlot(QWidget *parent);
+    explicit HistogramWidgetQwtPlot(QWidget *parent, Options options);
 
     void setModel(HistogramModel *model) { m_model = model; }
 
     HistogramModel *model() const { return m_model; }
 
+    virtual void setOptions(Options options) override;
+
     void rebuild();
 
 private:
+    friend class Picker;
+
+    QString getBarText(bool isTotal, int sampleIndex, int barIndex) const;
+
     HistogramModel *m_model;
 
     Picker *m_picker;
index 8d045caf1c5162e9521e0d8b81b471e07dd82bf3..6837b17ccff2a104faab25d2ff158a9899c7cd17 100644 (file)
@@ -699,9 +699,15 @@ void MainWindow::setupStacks()
             chartWidget->updateOnSelected(this);
             chartWidget->setFocus(); // to handle keyboard events in the widget
         }
-        else if (ChartWidget::HelpWindow != nullptr)
-        {
-            ChartWidget::HelpWindow->hide();
+        else {
+            if (ChartWidget::HelpWindow != nullptr) {
+                ChartWidget::HelpWindow->hide();
+            }
+            const auto histogramWidget = dynamic_cast<HistogramWidget*>(widget);
+            if (histogramWidget) {
+                histogramWidget->updateOnSelected();
+                histogramWidget->setFocus();
+            }
         }
 #endif
     };
@@ -711,7 +717,7 @@ void MainWindow::setupStacks()
     m_ui->stacksDock->setVisible(false);
 }
 
-#if defined(QWT_FOUND)
+#ifdef QWT_FOUND
 void MainWindow::moveEvent(QMoveEvent *event)
 {
     if (ChartWidget::HelpWindow != nullptr)
index 2f09d10cfc7945f8d7d48c3edee0dc963eb0e4bf..67751ffabe1f56eaf2503bfe172afd5fbb170447 100644 (file)
@@ -50,7 +50,7 @@ public slots:
 signals:
     void clearData();
 
-#if defined(QWT_FOUND)
+#ifdef QWT_FOUND
 protected:
     virtual void moveEvent(QMoveEvent *event) override;
 #endif
index 00ea260890eeedb4f289dde09a376ecf61d0521a..6d896c65c4fe12bd2f62db22d9b3c1f8987cf267 100644 (file)
 #include <KFormat>
 #endif
 
-QString Util::formatTime(qint64 ms)
+#ifdef QWT_FOUND
+#include <QFileDialog>
+#include <QFileInfo>
+#include <QMessageBox>
+#endif
+
+namespace Util {
+
+QString formatTime(qint64 ms)
 {
     if (ms > 60000) {
         // minutes
@@ -36,7 +44,7 @@ QString Util::formatTime(qint64 ms)
     }
 }
 
-QString Util::formatByteSize(double size, int precision)
+QString formatByteSize(double size, int precision)
 {
 #ifndef NO_K_LIB
     static KFormat format;
@@ -87,7 +95,7 @@ QString Util::formatByteSize(double size, int precision)
 #endif
 }
 
-QString Util::wrapLabel(QString label, int maxLineLength, int lastLineExtra,
+QString wrapLabel(QString label, int maxLineLength, int lastLineExtra,
     const QString& delimiter)
 {
     int labelLength = label.size();
@@ -146,3 +154,46 @@ QString Util::wrapLabel(QString label, int maxLineLength, int lastLineExtra,
     result += label.toHtmlEscaped();
     return result;
 }
+
+#ifdef QWT_FOUND
+bool isUnresolvedFunction(const QString &functionName)
+{
+    return functionName.startsWith("<unresolved function>");
+}
+
+bool exportChart(QWidget *parent, QWidget &chartWidget, const QString &chartName)
+{
+    QString selectedFilter;
+    QString saveFilename = QFileDialog::getSaveFileName(parent, "Save Chart As",
+        chartName, "PNG (*.png);; BMP (*.bmp);; JPEG (*.jpg *.jpeg)", &selectedFilter);
+    if (!saveFilename.isEmpty())
+    {
+        QFileInfo fi(saveFilename);
+        if (fi.suffix().isEmpty()) // can be on some platforms
+        {
+            int i = selectedFilter.indexOf("*.");
+            if (i >= 0)
+            {
+                static QRegularExpression delimiters("[ )]");
+                i += 2;
+                int j = selectedFilter.indexOf(delimiters, i);
+                if (j > i)
+                {
+                    --i;
+                    QString suffix = selectedFilter.mid(i, j - i);
+                    saveFilename += suffix;
+                }
+            }
+        }
+        if (chartWidget.grab().save(saveFilename))
+        {
+            return true;
+        }
+    }
+    QMessageBox::warning(parent, "Error",
+        QString("Cannot save the chart to \"%1\".").arg(saveFilename), QMessageBox::Ok);
+    return false;
+}
+#endif
+
+} // namespace Util
index 7f651a0b5b4cfb993c049bd6257f66082563212b..f2dfaa5ae03f8687de56b825a1da94bc69777a59 100644 (file)
 #ifndef UTIL_H
 #define UTIL_H
 
+#include "gui_config.h"
+
 #include <qglobal.h>
 #include <QString>
 
+#ifdef QWT_FOUND
+#include <QWidget>
+#endif
+
 namespace Util {
 
 QString formatTime(qint64 ms);
@@ -31,6 +37,11 @@ QString formatByteSize(double size, int precision = 1);
 QString wrapLabel(QString label, int maxLineLength, int lastLineExtra = 0,
                   const QString &delimiter = QString("<br>"));
 
+#ifdef QWT_FOUND
+bool isUnresolvedFunction(const QString &functionName);
+
+bool exportChart(QWidget *parent, QWidget &chartWidget, const QString &chartName);
+#endif
 }
 
 #endif // UTIL_H