]> sigrok.org Git - pulseview.git/blobdiff - pv/toolbars/mainbar.cpp
MainBar: fixup file extension filter in "Import File" dialog
[pulseview.git] / pv / toolbars / mainbar.cpp
index b670b75a6c41a2da6a117e4e7a55a205414f46a6..1879693d57a31c01bc87458f556d67dd01db7506 100644 (file)
@@ -14,8 +14,7 @@
  * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #include <extdef.h>
@@ -36,6 +35,7 @@
 
 #include <boost/algorithm/string/join.hpp>
 
+#include <pv/data/decodesignal.hpp>
 #include <pv/devicemanager.hpp>
 #include <pv/devices/hardwaredevice.hpp>
 #include <pv/devices/inputfile.hpp>
 #include <pv/dialogs/inputoutputoptions.hpp>
 #include <pv/dialogs/storeprogress.hpp>
 #include <pv/mainwindow.hpp>
-#include <pv/popups/deviceoptions.hpp>
 #include <pv/popups/channels.hpp>
+#include <pv/popups/deviceoptions.hpp>
 #include <pv/util.hpp>
-#include <pv/view/view.hpp>
+#include <pv/views/trace/view.hpp>
 #include <pv/widgets/exportmenu.hpp>
 #include <pv/widgets/importmenu.hpp>
 #ifdef ENABLE_DECODE
 #include <libsigrokcxx/libsigrokcxx.hpp>
 
 using std::back_inserter;
-using std::cerr;
 using std::copy;
-using std::endl;
 using std::list;
+using std::make_pair;
 using std::map;
 using std::max;
 using std::min;
+using std::pair;
+using std::set;
 using std::shared_ptr;
 using std::string;
 using std::vector;
@@ -86,20 +87,17 @@ const uint64_t MainBar::DefaultSampleCount = 1000000;
 const char *MainBar::SettingOpenDirectory = "MainWindow/OpenDirectory";
 const char *MainBar::SettingSaveDirectory = "MainWindow/SaveDirectory";
 
-MainBar::MainBar(Session &session, MainWindow &main_window) :
-       QToolBar("Sampling Bar", &main_window),
+MainBar::MainBar(Session &session, QWidget *parent,
+               pv::views::trace::View *view) :
+       StandardBar(session, parent, view, false),
        action_new_view_(new QAction(this)),
        action_open_(new QAction(this)),
        action_save_as_(new QAction(this)),
        action_save_selection_as_(new QAction(this)),
        action_connect_(new QAction(this)),
-       action_view_zoom_in_(new QAction(this)),
-       action_view_zoom_out_(new QAction(this)),
-       action_view_zoom_fit_(new QAction(this)),
-       action_view_zoom_one_to_one_(new QAction(this)),
-       action_view_show_cursors_(new QAction(this)),
-       session_(session),
-       device_selector_(&main_window, session.device_manager(),
+       open_button_(new QToolButton()),
+       save_button_(new QToolButton()),
+       device_selector_(parent, session.device_manager(),
                action_connect_),
        configure_button_(this),
        configure_button_action_(nullptr),
@@ -111,13 +109,12 @@ MainBar::MainBar(Session &session, MainWindow &main_window) :
        updating_sample_count_(false),
        sample_count_supported_(false)
 #ifdef ENABLE_DECODE
-       , menu_decoders_add_(new pv::widgets::DecoderMenu(this, true))
+       , add_decoder_button_(new QToolButton()),
+       menu_decoders_add_(new pv::widgets::DecoderMenu(this, true))
 #endif
 {
        setObjectName(QString::fromUtf8("MainBar"));
 
-       setMovable(false);
-       setFloatable(false);
        setContextMenuPolicy(Qt::PreventContextMenu);
 
        // Actions
@@ -152,75 +149,33 @@ MainBar::MainBar(Session &session, MainWindow &main_window) :
                session.device_manager().context());
        menu_file_export->setTitle(tr("&Export"));
        connect(menu_file_export,
-               SIGNAL(format_selected(std::shared_ptr<sigrok::OutputFormat>)),
-               this, SLOT(export_file(std::shared_ptr<sigrok::OutputFormat>)));
+               SIGNAL(format_selected(shared_ptr<sigrok::OutputFormat>)),
+               this, SLOT(export_file(shared_ptr<sigrok::OutputFormat>)));
 
        widgets::ImportMenu *menu_file_import = new widgets::ImportMenu(this,
                session.device_manager().context());
        menu_file_import->setTitle(tr("&Import"));
        connect(menu_file_import,
-               SIGNAL(format_selected(std::shared_ptr<sigrok::InputFormat>)),
-               this, SLOT(import_file(std::shared_ptr<sigrok::InputFormat>)));
+               SIGNAL(format_selected(shared_ptr<sigrok::InputFormat>)),
+               this, SLOT(import_file(shared_ptr<sigrok::InputFormat>)));
 
        action_connect_->setText(tr("&Connect to Device..."));
        connect(action_connect_, SIGNAL(triggered(bool)),
                this, SLOT(on_actionConnect_triggered()));
 
