help window for charts (QWT) added; export charts (QWT) to files implemented
authorAlexey Chernobaev <achernobaev@dev.rtsoft.ru>
Thu, 22 Mar 2018 19:14:12 +0000 (22:14 +0300)
committerAlexey Chernobaev <achernobaev@dev.rtsoft.ru>
Thu, 22 Mar 2018 19:14:12 +0000 (22:14 +0300)
src/analyze/gui/chartwidget.cpp
src/analyze/gui/chartwidget.h
src/analyze/gui/chartwidgetqwtplot.cpp
src/analyze/gui/chartwidgetqwtplot.h
src/analyze/gui/mainwindow.cpp
src/analyze/gui/mainwindow.h

index 52dad56c1de3babe7652353789ef5e94926fc824..ef9f960af2b07dfd0f9cd9c3aec2a1e673e89ee3 100644 (file)
@@ -18,6 +18,9 @@
 
 #include "chartwidget.h"
 
+#include <QMainWindow>
+#include <QTextEdit>
+#include <QToolTip>
 #include <QVBoxLayout>
 
 #if defined(KChart_FOUND)
@@ -35,6 +38,8 @@
 #include <QAction>
 #include <QContextMenuEvent>
 #include <QMenu>
+#include <QMessageBox>
+#include <QFileDialog>
 #endif
 
 #ifdef NO_K_LIB
@@ -84,17 +89,67 @@ public:
 };
 }
 #elif defined(QWT_FOUND)
-ChartWidgetQwtPlot::Options ChartWidget::globalOptions(
+class HelpWidget : public QMainWindow
+{
+    Q_OBJECT
+public:
+    explicit HelpWidget(QWidget *parent) : QMainWindow(parent)
+    {
+        setWindowTitle("Chart Help");
+        setWindowFlags(Qt::Tool);
+        setAttribute(Qt::WA_ShowWithoutActivating);
+        setAttribute(Qt::WA_DeleteOnClose);
+        setGeometry(0, 0, 292, 164);
+        setMinimumSize(100, 70);
+        setMaximumSize(400, 280);
+        setPalette(QToolTip::palette());
+        setWindowOpacity(0.9);
+        setAutoFillBackground(true);
+        auto textEdit = new QTextEdit(this);
+        textEdit->setReadOnly(true);
+        textEdit->setContextMenuPolicy(Qt::NoContextMenu);
+        textEdit->viewport()->setAutoFillBackground(false);
+        setCentralWidget(textEdit);
+        textEdit->setHtml(
+            "<p>Use <u>Context Menu</u> (right click inside the chart to open) to control different chart options.</p>" \
+            "<p>Use <u>left mouse button</u> to <b>zoom in</b> to selection: press the button, drag " \
+            "to make a rectangular selection, release.</p>" \
+            "<p>Use <u>left mouse button</u> with modifier keys to:</p>" \
+            "<ul>" \
+            "<li><b>zoom out</b> (one step back) - <b>&lt;Shift&gt;</b>+click;" \
+            "<li><b>reset zoom</b> - <b>&lt;Ctrl&gt;</b>+click;" \
+            "<li><b>move (pan)</b> the chart  - <b>&lt;Alt&gt;</b>+drag." \
+            "</ul>");
+    }
+
+    virtual ~HelpWidget()
+    {
+        ChartWidget::HelpWindow = nullptr;
+    }
+protected:
+    virtual void closeEvent(QCloseEvent *event) override
+    {
+        QMainWindow::closeEvent(event);
+        ChartWidget::GlobalOptions = ChartWidgetQwtPlot::setOption(ChartWidget::GlobalOptions,
+            ChartWidgetQwtPlot::ShowHelp, false);
+    }
+};
+
+ChartWidgetQwtPlot::Options ChartWidget::GlobalOptions(
+    ChartWidgetQwtPlot::ShowHelp |
     ChartWidgetQwtPlot::ShowTotal | ChartWidgetQwtPlot::ShowUnresolved |
     ChartWidgetQwtPlot::ShowLegend | ChartWidgetQwtPlot::ShowCurveBorders);
-#endif
+
+QWidget* ChartWidget::HelpWindow;
+QWidget* ChartWidget::MainWindow;
+#endif // QWT_FOUND
 
 ChartWidget::ChartWidget(QWidget* parent)
     : 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, GlobalOptions))
 #endif
 #ifdef SHOW_TABLES
     , m_tableViewTotal(new QTableView(this))
