Fix #1457 by adding markers, cursors and zero offset to session setup
authorSoeren Apel <soeren@apelpie.net>
Mon, 27 Jan 2020 16:50:38 +0000 (17:50 +0100)
committerSoeren Apel <soeren@apelpie.net>
Tue, 28 Jan 2020 20:46:49 +0000 (21:46 +0100)
pv/globalsettings.cpp
pv/globalsettings.hpp
pv/session.cpp
pv/views/trace/flag.cpp
pv/views/trace/flag.hpp
pv/views/trace/ruler.cpp
pv/views/trace/ruler.hpp
pv/views/trace/timemarker.cpp
pv/views/trace/timemarker.hpp
pv/views/trace/view.cpp
pv/views/trace/view.hpp

index 614b983c40a45418fb6b986c367fd2fad2227ee9..10b344a4aa4bb156e6f52163cf5c7085c7a60866 100644 (file)
@@ -17,8 +17,9 @@
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "globalsettings.hpp"
-#include "application.hpp"
+#include <boost/archive/text_iarchive.hpp>
+#include <boost/archive/text_oarchive.hpp>
+#include <boost/serialization/serialization.hpp>
 
 #include <QApplication>
 #include <QColor>
 #include <QStyle>
 #include <QtGlobal>
 
+#include "globalsettings.hpp"
+#include "application.hpp"
+
 using std::map;
 using std::pair;
 using std::string;
+using std::stringstream;
 using std::vector;
 
 namespace pv {
@@ -370,4 +375,28 @@ Glib::VariantBase GlobalSettings::restore_variantbase(QSettings &settings)
        return ret_val;
 }
 
+void GlobalSettings::store_timestamp(QSettings &settings, const char *name, const pv::util::Timestamp &ts)
+{
+       stringstream ss;
+       boost::archive::text_oarchive oa(ss);
+       oa << boost::serialization::make_nvp(name, ts);
+       settings.setValue(name, QString::fromStdString(ss.str()));
+}
+
+pv::util::Timestamp GlobalSettings::restore_timestamp(QSettings &settings, const char *name)
+{
+       util::Timestamp result;
+       stringstream ss;
+       ss << settings.value(name).toString().toStdString();
+
+       try {
+               boost::archive::text_iarchive ia(ss);
+               ia >> boost::serialization::make_nvp(name, result);
+       } catch (boost::archive::archive_exception&) {
+               qDebug() << "Could not restore setting" << name;
+       }
+
+       return result;
+}
+
 } // namespace pv
index adb9168a1fbc3be027db6f7ee16df0930b501de4..cf1921e89ea52b551f3ca46a85102b04a9dbf502 100644 (file)
@@ -30,6 +30,8 @@
 #include <QString>
 #include <QVariant>
 
+#include "util.hpp"
+
 using std::map;
 using std::pair;
 using std::vector;
@@ -122,13 +124,14 @@ public:
        void undo_tracked_changes();
 
        static void store_gvariant(QSettings &settings, GVariant *v);
-
        static GVariant* restore_gvariant(QSettings &settings);
 
        static void store_variantbase(QSettings &settings, Glib::VariantBase v);
-
        static Glib::VariantBase restore_variantbase(QSettings &settings);
 
+       static void store_timestamp(QSettings &settings, const char *name, const pv::util::Timestamp &ts);
+       static pv::util::Timestamp restore_timestamp(QSettings &settings, const char *name);
+
 private:
        static vector<GlobalSettingsInterface*> callbacks_;
 
index 589ec333a24c35bfbe02f47b8e393970f4370f42..b3f8ba87de7e31aa57bbc7dba5b4687fd45557f7 100644 (file)
@@ -17,9 +17,6 @@
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <QDebug>
-#include <QFileInfo>
-
 #include <cassert>
 #include <memory>
 #include <mutex>
 
 #include <sys/stat.h>
 
+#include <QDebug>
+#include <QFileInfo>
+
 #include "devicemanager.hpp"
 #include "mainwindow.hpp"
 #include "session.hpp"