-       action_view_zoom_in_->setText(tr("Zoom &In"));
-       action_view_zoom_in_->setIcon(QIcon::fromTheme("zoom-in",
-               QIcon(":/icons/zoom-in.png")));
-       // simply using Qt::Key_Plus shows no + in the menu
-       action_view_zoom_in_->setShortcut(QKeySequence::ZoomIn);
-       connect(action_view_zoom_in_, SIGNAL(triggered(bool)),
-               this, SLOT(on_actionViewZoomIn_triggered()));
-
-       action_view_zoom_out_->setText(tr("Zoom &Out"));
-       action_view_zoom_out_->setIcon(QIcon::fromTheme("zoom-out",
-               QIcon(":/icons/zoom-out.png")));
-       action_view_zoom_out_->setShortcut(QKeySequence::ZoomOut);
-       connect(action_view_zoom_out_, SIGNAL(triggered(bool)),
-               this, SLOT(on_actionViewZoomOut_triggered()));
-
-       action_view_zoom_fit_->setCheckable(true);
-       action_view_zoom_fit_->setText(tr("Zoom to &Fit"));
-       action_view_zoom_fit_->setIcon(QIcon::fromTheme("zoom-fit",
-               QIcon(":/icons/zoom-fit.png")));
-       action_view_zoom_fit_->setShortcut(QKeySequence(Qt::Key_F));
-       connect(action_view_zoom_fit_, SIGNAL(triggered(bool)),
-               this, SLOT(on_actionViewZoomFit_triggered()));
-
-       action_view_zoom_one_to_one_->setText(tr("Zoom to O&ne-to-One"));
-       action_view_zoom_one_to_one_->setIcon(QIcon::fromTheme("zoom-original",
-               QIcon(":/icons/zoom-original.png")));
-       action_view_zoom_one_to_one_->setShortcut(QKeySequence(Qt::Key_O));
-       connect(action_view_zoom_one_to_one_, SIGNAL(triggered(bool)),
-               this, SLOT(on_actionViewZoomOneToOne_triggered()));
-
-       action_view_show_cursors_->setCheckable(true);
-       action_view_show_cursors_->setIcon(QIcon::fromTheme("show-cursors",
-               QIcon(":/icons/show-cursors.svg")));
-       action_view_show_cursors_->setShortcut(QKeySequence(Qt::Key_C));
-       connect(action_view_show_cursors_, SIGNAL(triggered(bool)),
-               this, SLOT(on_actionViewShowCursors_triggered()));
-       action_view_show_cursors_->setText(tr("Show &Cursors"));
-
        // Open button
-       QToolButton *const open_button = new QToolButton(this);
-
        widgets::ImportMenu *import_menu = new widgets::ImportMenu(this,
                session.device_manager().context(), action_open_);
        connect(import_menu,
-               SIGNAL(format_selected(std::shared_ptr<sigrok::InputFormat>)),
+               SIGNAL(format_selected(shared_ptr<sigrok::InputFormat>)),
                this,
-               SLOT(import_file(std::shared_ptr<sigrok::InputFormat>)));
+               SLOT(import_file(shared_ptr<sigrok::InputFormat>)));
 