@@ -130,6 +185,16 @@ ChartWidget::ChartWidget(QWidget* parent)
 ChartWidget::~ChartWidget() = default;
 
 #ifdef QWT_FOUND
+void ChartWidget::updateOnSelected(QWidget *mainWindow)
+{
+    MainWindow = mainWindow;
+    m_plot->setOptions(GlobalOptions);
+    if (m_plot->hasOption(ChartWidgetQwtPlot::ShowHelp))
+    {
+        showHelp();
+    }
+}
+
 void ChartWidget::createActions()
 {
     m_resetZoomAction = new QAction(i18n("Reset Zoom and Pan"), this);
@@ -151,10 +216,10 @@ void ChartWidget::createActions()
     m_showLegendAction->setCheckable(true);
     connect(m_showLegendAction, &QAction::triggered, this, &ChartWidget::toggleShowLegend);
 
-    m_showCurveBorders = new QAction(i18n("Show Curve &Borders"), this);
-    m_showCurveBorders->setStatusTip(i18n("Show curve borders (as black lines)"));
-    m_showCurveBorders->setCheckable(true);
-    connect(m_showCurveBorders, &QAction::triggered, this, &ChartWidget::toggleShowCurveBorders);
+    m_showCurveBordersAction = new QAction(i18n("Show Curve &Borders"), this);
+    m_showCurveBordersAction->setStatusTip(i18n("Show curve borders (as black lines)"));
+    m_showCurveBordersAction->setCheckable(true);
+    connect(m_showCurveBordersAction, &QAction::triggered, this, &ChartWidget::toggleShowCurveBorders);
 
     m_showSymbolsAction = new QAction(i18n("Show &Symbols"), this);
     m_showSymbolsAction->setStatusTip(i18n("Show symbols (the chart data points)"));
@@ -166,6 +231,15 @@ void ChartWidget::createActions()
     m_showVLinesAction->setCheckable(true);
     connect(m_showVLinesAction, &QAction::triggered, this, &ChartWidget::toggleShowVLines);
 
+    m_exportChartAction = new QAction(i18n("&Export Chart..."), this);
+    m_exportChartAction->setStatusTip(i18n("Export the current chart to a file."));
+    connect(m_exportChartAction, &QAction::triggered, this, &ChartWidget::exportChart);
+
+    m_showHelpAction = new QAction(i18n("Show Chart &Help"), this);
+    m_showHelpAction->setStatusTip(i18n("Show a window with breif help information inside the chart."));
+    m_showHelpAction->setCheckable(true);
+    connect(m_showHelpAction, &QAction::triggered, this, &ChartWidget::toggleShowHelp);
+
     // shortcuts don't work under Windows (Qt 5.10.0) so using a workaround (manual processing
     // in keyPressEvent)
 
@@ -173,17 +247,19 @@ void ChartWidget::createActions()
     m_showTotalAction->setShortcut(QKeySequence(Qt::ALT | Qt::Key_T));
     m_showUnresolvedAction->setShortcut(QKeySequence(Qt::ALT | Qt::Key_U));
     m_showLegendAction->setShortcut(QKeySequence(Qt::ALT | Qt::Key_L));
-    m_showCurveBorders->setShortcut(QKeySequence(Qt::ALT | Qt::Key_B));
+    m_showCurveBordersAction->setShortcut(QKeySequence(Qt::ALT | Qt::Key_B));
     m_showSymbolsAction->setShortcut(QKeySequence(Qt::ALT | Qt::Key_S));
     m_showVLinesAction->setShortcut(QKeySequence(Qt::ALT | Qt::Key_V));
+    m_exportChartAction->setShortcut(QKeySequence(Qt::ALT | Qt::Key_E));
 #if QT_VERSION >= 0x050A00
     m_resetZoomAction->setShortcutVisibleInContextMenu(true);
     m_showTotalAction->setShortcutVisibleInContextMenu(true);
     m_showUnresolvedAction->setShortcutVisibleInContextMenu(true);
     m_showLegendAction->setShortcutVisibleInContextMenu(true);
-    m_showCurveBorders->setShortcutVisibleInContextMenu(true);
     m_showSymbolsAction->setShortcutVisibleInContextMenu(true);
     m_showVLinesAction->setShortcutVisibleInContextMenu(true);
+    m_showCurveBordersAction->setShortcutVisibleInContextMenu(true);
+    m_exportChartAction->setShortcutVisibleInContextMenu(true);
 #endif
     setFocusPolicy(Qt::StrongFocus);
 }
