]> sigrok.org Git - pulseview.git/commitdiff
Implement annotation export from the DecodeTrace context menu
authorSoeren Apel <redacted>
Sun, 5 Aug 2018 16:18:22 +0000 (18:18 +0200)
committerUwe Hermann <redacted>
Tue, 21 Aug 2018 10:02:38 +0000 (12:02 +0200)
pv/views/trace/decodetrace.cpp
pv/views/trace/decodetrace.hpp
pv/views/trace/view.cpp
pv/views/trace/viewitem.cpp
pv/views/trace/viewitem.hpp

index 9eeea1c29ec20beaa7139eb8ea1d9b835754b109..300fd2ecddbb5759f908f64f0a3255944a746939 100644 (file)
@@ -21,6 +21,7 @@ extern "C" {
 #include <libsigrokdecode/libsigrokdecode.h>
 }
 
+#include <climits>
 #include <mutex>
 #include <tuple>
 
@@ -31,10 +32,13 @@ extern "C" {
 #include <QAction>
 #include <QApplication>
 #include <QComboBox>
+#include <QFileDialog>
 #include <QFormLayout>
 #include <QLabel>
 #include <QMenu>
+#include <QMessageBox>
 #include <QPushButton>
+#include <QTextStream>
 #include <QToolTip>
 
 #include "decodetrace.hpp"
@@ -321,6 +325,39 @@ QMenu* DecodeTrace::create_header_context_menu(QWidget *parent)
        return menu;
 }
 
+QMenu* DecodeTrace::create_view_context_menu(QWidget *parent, QPoint &click_pos)
+{
+       try {
+               selected_row_ = &visible_rows_[get_row_at_point(click_pos)];
+       } catch (out_of_range&) {
+               selected_row_ = nullptr;
+       }
+
+       const pair<uint64_t, uint64_t> sample_range =
+               get_sample_range(click_pos.x(), click_pos.x() + 1);
+       selected_samplepos_ = sample_range.first;
+
+       QMenu *const menu = new QMenu(parent);
+
+       QAction *const export_row =
+                       new QAction(tr("Export all annotations for this row"), this);
+       export_row->setIcon(QIcon::fromTheme("document-save-as",
+               QIcon(":/icons/document-save-as.png")));
+       connect(export_row, SIGNAL(triggered()),
+               this, SLOT(on_export_row()));
+       menu->addAction(export_row);
+
+       QAction *const export_row_from_here =
+               new QAction(tr("Export annotations for this row, starting here"), this);
+       export_row_from_here->setIcon(QIcon::fromTheme("document-save-as",
+               QIcon(":/icons/document-save-as.png")));
+       connect(export_row_from_here, SIGNAL(triggered()),
+               this, SLOT(on_export_row_from_here()));
+       menu->addAction(export_row_from_here);
+
+       return menu;
+}
+
 void DecodeTrace::draw_annotations(vector<pv::data::decode::Annotation> annotations,
                QPainter &p, int h, const ViewItemPaintParams &pp, int y,
                QColor row_color, int row_title_width)
@@ -699,7 +736,7 @@ const QString DecodeTrace::get_annotation_at_point(const QPoint &point)
        if (row < 0)
                return QString();
 
-       vector<pv::data::decode::Annotation> annotations;
+       vector<Annotation> annotations;
 
        decode_signal_->get_annotation_subset(annotations, visible_rows_[row],
                current_segment_, sample_range.first, sample_range.second);
@@ -983,6 +1020,55 @@ void DecodeTrace::on_show_hide_decoder(int index)
                owner_->row_item_appearance_changed(false, true);
 }
 