-       open_button->setMenu(import_menu);
-       open_button->setDefaultAction(action_open_);
-       open_button->setPopupMode(QToolButton::MenuButtonPopup);
+       open_button_->setMenu(import_menu);
+       open_button_->setDefaultAction(action_open_);
+       open_button_->setPopupMode(QToolButton::MenuButtonPopup);
 
        // Save button
-       QToolButton *const save_button = new QToolButton(this);
-
        vector<QAction *> open_actions;
        open_actions.push_back(action_save_as_);
        open_actions.push_back(action_save_selection_as_);
@@ -229,13 +184,13 @@ MainBar::MainBar(Session &session, MainWindow &main_window) :
                session.device_manager().context(),
                open_actions);
        connect(export_menu,
-               SIGNAL(format_selected(std::shared_ptr<sigrok::OutputFormat>)),
+               SIGNAL(format_selected(shared_ptr<sigrok::OutputFormat>)),
                this,
-               SLOT(export_file(std::shared_ptr<sigrok::OutputFormat>)));
+               SLOT(export_file(shared_ptr<sigrok::OutputFormat>)));
 
-       save_button->setMenu(export_menu);
-       save_button->setDefaultAction(action_save_as_);
-       save_button->setPopupMode(QToolButton::MenuButtonPopup);
+       save_button_->setMenu(export_menu);
+       save_button_->setDefaultAction(action_save_as_);
+       save_button_->setPopupMode(QToolButton::MenuButtonPopup);
 
        // Device selector menu
        connect(&device_selector_, SIGNAL(device_selected()),
@@ -247,27 +202,12 @@ MainBar::MainBar(Session &session, MainWindow &main_window) :
        connect(menu_decoders_add_, SIGNAL(decoder_selected(srd_decoder*)),
                this, SLOT(add_decoder(srd_decoder*)));
 
-       QToolButton *add_decoder_button = new QToolButton(this);
-       add_decoder_button->setIcon(QIcon::fromTheme("add-decoder",
-               QIcon(":/icons/add-decoder.svg")));
-       add_decoder_button->setPopupMode(QToolButton::InstantPopup);
-       add_decoder_button->setMenu(menu_decoders_add_);
+       add_decoder_button_->setIcon(QIcon(":/icons/add-decoder.svg"));
+       add_decoder_button_->setPopupMode(QToolButton::InstantPopup);
+       add_decoder_button_->setMenu(menu_decoders_add_);
+       add_decoder_button_->setToolTip(tr("Add low-level, non-stacked protocol decoder"));
 #endif
 
-       // Setup the toolbar
-       addAction(action_new_view_);
-       addSeparator();
-       addWidget(open_button);
-       addWidget(save_button);
-       addSeparator();
-       addAction(action_view_zoom_in_);
-       addAction(action_view_zoom_out_);
-       addAction(action_view_zoom_fit_);
-       addAction(action_view_zoom_one_to_one_);
-       addSeparator();
-       addAction(action_view_show_cursors_);
-       addSeparator();
-
        connect(&sample_count_, SIGNAL(value_changed()),
                this, SLOT(on_sample_count_changed()));
        connect(&sample_rate_, SIGNAL(value_changed()),
@@ -277,39 +217,27 @@ MainBar::MainBar(Session &session, MainWindow &main_window) :
 
        set_capture_state(pv::Session::Stopped);
 
-       configure_button_.setIcon(QIcon::fromTheme("configure",
-               QIcon(":/icons/configure.png")));
+       configure_button_.setToolTip(tr("Configure Device"));
+       configure_button_.setIcon(QIcon::fromTheme("preferences-system",
+               QIcon(":/icons/preferences-system.png")));
 
-       channels_button_.setIcon(QIcon::fromTheme("channels",
-               QIcon(":/icons/channels.svg")));
+       channels_button_.setToolTip(tr("Configure Channels"));
+       channels_button_.setIcon(QIcon(":/icons/channels.svg"));
 
-       addWidget(&device_selector_);
-       configure_button_action_ = addWidget(&configure_button_);
-       channels_button_action_ = addWidget(&channels_button_);
-       addWidget(&sample_count_);
-       addWidget(&sample_rate_);
-#ifdef ENABLE_DECODE
-       addSeparator();
-       addWidget(add_decoder_button);
-#endif
+       add_toolbar_widgets();
 
        sample_count_.installEventFilter(this);
        sample_rate_.installEventFilter(this);
 
        // Setup session_ events
        connect(&session_, SIGNAL(capture_state_changed(int)),
-               this, SLOT(capture_state_changed(int)));
+               this, SLOT(on_capture_state_changed(int)));
        connect(&session, SIGNAL(device_changed()),
                this, SLOT(on_device_changed()));
 
        update_device_list();
 }
 