@@ -332,12 +408,17 @@ void ChartWidget::contextMenuEvent(QContextMenuEvent *event)
     menu.addSeparator();
     m_showLegendAction->setChecked(m_plot->hasOption(ChartWidgetQwtPlot::ShowLegend));
     menu.addAction(m_showLegendAction);
-    m_showCurveBorders->setChecked(m_plot->hasOption(ChartWidgetQwtPlot::ShowCurveBorders));
-    menu.addAction(m_showCurveBorders);
+    m_showCurveBordersAction->setChecked(m_plot->hasOption(ChartWidgetQwtPlot::ShowCurveBorders));
+    menu.addAction(m_showCurveBordersAction);
     m_showSymbolsAction->setChecked(m_plot->hasOption(ChartWidgetQwtPlot::ShowSymbols));
     menu.addAction(m_showSymbolsAction);
     m_showVLinesAction->setChecked(m_plot->hasOption(ChartWidgetQwtPlot::ShowVLines));
     menu.addAction(m_showVLinesAction);
+    menu.addSeparator();
+    menu.addAction(m_exportChartAction);
+    menu.addSeparator();
+    m_showHelpAction->setChecked(ChartWidgetQwtPlot::hasOption(GlobalOptions, ChartWidgetQwtPlot::ShowHelp));
+    menu.addAction(m_showHelpAction);
     menu.exec(event->globalPos());
 }
 #endif
@@ -369,6 +450,9 @@ void ChartWidget::keyPressEvent(QKeyEvent *event)
         case Qt::Key_V:
             toggleShowVLines(!m_plot->hasOption(ChartWidgetQwtPlot::ShowVLines));
             break;
+        case Qt::Key_E:
+            exportChart();
+            break;
         default:
             event->ignore();
             return;
@@ -381,11 +465,6 @@ void ChartWidget::keyPressEvent(QKeyEvent *event)
     }
 }
 