+#include "util.hpp"
 
 #include "data/analog.hpp"
 #include "data/analogsegment.hpp"
@@ -105,6 +106,7 @@ using Gst::ElementFactory;
 using Gst::Pipeline;
 #endif
 
+using pv::util::Timestamp;
 using pv::views::trace::Signal;
 using pv::views::trace::AnalogSignal;
 using pv::views::trace::LogicSignal;
@@ -193,13 +195,13 @@ bool Session::data_saved() const
 
 void Session::save_setup(QSettings &settings) const
 {
-       int decode_signals = 0, views = 0;
+       int i = 0;
 
        // Save channels and decoders
        for (const shared_ptr<data::SignalBase>& base : signalbases_) {
 #ifdef ENABLE_DECODE
                if (base->is_decode_signal()) {
-                       settings.beginGroup("decode_signal" + QString::number(decode_signals++));
+                       settings.beginGroup("decode_signal" + QString::number(i++));
                        base->save_settings(settings);
                        settings.endGroup();
                } else
@@ -211,24 +213,54 @@ void Session::save_setup(QSettings &settings) const
                }
        }
 
-       settings.setValue("decode_signals", decode_signals);
+       settings.setValue("decode_signals", i);
 
        // Save view states and their signal settings
        // Note: main_view must be saved as view0
-       settings.beginGroup("view" + QString::number(views++));
+       i = 0;
+       settings.beginGroup("view" + QString::number(i++));
        main_view_->save_settings(settings);
        settings.endGroup();
 
        for (const shared_ptr<views::ViewBase>& view : views_) {
                if (view != main_view_) {
-                       settings.beginGroup("view" + QString::number(views++));
+                       settings.beginGroup("view" + QString::number(i++));
                        settings.setValue("type", view->get_type());
                        view->save_settings(settings);
                        settings.endGroup();
                }
        }
 
-       settings.setValue("views", views);
+       settings.setValue("views", i);
+
+       i = 0;
+       shared_ptr<views::trace::View> tv = dynamic_pointer_cast<views::trace::View>(main_view_);
+       for (const shared_ptr<views::trace::TimeItem>& time_item : tv->time_items()) {
+
+               const shared_ptr<views::trace::Flag> flag =
+                       dynamic_pointer_cast<views::trace::Flag>(time_item);
+               if (flag) {
+                       if (!flag->enabled())
+                               continue;
+
+                       settings.beginGroup("meta_obj" + QString::number(i++));
+                       settings.setValue("type", "time_marker");
+                       GlobalSettings::store_timestamp(settings, "time", flag->time());
+                       settings.setValue("text", flag->get_text());
+                       settings.endGroup();
+               }
+       }
+
+       if (tv->cursors_shown()) {
+               settings.beginGroup("meta_obj" + QString::number(i++));
+               settings.setValue("type", "selection");
+               const shared_ptr<views::trace::CursorPair> cp = tv->cursors();
+               GlobalSettings::store_timestamp(settings, "start_time", cp->first()->time());
+               GlobalSettings::store_timestamp(settings, "end_time", cp->second()->time());
+               settings.endGroup();
+       }
+
+       settings.setValue("meta_objs", i);
 }
 
 void Session::save_settings(QSettings &settings) const
@@ -324,13 +356,37 @@ void Session::restore_setup(QSettings &settings)
 
                settings.endGroup();
        }