+void DecodeTrace::on_export_row()
+{
+       selected_samplepos_ = 0;
+       on_export_row_from_here();
+}
+
+void DecodeTrace::on_export_row_from_here()
+{
+       using namespace pv::data::decode;
+
+       if (!selected_row_)
+               return;
+
+       vector<Annotation> annotations;
+
+       decode_signal_->get_annotation_subset(annotations, *selected_row_,
+               current_segment_, selected_samplepos_, ULLONG_MAX);
+
+       if (annotations.empty())
+               return;
+
+       QSettings settings;
+       const QString dir = settings.value(SettingSaveDirectory).toString();
+
+       const QString file_name = QFileDialog::getSaveFileName(
+               owner_->view(), tr("Export annotations"), dir, tr("Text Files (*.txt);;All Files (*)"));
+
+       if (file_name.isEmpty())
+               return;
+
+       QFile file(file_name);
+       if (file.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text)) {
+               QTextStream out_stream(&file);
+
+               for (Annotation &ann : annotations)
+                       out_stream << ann.annotations().front() << '\n';
+
+               if (out_stream.status() == QTextStream::Ok)
+                       return;
+       }
+
+       QMessageBox msg(owner_->view());
+       msg.setText(tr("Error"));
+       msg.setInformativeText(tr("File %1 could not be written to.").arg(file_name));
+       msg.setStandardButtons(QMessageBox::Ok);
+       msg.setIcon(QMessageBox::Warning);
+       msg.exec();
+}
+
 } // namespace trace
 } // namespace views
 } // namespace pv
index 4d9e59c162b7484d2c748dbfb2afd492f5f7be25..8f8765c17dc8857423901e353e9d574282f84960 100644 (file)
@@ -120,6 +120,8 @@ public:
 
        QMenu* create_header_context_menu(QWidget *parent);
 
+       virtual QMenu* create_view_context_menu(QWidget *parent, QPoint &click_pos);
+
        void delete_pressed();
 
 private:
@@ -198,6 +200,9 @@ private Q_SLOTS:
 
        void on_show_hide_decoder(int index);
 
+       void on_export_row();
+       void on_export_row_from_here();
+
 private:
        pv::Session &session_;
        shared_ptr<data::DecodeSignal> decode_signal_;
@@ -208,6 +213,9 @@ private:
        map<QComboBox*, uint16_t> init_state_map_;  // init state selector -> decode channel ID
        list< shared_ptr<pv::binding::Decoder> > bindings_;
 
+       data::decode::Row *selected_row_;
+       uint64_t selected_samplepos_;
+
        vector<pv::widgets::DecoderGroupBox*> decoder_forms_;
 
        map<data::decode::Row, int> row_title_widths_;
index 99e75bfdc9ec72de6281d86b3d922e626a5911a5..1e4f07aa3ddab2fa3f0861881c5b50709e1e75f7 100644 (file)
@@ -1254,11 +1254,13 @@ bool View::eventFilter(QObject *object, QEvent *event)
 
 void View::contextMenuEvent(QContextMenuEvent *event)
 {
-       const shared_ptr<ViewItem> r = viewport_->get_mouse_over_item(event->pos());
+       QPoint pos = event->pos() - QPoint(0, ruler_->sizeHint().height());
+
+       const shared_ptr<ViewItem> r = viewport_->get_mouse_over_item(pos);
        if (!r)
                return;
 
-       QMenu *menu = r->create_view_context_menu(this);
+       QMenu *menu = r->create_view_context_menu(this, pos);
        if (menu)
                menu->exec(event->globalPos());
 }
index ee0720ea6064dd12538bd0bbec10e9c68daaf72b..43c9ca2673de149ed6fcbdf50a4e7cec9ee723e1 100644 (file)
@@ -88,9 +88,10 @@ QMenu* ViewItem::create_header_context_menu(QWidget *parent)
        return new QMenu(parent);
 }
 
-QMenu* ViewItem::create_view_context_menu(QWidget *parent)
+QMenu* ViewItem::create_view_context_menu(QWidget *parent, QPoint &click_pos)
 {
        (void)parent;
+       (void)click_pos;
        return nullptr;
 }
 
index e07b26b87912cc1f072c1f4fd12e2eff2cdbe9df..89a57e5edeb248b2dab9b59618cab71b9d268667 100644 (file)
@@ -23,6 +23,7 @@
 #include <list>
 
 #include <QPen>
+#include <QPoint>
 
 #include "viewitempaintparams.hpp"
 
@@ -157,7 +158,7 @@ public:
 public:
        virtual QMenu* create_header_context_menu(QWidget *parent);
 
-       virtual QMenu* create_view_context_menu(QWidget *parent);
+       virtual QMenu* create_view_context_menu(QWidget *parent, QPoint &click_pos);
 
        virtual pv::widgets::Popup* create_popup(QWidget *parent);