-void ChartWidget::updateIfOptionsChanged()
-{
-    m_plot->setOptions(globalOptions);
-}
-
 void ChartWidget::resetZoom()
 {
     m_plot->resetZoom();
@@ -393,32 +472,75 @@ void ChartWidget::resetZoom()
 
 void ChartWidget::toggleShowTotal(bool checked)
 {
-    globalOptions = m_plot->setOption(ChartWidgetQwtPlot::ShowTotal, checked);
+    GlobalOptions = m_plot->setOption(ChartWidgetQwtPlot::ShowTotal, checked);
 }
 
 void ChartWidget::toggleShowUnresolved(bool checked)
 {
-    globalOptions = m_plot->setOption(ChartWidgetQwtPlot::ShowUnresolved, checked);
+    GlobalOptions = m_plot->setOption(ChartWidgetQwtPlot::ShowUnresolved, checked);
 }
 
 void ChartWidget::toggleShowLegend(bool checked)
 {
-    globalOptions = m_plot->setOption(ChartWidgetQwtPlot::ShowLegend, checked);
+    GlobalOptions = m_plot->setOption(ChartWidgetQwtPlot::ShowLegend, checked);
 }
 
 void ChartWidget::toggleShowCurveBorders(bool checked)
 {
-    globalOptions = m_plot->setOption(ChartWidgetQwtPlot::ShowCurveBorders, checked);
+    GlobalOptions = m_plot->setOption(ChartWidgetQwtPlot::ShowCurveBorders, checked);
 }
 
 void ChartWidget::toggleShowSymbols(bool checked)
 {
-    globalOptions = m_plot->setOption(ChartWidgetQwtPlot::ShowSymbols, checked);
+    GlobalOptions = m_plot->setOption(ChartWidgetQwtPlot::ShowSymbols, checked);
 }
 
 void ChartWidget::toggleShowVLines(bool checked)
 {
-    globalOptions = m_plot->setOption(ChartWidgetQwtPlot::ShowVLines, checked);
+    GlobalOptions = m_plot->setOption(ChartWidgetQwtPlot::ShowVLines, checked);
+}
+
+void ChartWidget::toggleShowHelp(bool checked)
+{
+    if (checked)
+    {
+        showHelp();
+    }
+    else
+    {
+        if (HelpWindow != nullptr)
+        {
+            delete HelpWindow;
+            HelpWindow = nullptr;
+        }
+    }
+    GlobalOptions = ChartWidgetQwtPlot::setOption(GlobalOptions, ChartWidgetQwtPlot::ShowHelp, checked);
+}
+
+void ChartWidget::showHelp()
+{
+    if (HelpWindow == nullptr)
+    {
+        HelpWindow = new HelpWidget(MainWindow);
+        QPoint p = mapToGlobal(pos());
+        HelpWindow->move(p.x() + 32, p.y() + 32);
+    }
+    HelpWindow->show();
+}
+
+void ChartWidget::exportChart()
+{
+    QString saveFilename = QFileDialog::getSaveFileName(this, "Save Chart As",
+        m_plot->model()->headerData(1, Qt::Horizontal).toString(),
+        "PNG (*.png);; TIFF (*.tif *.tiff);; JPEG (*.jpg *.jpeg)");
+    if (!saveFilename.isEmpty())
+    {
+        if (!m_plot->grab().save(saveFilename))
+        {
+            QMessageBox::warning(this, "Error",
+                QString("Cannot save the chart to \"%1\".").arg(saveFilename), QMessageBox::Ok);
+        }
+    }
 }
 #endif // QWT_FOUND
 
index 05f01f63baed11d93e90c74e6f832f289fbb792b..7bda4802a2882a1294150bafdbb77930531affd5 100644 (file)
@@ -55,7 +55,11 @@ public:
     QSize sizeHint() const override;
 
 #if defined(QWT_FOUND)
-    void updateIfOptionsChanged();
+    void updateOnSelected(QWidget *mainWindow);
+
+    static ChartWidgetQwtPlot::Options GlobalOptions;
+    static QWidget* HelpWindow;
+    static QWidget* MainWindow;
 
 public slots:
     void modelReset();
@@ -79,9 +83,13 @@ private slots:
     void toggleShowCurveBorders(bool checked);
     void toggleShowSymbols(bool checked);
     void toggleShowVLines(bool checked);
+    void toggleShowHelp(bool checked);
+    void exportChart();
 private:
     void createActions();
 
+    void showHelp();
+
     ChartWidgetQwtPlot* m_plot;
 
     QAction* m_resetZoomAction;
@@ -90,9 +98,9 @@ private:
     QAction* m_showLegendAction;
     QAction* m_showSymbolsAction;
     QAction* m_showVLinesAction;
-    QAction* m_showCurveBorders;
-
-    static ChartWidgetQwtPlot::Options globalOptions;
+    QAction* m_showCurveBordersAction;
+    QAction* m_exportChartAction;
+    QAction* m_showHelpAction;
 #endif // QWT_FOUND, KChart_FOUND
 #ifdef SHOW_TABLES
     QTableView* m_tableViewTotal;
index e1ba57ecaf6e75d44b8185e391e24e310a84c6d5..82f09194fdc1725884771c7057832848eb111df0 100644 (file)
@@ -102,15 +102,13 @@ ChartWidgetQwtPlot::ChartWidgetQwtPlot(QWidget *parent, Options options)
     enableAxis(QwtPlot::yRight);
     enableAxis(QwtPlot::yLeft, false);
 
-    // TODO!! show help about zooming and panning
-
-    // LeftButton for the zooming
+    // LeftButton for zooming
     // Shift+LeftButton: zoom out by 1
     // Ctrl+LeftButton: zoom out to full size
     m_zoomer->setMousePattern(QwtEventPattern::MouseSelect2, Qt::LeftButton, Qt::ControlModifier);
     m_zoomer->setMousePattern(QwtEventPattern::MouseSelect3, Qt::LeftButton, Qt::ShiftModifier);
 
-    // Alt+LeftButton for the panning
+    // Alt+LeftButton for panning
     auto panner = new QwtPlotPanner(canvas());
     panner->setMouseButton(Qt::LeftButton, Qt::AltModifier);
 
@@ -127,9 +125,14 @@ void ChartWidgetQwtPlot::setModel(ChartModel* model)
           model->type() == ChartModel::Temporary);
 }
 