+
+       // Restore meta objects like markers and cursors
+       int meta_objs = settings.value("meta_objs").toInt();
+
+       shared_ptr<views::trace::View> tv = dynamic_pointer_cast<views::trace::View>(main_view_);
+       for (int i = 0; i < meta_objs; i++) {
+               settings.beginGroup("meta_obj" + QString::number(i));
+               const QString type = settings.value("type").toString();
+
+               if (type == "time_marker") {
+                       Timestamp ts = GlobalSettings::restore_timestamp(settings, "time");
+                       shared_ptr<views::trace::Flag> flag = tv->add_flag(ts);
+                       flag->set_text(settings.value("text").toString());
+               }
+
+               if (type == "selection") {
+                       Timestamp start = GlobalSettings::restore_timestamp(settings, "start_time");
+                       Timestamp end = GlobalSettings::restore_timestamp(settings, "end_time");
+                       tv->set_cursors(start, end);
+                       tv->show_cursors();
+               }
+
+               settings.endGroup();
+       }
 }
 
 void Session::restore_settings(QSettings &settings)
 {
        shared_ptr<devices::Device> device;
 
-       QString device_type = settings.value("device_type").toString();
+       const QString device_type = settings.value("device_type").toString();
 
        if (device_type == "hardware") {
                map<string, string> dev_info;
@@ -366,7 +422,7 @@ void Session::restore_settings(QSettings &settings)
        if ((device_type == "sessionfile") || (device_type == "inputfile")) {
                if (device_type == "sessionfile") {
                        settings.beginGroup("device");
-                       QString filename = settings.value("filename").toString();
+                       const QString filename = settings.value("filename").toString();
                        settings.endGroup();
 
                        if (QFileInfo(filename).isReadable()) {
index ea3cd609854c813783ffe6e406143b887915693a..b0518b646d87c493d8c13de606570f8dccf92522 100644 (file)
@@ -73,6 +73,12 @@ QString Flag::get_text() const
        return s;
 }
 
+void Flag::set_text(const QString &text)
+{
+       text_ = text;
+       view_.time_item_appearance_changed(true, false);
+}
+
 QRectF Flag::label_rect(const QRectF &rect) const
 {
        QRectF r;
@@ -158,8 +164,7 @@ void Flag::on_delete()
 
 void Flag::on_text_changed(const QString &text)
 {
-       text_ = text;
-       view_.time_item_appearance_changed(true, false);
+       set_text(text);
 }
 
 } // namespace trace
index 5edf90b01ef63997595415d32e0fc6faea35c0d3..e58771b81a4f4f603d8171fdfb8905d8a6edb6e1 100644 (file)
@@ -67,6 +67,11 @@ public:
         */
        virtual QString get_text() const override;
 
+       /**
+        * Sets the text to show in the marker.
+        */
+       virtual void set_text(const QString &text) override;
+
        virtual pv::widgets::Popup* create_popup(QWidget *parent) override;
 
        virtual QMenu* create_header_context_menu(QWidget *parent) override;
index bebf529147da67f5bc4d591255bce144d5d1674b..555794fc42c6e881c5691fc1d64c43a0355e7cd3 100644 (file)
@@ -158,6 +158,12 @@ void Ruler::contextMenuEvent(QContextMenuEvent *event)
        connect(set_zero_position, SIGNAL(triggered()), this, SLOT(on_setZeroPosition()));
        menu->addAction(set_zero_position);
 
+       if (view_.zero_offset().convert_to<double>() != 0) {
+               QAction *const reset_zero_position = new QAction(tr("Reset zero point"), this);
+               connect(reset_zero_position, SIGNAL(triggered()), this, SLOT(on_resetZeroPosition()));
+               menu->addAction(reset_zero_position);
+       }
+
        QAction *const toggle_hover_marker = new QAction(this);
        connect(toggle_hover_marker, SIGNAL(triggered()), this, SLOT(on_toggleHoverMarker()));
        menu->addAction(toggle_hover_marker);
@@ -397,6 +403,11 @@ void Ruler::on_setZeroPosition()
        view_.set_zero_position(get_absolute_time_from_x_pos(mouse_down_point_.x()));
 }
 
+void Ruler::on_resetZeroPosition()
+{
+       view_.reset_zero_position();
+}
+
 void Ruler::on_toggleHoverMarker()
 {
        GlobalSettings settings;
index 18a09d9baf5fce069f8ebeaf8b584a142058e36f..9d708ce027bc9bfaca3ed6610c81fb338ea5dae6 100644 (file)
@@ -184,6 +184,7 @@ private Q_SLOTS:
 
        void on_createMarker();
        void on_setZeroPosition();
+       void on_resetZeroPosition();
        void on_toggleHoverMarker();
 
 private:
index 9cb33a7637e1d7a3d90550c5d90656d2b3fbedd6..b428f6027e7bf4331d5c9d4d408a3f56fe554a92 100644 (file)
@@ -105,6 +105,11 @@ QRectF TimeMarker::hit_box_rect(const ViewItemPaintParams &pp) const
        return QRectF(x - h / 2.0f, pp.top(), h, pp.height());
 }
 
+void TimeMarker::set_text(const QString &text)
+{
+       (void)text;
+}
+
 void TimeMarker::paint_label(QPainter &p, const QRect &rect, bool hover)
 {
        if (!enabled())
index 99c56d34beedad769a7b4e988b456178210fa412..cd7c84d279747cddf13fb0a6fd58c11af5292b3f 100644 (file)
@@ -99,6 +99,11 @@ public:
         */
        virtual QString get_text() const = 0;
 
+       /**
+        * Sets the text to show in the marker.
+        */
+       virtual void set_text(const QString &text);
+
        /**
         * Paints the marker's label to the ruler.
         * @param p The painter to draw with.
index 15e65127b2932062b46a5734575febf9d163631c..40ecc195cea44e9cd5d204b525c2386c8c618baa 100644 (file)
 #include <iterator>
 #include <unordered_set>
 
-#include <boost/archive/text_iarchive.hpp>
-#include <boost/archive/text_oarchive.hpp>
-#include <boost/serialization/serialization.hpp>
-
 #include <QApplication>
+#include <QDebug>
 #include <QEvent>
 #include <QFontMetrics>
 #include <QMenu>
@@ -84,7 +81,6 @@ using std::pair;
 using std::set;
 using std::set_difference;
 using std::shared_ptr;
-using std::stringstream;
 using std::unordered_map;
 using std::unordered_set;
 using std::vector;
@@ -276,6 +272,8 @@ void View::reset_view_state()
        scale_ = 1e-3;
        offset_ = 0;
        ruler_offset_ = 0;
+       zero_offset_ = 0;
+       custom_zero_offset_set_ = false;
        updating_scroll_ = false;
        settings_restored_ = false;
        always_zoom_to_fit_ = false;
@@ -432,12 +430,12 @@ void View::save_settings(QSettings &settings) const
        settings.setValue("splitter_state", splitter_->saveState());
        settings.setValue("segment_display_mode", segment_display_mode_);
 
-       {
-               stringstream ss;
-               boost::archive::text_oarchive oa(ss);
-               oa << boost::serialization::make_nvp("offset", offset_);
-               settings.setValue("offset", QString::fromStdString(ss.str()));
-       }
+       GlobalSettings::store_timestamp(settings, "offset", offset_);
+
+       if (custom_zero_offset_set_)
+               GlobalSettings::store_timestamp(settings, "zero_offset", -zero_offset_);
+       else
+               settings.remove("zero_offset");
 
        for (const shared_ptr<Signal>& signal : signals_) {
                settings.beginGroup(signal->base()->internal_name());
@@ -455,20 +453,13 @@ void View::restore_settings(QSettings &settings)
                set_scale(settings.value("scale").toDouble());
 
        if (settings.contains("offset")) {
-               util::Timestamp offset;
-               stringstream ss;
-               ss << settings.value("offset").toString().toStdString();
-
-               try {
-                       boost::archive::text_iarchive ia(ss);
-                       ia >> boost::serialization::make_nvp("offset", offset);
-                       // This also updates ruler_offset_
-                       set_offset(offset);
-               } catch (boost::archive::archive_exception&) {
-                       qDebug() << "Could not restore the view offset";
-               }
+               // This also updates ruler_offset_
+               set_offset(GlobalSettings::restore_timestamp(settings, "offset"));
        }
 
+       if (settings.contains("zero_offset"))
+               set_zero_position(GlobalSettings::restore_timestamp(settings, "zero_offset"));
+
        if (settings.contains("splitter_state"))
                splitter_->restoreState(settings.value("splitter_state").toByteArray());
 
@@ -548,6 +539,7 @@ const Timestamp& View::ruler_offset() const
 void View::set_zero_position(const pv::util::Timestamp& position)
 {
        zero_offset_ = -position;
+       custom_zero_offset_set_ = true;
 
        // Force an immediate update of the offsets
        set_offset(offset_, true);
@@ -558,6 +550,19 @@ void View::reset_zero_position()
 {
        zero_offset_ = 0;
 
+       // When enabled, the first trigger for this segment is used as the zero position
+       GlobalSettings settings;
+       bool trigger_is_zero_time = settings.value(GlobalSettings::Key_View_TriggerIsZeroTime).toBool();
+
+       if (trigger_is_zero_time) {
+               vector<util::Timestamp> triggers = session_.get_triggers(current_segment_);
+
+               if (triggers.size() > 0)
+                       zero_offset_ = triggers.front();
+       }
+
+       custom_zero_offset_set_ = false;
+
        // Force an immediate update of the offsets
        set_offset(offset_, true);
        ruler_->update();
@@ -676,12 +681,8 @@ void View::set_current_segment(uint32_t segment_id)
        for (util::Timestamp timestamp : triggers)
                trigger_markers_.push_back(make_shared<TriggerMarker>(*this, timestamp));
 
-       // When enabled, the first trigger for this segment is used as the zero position
-       GlobalSettings settings;
-       bool trigger_is_zero_time = settings.value(GlobalSettings::Key_View_TriggerIsZeroTime).toBool();
-
-       if (trigger_is_zero_time && (triggers.size() > 0))
-               set_zero_position(triggers.front());
+       if (!custom_zero_offset_set_)
+               reset_zero_position();
 
        viewport_->update();
 
@@ -1088,15 +1089,8 @@ void View::trigger_event(int segment_id, util::Timestamp location)
        if ((uint32_t)segment_id != current_segment_)
                return;
 
-       // Set zero location if the Key_View_TriggerIsZeroTime setting is set and
-       // if this is the first trigger for this segment.
-       GlobalSettings settings;
-       bool trigger_is_zero_time = settings.value(GlobalSettings::Key_View_TriggerIsZeroTime).toBool();
-
-       size_t trigger_count = session_.get_triggers(current_segment_).size();
-
-       if (trigger_is_zero_time && trigger_count == 1)
-               set_zero_position(location);
+       if (!custom_zero_offset_set_)
+               reset_zero_position();
 
        trigger_markers_.push_back(make_shared<TriggerMarker>(*this, location));
 }
@@ -1831,7 +1825,8 @@ void View::capture_state_updated(int state)
                set_time_unit(util::TimeUnit::Samples);
 
                trigger_markers_.clear();
-               set_zero_position(0);
+               if (!custom_zero_offset_set_)
+                       set_zero_position(0);
 
                scale_at_acq_start_ = scale_;
                offset_at_acq_start_ = offset_;
@@ -1914,12 +1909,7 @@ void View::on_segment_changed(int segment)
 
 void View::on_settingViewTriggerIsZeroTime_changed(const QVariant new_value)
 {
-       if (new_value.toBool()) {
-               // The first trigger for this segment is used as the zero position
-               vector<util::Timestamp> triggers = session_.get_triggers(current_segment_);
-               if (triggers.size() > 0)
-                       set_zero_position(triggers.front());
-       } else
+       if (!custom_zero_offset_set_)
                reset_zero_position();
 }
 
index 2938d00fc0014296712adecc921ada3f2e5511d2..c2cceb274d851989c8d6b1f8d225fb5ec3e238a1 100644 (file)
@@ -530,6 +530,8 @@ private:
        pv::util::Timestamp ruler_offset_;
        /// The offset of the zero point in seconds.
        pv::util::Timestamp zero_offset_;
+       /// Shows whether the user set a custom zero offset that we should keep
+       bool custom_zero_offset_set_;
 
        bool updating_scroll_;
        bool settings_restored_;