-Session &MainBar::session(void) const
-{
-       return session_;
-}
-
 void MainBar::update_device_list()
 {
        DeviceManager &mgr = session_.device_manager();
@@ -325,7 +253,6 @@ void MainBar::update_device_list()
        update_device_config_widgets();
 }
 
-
 void MainBar::set_capture_state(pv::Session::capture_state state)
 {
        bool ui_enabled = (state == pv::Session::Stopped) ? true : false;
@@ -362,38 +289,13 @@ QAction* MainBar::action_connect() const
        return action_connect_;
 }
 
-QAction* MainBar::action_view_zoom_in() const
-{
-       return action_view_zoom_in_;
-}
-
-QAction* MainBar::action_view_zoom_out() const
-{
-       return action_view_zoom_out_;
-}
-
-QAction* MainBar::action_view_zoom_fit() const
-{
-       return action_view_zoom_fit_;
-}
-
-QAction* MainBar::action_view_zoom_one_to_one() const
-{
-       return action_view_zoom_one_to_one_;
-}
-
-QAction* MainBar::action_view_show_cursors() const
-{
-       return action_view_show_cursors_;
-}
-
 void MainBar::update_sample_rate_selector()
 {
        Glib::VariantContainerBase gvar_dict;
        GVariant *gvar_list;
        const uint64_t *elements = nullptr;
        gsize num_elements;
-       map< const ConfigKey*, std::set<Capability> > keys;
+       map< const ConfigKey*, set<Capability> > keys;
 
        if (updating_sample_rate_) {
                sample_rate_.show_none();
@@ -503,9 +405,12 @@ void MainBar::update_sample_count_selector()
        uint64_t sample_count = sample_count_.value();
        uint64_t min_sample_count = 0;
        uint64_t max_sample_count = MaxSampleCount;
+       bool default_count_set = false;
 
-       if (sample_count == 0)
+       if (sample_count == 0) {
                sample_count = DefaultSampleCount;
+               default_count_set = true;
+       }
 
        if (sr_dev->config_check(ConfigKey::LIMIT_SAMPLES, Capability::LIST)) {
                auto gvar = sr_dev->config_list(ConfigKey::LIMIT_SAMPLES);
@@ -517,14 +422,15 @@ void MainBar::update_sample_count_selector()
        min_sample_count = min(max(min_sample_count, MinSampleCount),
                max_sample_count);
 
-       sample_count_.show_125_list(
-               min_sample_count, max_sample_count);
+       sample_count_.show_125_list(min_sample_count, max_sample_count);
 
        if (sr_dev->config_check(ConfigKey::LIMIT_SAMPLES, Capability::GET)) {
                auto gvar = sr_dev->config_get(ConfigKey::LIMIT_SAMPLES);
                sample_count = g_variant_get_uint64(gvar.gobj());
-               if (sample_count == 0)
+               if (sample_count == 0) {
                        sample_count = DefaultSampleCount;
+                       default_count_set = true;
+               }
                sample_count = min(max(sample_count, MinSampleCount),
                        max_sample_count);
        }
@@ -532,6 +438,10 @@ void MainBar::update_sample_count_selector()
        sample_count_.set_value(sample_count);
 
        updating_sample_count_ = false;
+
+       // If we show the default rate then make sure the device uses the same
+       if (default_count_set)
+               commit_sample_count();
 }
 
 void MainBar::update_device_config_widgets()
@@ -570,12 +480,6 @@ void MainBar::update_device_config_widgets()
        if (sr_dev->config_check(ConfigKey::LIMIT_SAMPLES, Capability::SET))
                sample_count_supported_ = true;
 
-       if (sr_dev->config_check(ConfigKey::LIMIT_FRAMES, Capability::SET)) {
-               sr_dev->config_set(ConfigKey::LIMIT_FRAMES,
-                       Glib::Variant<guint64>::create(1));
-                       on_config_changed();
-       }
-
        // Add notification of reconfigure events
        disconnect(this, SLOT(on_config_changed()));
        connect(&opts->binding(), SIGNAL(config_changed()),
@@ -662,23 +566,19 @@ void MainBar::show_session_error(const QString text, const QString info_text)
        msg.exec();
 }
 
-void MainBar::capture_state_changed(int state)
-{
-       set_capture_state((pv::Session::capture_state)state);
-}
-
 void MainBar::add_decoder(srd_decoder *decoder)
 {
 #ifdef ENABLE_DECODE
        assert(decoder);
-       session_.add_decoder(decoder);
+       shared_ptr<data::DecodeSignal> signal = session_.add_decode_signal();
+       if (signal)
+               signal->stack_decoder(decoder);
 #else
        (void)decoder;
 #endif
 }
 
-void MainBar::export_file(shared_ptr<OutputFormat> format,
-       bool selection_only)
+void MainBar::export_file(shared_ptr<OutputFormat> format, bool selection_only)
 {
        using pv::dialogs::StoreProgress;
 
@@ -688,17 +588,17 @@ void MainBar::export_file(shared_ptr<OutputFormat> format,
        QSettings settings;
        const QString dir = settings.value(SettingSaveDirectory).toString();
 
-       std::pair<uint64_t, uint64_t> sample_range;
+       pair<uint64_t, uint64_t> sample_range;
 
        // Selection only? Verify that the cursors are active and fetch their values
        if (selection_only) {
-               views::TraceView::View *trace_view =
-                       qobject_cast<views::TraceView::View*>(session_.main_view().get());
+               views::trace::View *trace_view =
+                       qobject_cast<views::trace::View*>(session_.main_view().get());
 
                if (!trace_view->cursors()->enabled()) {
                        show_session_error(tr("Missing Cursors"), tr("You need to set the " \
                                        "cursors before you can save the data enclosed by them " \
-                                       "to a session file (e.g. using ALT-V - Show Cursors)."));
+                                       "to a session file (e.g. using the Show Cursors button)."));
                        return;
                }
 
@@ -707,13 +607,14 @@ void MainBar::export_file(shared_ptr<OutputFormat> format,
                const pv::util::Timestamp& start_time = trace_view->cursors()->first()->time();
                const pv::util::Timestamp& end_time = trace_view->cursors()->second()->time();
 
-               const uint64_t start_sample =
-                       std::max((double)0, start_time.convert_to<double>() * samplerate);
-               const uint64_t end_sample = end_time.convert_to<double>() * samplerate;
+               const uint64_t start_sample = (uint64_t)max(
+                       (double)0, start_time.convert_to<double>() * samplerate);
+               const uint64_t end_sample = (uint64_t)max(
+                       (double)0, end_time.convert_to<double>() * samplerate);
 
-               sample_range = std::make_pair(start_sample, end_sample);
+               sample_range = make_pair(start_sample, end_sample);
        } else {
-               sample_range = std::make_pair(0, 0);
+               sample_range = make_pair(0, 0);
        }
 
        // Construct the filter
@@ -722,9 +623,9 @@ void MainBar::export_file(shared_ptr<OutputFormat> format,
                QString::fromStdString(format->description()));
 
        if (exts.empty())
-               filter += "(*.*)";
+               filter += "(*)";
        else
-               filter += QString("(*.%1);;%2 (*.*)").arg(
+               filter += QString("(*.%1);;%2 (*)").arg(
                        QString::fromStdString(join(exts, ", *.")),
                        tr("All Files"));
 
@@ -767,16 +668,19 @@ void MainBar::import_file(shared_ptr<InputFormat> format)
 
        // Construct the filter
        const vector<string> exts = format->extensions();
-       const QString filter = exts.empty() ? "" :
-               tr("%1 files (*.%2)").arg(
-                       QString::fromStdString(format->description()),
-                       QString::fromStdString(join(exts, ", *.")));
+       const QString filter_exts = exts.empty() ? "" : QString::fromStdString("%1 (%2)").arg(
+               tr("%1 files").arg(QString::fromStdString(format->description())),
+               QString::fromStdString("*.%1").arg(QString::fromStdString(join(exts, " *."))));
+       const QString filter_all = QString::fromStdString("%1 (%2)").arg(
+               tr("All Files"), QString::fromStdString("*"));
+       const QString filter = QString::fromStdString("%1%2%3").arg(
+               exts.empty() ? "" : filter_exts,
+               exts.empty() ? "" : ";;",
+               filter_all);
 
        // Show the file dialog
        const QString file_name = QFileDialog::getOpenFileName(
-               this, tr("Import File"), dir, tr(
-                       "%1 files (*.*);;All Files (*.*)").arg(
-                       QString::fromStdString(format->description())));
+               this, tr("Import File"), dir, filter);
 
        if (file_name.isEmpty())
                return;
@@ -816,6 +720,11 @@ void MainBar::on_device_changed()
        update_device_config_widgets();
 }
 
+void MainBar::on_capture_state_changed(int state)
+{
+       set_capture_state((pv::Session::capture_state)state);
+}
+
 void MainBar::on_sample_count_changed()
 {
        if (!updating_sample_count_)
@@ -831,7 +740,7 @@ void MainBar::on_sample_rate_changed()
 void MainBar::on_config_changed()
 {
        commit_sample_count();
-       commit_sample_rate();   
+       commit_sample_rate();
 }
 
 void MainBar::on_actionNewView_triggered()
@@ -847,8 +756,8 @@ void MainBar::on_actionOpen_triggered()
        // Show the dialog
        const QString file_name = QFileDialog::getOpenFileName(
                this, tr("Open File"), dir, tr(
-                       "Sigrok Sessions (*.sr);;"
-                       "All Files (*.*)"));
+                       "sigrok Sessions (*.sr);;"
+                       "All Files (*)"));
 
        if (!file_name.isEmpty()) {
                session_.load_file(file_name);
@@ -883,53 +792,25 @@ void MainBar::on_actionConnect_triggered()
        update_device_list();
 }
 
-void MainBar::on_actionViewZoomIn_triggered()
+void MainBar::add_toolbar_widgets()
 {
-       views::TraceView::View *trace_view =
-               qobject_cast<views::TraceView::View*>(session_.main_view().get());
-
-       trace_view->zoom(1);
-}
-
-void MainBar::on_actionViewZoomOut_triggered()
-{
-       views::TraceView::View *trace_view =
-               qobject_cast<views::TraceView::View*>(session_.main_view().get());
-
-       trace_view->zoom(-1);
-}
-
-void MainBar::on_actionViewZoomFit_triggered()
-{
-       views::TraceView::View *trace_view =
-               qobject_cast<views::TraceView::View*>(session_.main_view().get());
-
-       trace_view->zoom_fit(action_view_zoom_fit_->isChecked());
-}
-
-void MainBar::on_actionViewZoomOneToOne_triggered()
-{
-       views::TraceView::View *trace_view =
-               qobject_cast<views::TraceView::View*>(session_.main_view().get());
-
-       trace_view->zoom_one_to_one();
-}
-
-void MainBar::on_actionViewShowCursors_triggered()
-{
-       views::TraceView::View *trace_view =
-               qobject_cast<views::TraceView::View*>(session_.main_view().get());
-
-       const bool show = !trace_view->cursors_shown();
-       if (show)
-               trace_view->centre_cursors();
+       addAction(action_new_view_);
+       addSeparator();
+       addWidget(open_button_);
+       addWidget(save_button_);
+       addSeparator();
 
-       trace_view->show_cursors(show);
-}
+       StandardBar::add_toolbar_widgets();
 
-void MainBar::on_always_zoom_to_fit_changed(bool state)
-{
-       action_view_zoom_fit_->setChecked(state);
+       addWidget(&device_selector_);
+       configure_button_action_ = addWidget(&configure_button_);
+       channels_button_action_ = addWidget(&channels_button_);
+       addWidget(&sample_count_);
+       addWidget(&sample_rate_);
+#ifdef ENABLE_DECODE
+       addSeparator();
+       addWidget(add_decoder_button_);
+#endif
 }
 
 bool MainBar::eventFilter(QObject *watched, QEvent *event)