+ChartWidgetQwtPlot::Options ChartWidgetQwtPlot::setOption(Options options, Options option, bool isOn)
+{
+    return (isOn ? (options | option) : Options(options & ~option));
+}
+
 ChartWidgetQwtPlot::Options ChartWidgetQwtPlot::setOption(Options option, bool isOn)
 {
-    setOptions(isOn ? (m_options | option) : Options(m_options & ~option));
+    setOptions(setOption(m_options, option, isOn));
     return m_options;
 }
 
index d1c5d724647cf700a6abcd8d8e601fc58e97b826..ac17d452098c8b83735f080ef309e7c049fc03a9 100644 (file)
@@ -15,8 +15,9 @@ public:
     enum Options
     {
         None = 0,
-        ShowTotal = 0x01,
-        ShowUnresolved = 0x02,
+        ShowHelp = 0x01,
+        ShowTotal = 0x02,
+        ShowUnresolved = 0x04,
         ShowLegend = 0x10,
         ShowCurveBorders = 0x20,
         ShowSymbols = 0x40,
@@ -27,11 +28,17 @@ public:
 
     void setModel(ChartModel* model);
 
+    ChartModel* model() const { return m_model; }
+
     bool isSizeModel() const { return m_isSizeModel; }
 
     Options options() const { return m_options; }
 
-    bool hasOption(Options option) const { return (m_options & option) != 0; }
+    static bool hasOption(Options options, Options option) { return (options & option) != 0; }
+
+    bool hasOption(Options option) const { return hasOption(m_options, option); }
+
+    static Options setOption(Options options, Options option, bool isOn);
 
     Options setOption(Options option, bool isOn);
 
index cc1ffdf7b03cc55d913d6c2bdc2dd64e9f221534..8d045caf1c5162e9521e0d8b81b471e07dd82bf3 100644 (file)
@@ -39,6 +39,7 @@
 #include <QDesktopServices>
 #include <QFileDialog>
 #include <QMenu>
+#include <QMoveEvent>
 #include <QStatusBar>
 
 #include "../accumulatedtracedata.h"
@@ -695,9 +696,13 @@ void MainWindow::setupStacks()
 #ifdef QWT_FOUND
         const auto chartWidget = dynamic_cast<ChartWidget*>(widget);
         if (chartWidget) {
-            chartWidget->updateIfOptionsChanged();
+            chartWidget->updateOnSelected(this);
             chartWidget->setFocus(); // to handle keyboard events in the widget
         }
+        else if (ChartWidget::HelpWindow != nullptr)
+        {
+            ChartWidget::HelpWindow->hide();
+        }
 #endif
     };
     connect(m_ui->tabWidget, &QTabWidget::currentChanged, this, tabChanged);
@@ -705,3 +710,14 @@ void MainWindow::setupStacks()
 
     m_ui->stacksDock->setVisible(false);
 }
+
+#if defined(QWT_FOUND)
+void MainWindow::moveEvent(QMoveEvent *event)
+{
+    if (ChartWidget::HelpWindow != nullptr)
+    {
+        ChartWidget::HelpWindow->move(ChartWidget::HelpWindow->pos() +
+                                      (event->pos() - event->oldPos()));
+    }
+}
+#endif
index a6900e2c33b4c86c015eef25ef210b3e6e582cd4..2f09d10cfc7945f8d7d48c3edee0dc963eb0e4bf 100644 (file)
@@ -19,6 +19,8 @@
 #ifndef MAINWINDOW_H
 #define MAINWINDOW_H
 
+#include "gui_config.h"
+
 #include <QMainWindow>
 
 #ifndef NO_K_LIB
@@ -48,6 +50,10 @@ public slots:
 signals:
     void clearData();
 
+#if defined(QWT_FOUND)
+protected:
+    virtual void moveEvent(QMoveEvent *event) override;
+#endif
 private:
     void showError(const QString& message);
     void setupStacks();