#include <algorithm>
#include <iterator>
-#include <boost/algorithm/string/join.hpp>
-
#include <QAction>
#include <QApplication>
-#include <QButtonGroup>
#include <QCloseEvent>
-#include <QFileDialog>
-#include <QMessageBox>
-#include <QMenu>
-#include <QMenuBar>
+#include <QDockWidget>
#include <QSettings>
-#include <QStatusBar>
-#include <QVBoxLayout>
#include <QWidget>
-#include <QDockWidget>
-
#include "mainwindow.hpp"
#include "devicemanager.hpp"
#include "util.hpp"
-#include "data/segment.hpp"
-#include "devices/hardwaredevice.hpp"
-#include "devices/inputfile.hpp"
-#include "devices/sessionfile.hpp"
#include "dialogs/about.hpp"
-#include "dialogs/connect.hpp"
-#include "dialogs/inputoutputoptions.hpp"
-#include "dialogs/storeprogress.hpp"
#include "toolbars/mainbar.hpp"
-#include "view/logicsignal.hpp"
#include "view/view.hpp"
-#include "widgets/exportmenu.hpp"
-#include "widgets/importmenu.hpp"
-#ifdef ENABLE_DECODE
-#include "widgets/decodermenu.hpp"
-#endif
-#include <inttypes.h>
#include <stdint.h>
#include <stdarg.h>
-#include <glib.h>
#include <libsigrokcxx/libsigrokcxx.hpp>
-using std::cerr;
-using std::endl;
using std::list;
using std::make_shared;
using std::map;
-using std::max;
-using std::pair;
using std::shared_ptr;
using std::string;
-using std::vector;
-
-using boost::algorithm::join;
-
-using sigrok::Error;
-using sigrok::OutputFormat;
-using sigrok::InputFormat;
namespace pv {
class ViewItem;
}
-const char *MainWindow::SettingOpenDirectory = "MainWindow/OpenDirectory";
-const char *MainWindow::SettingSaveDirectory = "MainWindow/SaveDirectory";
+using toolbars::MainBar;
MainWindow::MainWindow(DeviceManager &device_manager,
string open_file_name, string open_file_format,
QMainWindow(parent),
device_manager_(device_manager),
session_(device_manager),
- action_open_(new QAction(this)),
- action_save_as_(new QAction(this)),
- action_save_selection_as_(new QAction(this)),
- action_connect_(new QAction(this)),
- action_quit_(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)),
+ open_file_name_(open_file_name),
+ open_file_format_(open_file_format),
action_view_sticky_scrolling_(new QAction(this)),
action_view_coloured_bg_(new QAction(this)),
- action_view_show_cursors_(new QAction(this)),
action_about_(new QAction(this))
-#ifdef ENABLE_DECODE
- , menu_decoders_add_(new pv::widgets::DecoderMenu(this, true))
-#endif
{
qRegisterMetaType<util::Timestamp>("util::Timestamp");
setup_ui();
restore_ui_settings();
- if (open_file_name.empty())
- select_init_device();
- else
- load_init_file(open_file_name, open_file_format);
}
MainWindow::~MainWindow()
{
for (auto entry : view_docks_) {
+
const std::shared_ptr<QDockWidget> dock = entry.first;
+
+ // Remove view from the dock widget's QMainWindow
+ QMainWindow *dock_main = dynamic_cast<QMainWindow*>(dock->widget());
+ dock_main->setCentralWidget(0);
+
+ // Remove the QMainWindow
dock->setWidget(0);
+
const std::shared_ptr<pv::view::View> view = entry.second;
session_.deregister_view(view);
}
}
-QAction* MainWindow::action_open() const
-{
- return action_open_;
-}
-
-QAction* MainWindow::action_save_as() const
-{
- return action_save_as_;
-}
-
-QAction* MainWindow::action_save_selection_as() const
-{
- return action_save_selection_as_;
-}
-
-QAction* MainWindow::action_connect() const
-{
- return action_connect_;
-}
-
-QAction* MainWindow::action_quit() const
-{
- return action_quit_;
-}
-
-QAction* MainWindow::action_view_zoom_in() const
-{
- return action_view_zoom_in_;
-}
-
-QAction* MainWindow::action_view_zoom_out() const
-{
- return action_view_zoom_out_;
-}
-
-QAction* MainWindow::action_view_zoom_fit() const
-{
- return action_view_zoom_fit_;
-}
-
-QAction* MainWindow::action_view_zoom_one_to_one() const
-{
- return action_view_zoom_one_to_one_;
-}
-
QAction* MainWindow::action_view_sticky_scrolling() const
{
return action_view_sticky_scrolling_;
return action_view_coloured_bg_;
}
-QAction* MainWindow::action_view_show_cursors() const
-{
- return action_view_show_cursors_;
-}
-
QAction* MainWindow::action_about() const
{
return action_about_;
}
-#ifdef ENABLE_DECODE
-QMenu* MainWindow::menu_decoder_add() const
-{
- return menu_decoders_add_;
-}
-#endif
-
shared_ptr<pv::view::View> MainWindow::get_active_view() const
{
// If there's only one view, use it...
{
shared_ptr<pv::view::View> v;
- if (type == pv::view::TraceView)
- v = make_shared<pv::view::View>(session, this);
-
- if (v) {
+ if (type == pv::view::TraceView) {
shared_ptr<QDockWidget> dock = make_shared<QDockWidget>(title, this);
- dock->setWidget(v.get());
dock->setObjectName(title);
addDockWidget(Qt::TopDockWidgetArea, dock.get());
+
+ // Insert a QMainWindow into the dock widget to allow for a tool bar
+ QMainWindow *dock_main = new QMainWindow(dock.get());
+ dock_main->setWindowFlags(Qt::Widget); // Remove Qt::Window flag
+
+ v = make_shared<pv::view::View>(session, dock_main);
view_docks_[dock] = v;
+ session.register_view(v);
+
+ dock_main->setCentralWidget(v.get());
+ dock->setWidget(dock_main);
dock->setFeatures(QDockWidget::DockWidgetMovable |
QDockWidget::DockWidgetFloatable);
v->enable_sticky_scrolling(action_view_sticky_scrolling_->isChecked());
v->enable_coloured_bg(action_view_coloured_bg_->isChecked());
- action_view_show_cursors_->setChecked(v->cursors_shown());
- }
-
- session.register_view(v);
- }
-
- return v;
-}
-void MainWindow::run_stop()
-{
- switch (session_.get_capture_state()) {
- case Session::Stopped:
- session_.start_capture([&](QString message) {
- session_error("Capture failed", message); });
- break;
- case Session::AwaitingTrigger:
- case Session::Running:
- session_.stop_capture();
- break;
- }
-}
-
-void MainWindow::select_device(shared_ptr<devices::Device> device)
-{
- try {
- if (device)
- session_.set_device(device);
- else
- session_.set_default_device();
- } catch (const QString &e) {
- QMessageBox msg(this);
- msg.setText(e);
- msg.setInformativeText(tr("Failed to Select Device"));
- msg.setStandardButtons(QMessageBox::Ok);
- msg.setIcon(QMessageBox::Warning);
- msg.exec();
- }
-}
-
-void MainWindow::export_file(shared_ptr<OutputFormat> format,
- bool selection_only)
-{
- using pv::dialogs::StoreProgress;
-
- // Make sure there's a view selected to pull the data from
- shared_ptr<pv::view::View> view = get_active_view();
- if (!view) {
- show_session_error(tr("No View Selected"), tr("Please click on the " \
- "view whose data you want to save and try again."));
- return;
- }
-
- // Stop any currently running capture session
- session_.stop_capture();
-
- QSettings settings;
- const QString dir = settings.value(SettingSaveDirectory).toString();
-
- std::pair<uint64_t, uint64_t> sample_range;
-
- // Selection only? Verify that the cursors are active and fetch their values
- if (selection_only) {
- if (!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)."));
- return;
+ shared_ptr<MainBar> main_bar = session.main_bar();
+ if (!main_bar) {
+ main_bar = make_shared<MainBar>(session_, *this,
+ open_file_name_, open_file_format_);
+ dock_main->addToolBar(main_bar.get());
+ session.set_main_bar(main_bar);
+
+ open_file_name_.clear();
+ open_file_format_.clear();
+ }
+ main_bar->action_view_show_cursors()->setChecked(v->cursors_shown());
}
-
- const double samplerate = session_.get_samplerate();
-
- const pv::util::Timestamp& start_time = view->cursors()->first()->time();
- const pv::util::Timestamp& end_time = 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;
-
- sample_range = std::make_pair(start_sample, end_sample);
- } else {
- sample_range = std::make_pair(0, 0);
- }
-
- // Construct the filter
- const vector<string> exts = format->extensions();
- QString filter = tr("%1 files ").arg(
- QString::fromStdString(format->description()));
-
- if (exts.empty())
- filter += "(*.*)";
- else
- filter += QString("(*.%1);;%2 (*.*)").arg(
- QString::fromStdString(join(exts, ", *.")),
- tr("All Files"));
-
- // Show the file dialog
- const QString file_name = QFileDialog::getSaveFileName(
- this, tr("Save File"), dir, filter);
-
- if (file_name.isEmpty())
- return;
-
- const QString abs_path = QFileInfo(file_name).absolutePath();
- settings.setValue(SettingSaveDirectory, abs_path);
-
- // Show the options dialog
- map<string, Glib::VariantBase> options;
- if (!format->options().empty()) {
- dialogs::InputOutputOptions dlg(
- tr("Export %1").arg(QString::fromStdString(
- format->description())),
- format->options(), this);
- if (!dlg.exec())
- return;
- options = dlg.options();
}
- StoreProgress *dlg = new StoreProgress(file_name, format, options,
- sample_range, session_, this);
- dlg->run();
-}
-
-void MainWindow::import_file(shared_ptr<InputFormat> format)
-{
- assert(format);
-
- QSettings settings;
- const QString dir = settings.value(SettingOpenDirectory).toString();
-
- // 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, ", *.")));
-
- // 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())));
-
- if (file_name.isEmpty())
- return;
-
- // Show the options dialog
- map<string, Glib::VariantBase> options;
- if (!format->options().empty()) {
- dialogs::InputOutputOptions dlg(
- tr("Import %1").arg(QString::fromStdString(
- format->description())),
- format->options(), this);
- if (!dlg.exec())
- return;
- options = dlg.options();
- }
-
- load_file(file_name, format, options);
-
- const QString abs_path = QFileInfo(file_name).absolutePath();
- settings.setValue(SettingOpenDirectory, abs_path);
+ return v;
}
void MainWindow::setup_ui()
icon.addFile(QString(":/icons/sigrok-logo-notext.png"));
setWindowIcon(icon);
- action_open_->setText(tr("&Open..."));
- action_open_->setIcon(QIcon::fromTheme("document-open",
- QIcon(":/icons/document-open.png")));
- action_open_->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_O));
- action_open_->setObjectName(QString::fromUtf8("actionOpen"));
-
- action_save_as_->setText(tr("&Save As..."));
- action_save_as_->setIcon(QIcon::fromTheme("document-save-as",
- QIcon(":/icons/document-save-as.png")));
- action_save_as_->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_S));
- action_save_as_->setObjectName(QString::fromUtf8("actionSaveAs"));
-
- action_save_selection_as_->setText(tr("Save Selected &Range As..."));
- action_save_selection_as_->setIcon(QIcon::fromTheme("document-save-as",
- QIcon(":/icons/document-save-as.png")));
- action_save_selection_as_->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_R));
- action_save_selection_as_->setObjectName(QString::fromUtf8("actionSaveSelectionAs"));
-
- widgets::ExportMenu *menu_file_export = new widgets::ExportMenu(this,
- 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>)));
-
- widgets::ImportMenu *menu_file_import = new widgets::ImportMenu(this,
- 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>)));
-
- action_connect_->setText(tr("&Connect to Device..."));
- action_connect_->setObjectName(QString::fromUtf8("actionConnect"));
-
- action_quit_->setText(tr("&Quit"));
- action_quit_->setIcon(QIcon::fromTheme("application-exit",
- QIcon(":/icons/application-exit.png")));
- action_quit_->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q));
- action_quit_->setObjectName(QString::fromUtf8("actionQuit"));
-
- 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);
- action_view_zoom_in_->setObjectName(
- QString::fromUtf8("actionViewZoomIn"));
-
- 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);
- action_view_zoom_out_->setObjectName(
- QString::fromUtf8("actionViewZoomOut"));
-
- 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));
- action_view_zoom_fit_->setObjectName(
- QString::fromUtf8("actionViewZoomFit"));
-
- 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));
- action_view_zoom_one_to_one_->setObjectName(
- QString::fromUtf8("actionViewZoomOneToOne"));
-
action_view_sticky_scrolling_->setCheckable(true);
action_view_sticky_scrolling_->setChecked(true);
action_view_sticky_scrolling_->setShortcut(QKeySequence(Qt::Key_S));
QString::fromUtf8("actionViewColouredBg"));
action_view_coloured_bg_->setText(tr("Use &coloured backgrounds"));
- 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));
- action_view_show_cursors_->setObjectName(
- QString::fromUtf8("actionViewShowCursors"));
- action_view_show_cursors_->setText(tr("Show &Cursors"));
-
-#ifdef ENABLE_DECODE
- menu_decoders_add_->setTitle(tr("&Add"));
- connect(menu_decoders_add_, SIGNAL(decoder_selected(srd_decoder*)),
- this, SLOT(add_decoder(srd_decoder*)));
-#endif
-
action_about_->setObjectName(QString::fromUtf8("actionAbout"));
action_about_->setText(tr("&About..."));
- QMetaObject::connectSlotsByName(this);
-
- // Setup the toolbar
- main_bar_ = new toolbars::MainBar(session_, *this);
-
// Set up the initial view
- add_view(tr("Untitled"), pv::view::TraceView, session_);
-
- // Populate the device list and select the initially selected device
- update_device_list();
-
- addToolBar(main_bar_);
+ shared_ptr<view::View> main_view =
+ add_view(tr("Untitled"), pv::view::TraceView, session_);
// Set the title
setWindowTitle(tr("PulseView"));
-
- // Setup session_ events
- connect(&session_, SIGNAL(capture_state_changed(int)), this,
- SLOT(capture_state_changed(int)));
- connect(&session_, SIGNAL(device_selected()), this,
- SLOT(device_selected()));
-}
-
-void MainWindow::select_init_device()
-{
- QSettings settings;
- map<string, string> dev_info;
- list<string> key_list;
- shared_ptr<devices::HardwareDevice> device;
-
- // Re-select last used device if possible but only if it's not demo
- settings.beginGroup("Device");
- key_list.push_back("vendor");
- key_list.push_back("model");
- key_list.push_back("version");
- key_list.push_back("serial_num");
- key_list.push_back("connection_id");
-
- for (string key : key_list) {
- const QString k = QString::fromStdString(key);
- if (!settings.contains(k))
- continue;
-
- const string value = settings.value(k).toString().toStdString();
- if (!value.empty())
- dev_info.insert(std::make_pair(key, value));
- }
-
- if (dev_info.count("model") > 0)
- if (dev_info.at("model").find("Demo device") == std::string::npos)
- device = device_manager_.find_device_from_info(dev_info);
-
- // When we can't find a device similar to the one we used last
- // time and there is at least one device aside from demo, use it
- if (!device) {
- for (shared_ptr<devices::HardwareDevice> dev : device_manager_.devices()) {
- dev_info = device_manager_.get_device_info(dev);
-
- if (dev_info.count("model") > 0)
- if (dev_info.at("model").find("Demo device") == std::string::npos) {
- device = dev;
- break;
- }
- }
- }
-
- select_device(device);
- update_device_list();
-
- settings.endGroup();
}
-void MainWindow::load_init_file(const std::string &file_name,
- const std::string &format)
-{
- shared_ptr<InputFormat> input_format;
-
- if (!format.empty()) {
- const map<string, shared_ptr<InputFormat> > formats =
- device_manager_.context()->input_formats();
- const auto iter = find_if(formats.begin(), formats.end(),
- [&](const pair<string, shared_ptr<InputFormat> > f) {
- return f.first == format; });
- if (iter == formats.end()) {
- cerr << "Unexpected input format: " << format << endl;
- return;
- }
-
- input_format = (*iter).second;
- }
-
- load_file(QString::fromStdString(file_name), input_format);
-}
-
-
void MainWindow::save_ui_settings()
{
QSettings settings;
settings.endGroup();
}
-void MainWindow::session_error(
- const QString text, const QString info_text)
-{
- QMetaObject::invokeMethod(this, "show_session_error",
- Qt::QueuedConnection, Q_ARG(QString, text),
- Q_ARG(QString, info_text));
-}
-
-void MainWindow::update_device_list()
-{
- main_bar_->update_device_list();
-}
-
-void MainWindow::load_file(QString file_name,
- std::shared_ptr<sigrok::InputFormat> format,
- const std::map<std::string, Glib::VariantBase> &options)
-{
- const QString errorMessage(
- QString("Failed to load file %1").arg(file_name));
-
- try {
- if (format)
- session_.set_device(shared_ptr<devices::Device>(
- new devices::InputFile(
- device_manager_.context(),
- file_name.toStdString(),
- format, options)));
- else
- session_.set_device(shared_ptr<devices::Device>(
- new devices::SessionFile(
- device_manager_.context(),
- file_name.toStdString())));
- } catch (Error e) {
- show_session_error(tr("Failed to load ") + file_name, e.what());
- session_.set_default_device();
- update_device_list();
- return;
- }
-
- update_device_list();
-
- session_.start_capture([&, errorMessage](QString infoMessage) {
- session_error(errorMessage, infoMessage); });
-}
-
void MainWindow::closeEvent(QCloseEvent *event)
{
save_ui_settings();
event->accept();
}
-void MainWindow::keyReleaseEvent(QKeyEvent *event)
-{
- if (event->key() == Qt::Key_Alt) {
- menuBar()->setHidden(!menuBar()->isHidden());
- menuBar()->setFocus();
- }
- QMainWindow::keyReleaseEvent(event);
-}
-
QMenu* MainWindow::createPopupMenu()
{
return nullptr;
return false;
}
-void MainWindow::show_session_error(
- const QString text, const QString info_text)
-{
- QMessageBox msg(this);
- msg.setText(text);
- msg.setInformativeText(info_text);
- msg.setStandardButtons(QMessageBox::Ok);
- msg.setIcon(QMessageBox::Warning);
- msg.exec();
-}
-
-void MainWindow::on_actionOpen_triggered()
-{
- QSettings settings;
- const QString dir = settings.value(SettingOpenDirectory).toString();
-
- // Show the dialog
- const QString file_name = QFileDialog::getOpenFileName(
- this, tr("Open File"), dir, tr(
- "Sigrok Sessions (*.sr);;"
- "All Files (*.*)"));
-
- if (!file_name.isEmpty()) {
- load_file(file_name);
-
- const QString abs_path = QFileInfo(file_name).absolutePath();
- settings.setValue(SettingOpenDirectory, abs_path);
- }
-}
-
-void MainWindow::on_actionSaveAs_triggered()
-{
- export_file(device_manager_.context()->output_formats()["srzip"]);
-}
-
-void MainWindow::on_actionSaveSelectionAs_triggered()
-{
- export_file(device_manager_.context()->output_formats()["srzip"], true);
-}
-
-void MainWindow::on_actionConnect_triggered()
-{
- // Stop any currently running capture session
- session_.stop_capture();
-
- dialogs::Connect dlg(this, device_manager_);
-
- // If the user selected a device, select it in the device list. Select the
- // current device otherwise.
- if (dlg.exec())
- select_device(dlg.get_selected_device());
-
- update_device_list();
-}
-
-void MainWindow::on_actionQuit_triggered()
-{
- close();
-}
-
-void MainWindow::on_actionViewZoomIn_triggered()
-{
- shared_ptr<pv::view::View> view = get_active_view();
- if (view)
- view->zoom(1);
-}
-
-void MainWindow::on_actionViewZoomOut_triggered()
-{
- shared_ptr<pv::view::View> view = get_active_view();
- if (view)
- view->zoom(-1);
-}
-
-void MainWindow::on_actionViewZoomFit_triggered()
-{
- shared_ptr<pv::view::View> view = get_active_view();
- if (view)
- view->zoom_fit(action_view_zoom_fit_->isChecked());
-}
-
-void MainWindow::on_actionViewZoomOneToOne_triggered()
-{
- shared_ptr<pv::view::View> view = get_active_view();
- if (view)
- view->zoom_one_to_one();
-}
-
void MainWindow::on_actionViewStickyScrolling_triggered()
{
shared_ptr<pv::view::View> view = get_active_view();
view->enable_coloured_bg(action_view_coloured_bg_->isChecked());
}
-void MainWindow::on_actionViewShowCursors_triggered()
-{
- shared_ptr<pv::view::View> view = get_active_view();
- if (!view)
- return;
-
- const bool show = !view->cursors_shown();
- if (show)
- view->centre_cursors();
-
- view->show_cursors(show);
-}
-
void MainWindow::on_actionAbout_triggered()
{
dialogs::About dlg(device_manager_.context(), this);
dlg.exec();
}
-void MainWindow::sticky_scrolling_changed(bool state)
-{
- action_view_sticky_scrolling_->setChecked(state);
-}
-
-void MainWindow::always_zoom_to_fit_changed(bool state)
-{
- action_view_zoom_fit_->setChecked(state);
-}
-
-void MainWindow::add_decoder(srd_decoder *decoder)
-{
-#ifdef ENABLE_DECODE
- assert(decoder);
- session_.add_decoder(decoder);
-#else
- (void)decoder;
-#endif
-}
-
-void MainWindow::capture_state_changed(int state)
-{
- main_bar_->set_capture_state((pv::Session::capture_state)state);
-}
-
-void MainWindow::device_selected()
-{
- // Set the title to include the device/file name
- const shared_ptr<devices::Device> device = session_.device();
-
- if (!device) {
- main_bar_->reset_device_selector();
- return;
- }
-
- const string display_name = device->display_name(device_manager_);
- setWindowTitle(tr("%1 - PulseView").arg(display_name.c_str()));
-}
-
} // namespace pv
#include <map>
#include <memory>
-#include <glibmm/variant.h>
-
#include <QMainWindow>
#include "session.hpp"
class QVBoxLayout;
-namespace sigrok {
-class InputFormat;
-class OutputFormat;
-}
-
namespace pv {
class DeviceManager;
{
Q_OBJECT
-private:
- /**
- * Name of the setting used to remember the directory
- * containing the last file that was opened.
- */
- static const char *SettingOpenDirectory;
-
- /**
- * Name of the setting used to remember the directory
- * containing the last file that was saved.
- */
- static const char *SettingSaveDirectory;
-
public:
explicit MainWindow(DeviceManager &device_manager,
std::string open_file_name = std::string(),
~MainWindow();
- QAction* action_open() const;
- QAction* action_save_as() const;
- QAction* action_save_selection_as() const;
- QAction* action_connect() const;
- QAction* action_quit() const;
- QAction* action_view_zoom_in() const;
- QAction* action_view_zoom_out() const;
- QAction* action_view_zoom_fit() const;
- QAction* action_view_zoom_one_to_one() const;
QAction* action_view_sticky_scrolling() const;
QAction* action_view_coloured_bg() const;
- QAction* action_view_show_cursors() const;
QAction* action_about() const;
-#ifdef ENABLE_DECODE
- QMenu* menu_decoder_add() const;
-#endif
-
std::shared_ptr<pv::view::View> get_active_view() const;
std::shared_ptr<pv::view::View> add_view(const QString &title,
view::ViewType type, Session &session);
- void run_stop();
-
- void select_device(std::shared_ptr<devices::Device> device);
-
-public Q_SLOTS:
- void export_file(std::shared_ptr<sigrok::OutputFormat> format,
- bool selection_only = false);
- void import_file(std::shared_ptr<sigrok::InputFormat> format);
-
private:
void setup_ui();
- void select_init_device();
-
- void load_init_file(const std::string &file_name,
- const std::string &format);
-
void save_ui_settings();
void restore_ui_settings();
- void session_error(const QString text, const QString info_text);
-
- /**
- * Updates the device list in the toolbar
- */
- void update_device_list();
-
- void load_file(QString file_name,
- std::shared_ptr<sigrok::InputFormat> format = nullptr,
- const std::map<std::string, Glib::VariantBase> &options =
- std::map<std::string, Glib::VariantBase>());
-
- void save_selection_to_file();
-
private:
void closeEvent(QCloseEvent *event);
- void keyReleaseEvent(QKeyEvent *event);
-
virtual QMenu* createPopupMenu();
virtual bool restoreState(const QByteArray &state, int version = 0);
private Q_SLOTS:
- void show_session_error(
- const QString text, const QString info_text);
-
- void on_actionOpen_triggered();
- void on_actionSaveAs_triggered();
- void on_actionSaveSelectionAs_triggered();
- void on_actionQuit_triggered();
-
- void on_actionConnect_triggered();
-
- void on_actionViewZoomIn_triggered();
-
- void on_actionViewZoomOut_triggered();
-
- void on_actionViewZoomFit_triggered();
-
- void on_actionViewZoomOneToOne_triggered();
-
void on_actionViewStickyScrolling_triggered();
void on_actionViewColouredBg_triggered();
- void on_actionViewShowCursors_triggered();
-
void on_actionAbout_triggered();
- void add_decoder(srd_decoder *decoder);
-
- void capture_state_changed(int state);
- void device_selected();
-
- void sticky_scrolling_changed(bool state);
-
- void always_zoom_to_fit_changed(bool state);
-
private:
DeviceManager &device_manager_;
std::map< std::shared_ptr<QDockWidget>,
std::shared_ptr<pv::view::View> > view_docks_;
- toolbars::MainBar *main_bar_;
-
- QAction *const action_open_;
- QAction *const action_save_as_;
- QAction *const action_save_selection_as_;
- QAction *const action_connect_;
- QAction *const action_quit_;
- QAction *const action_view_zoom_in_;
- QAction *const action_view_zoom_out_;
- QAction *const action_view_zoom_fit_;
- QAction *const action_view_zoom_one_to_one_;
+ std::string open_file_name_, open_file_format_;
+
QAction *const action_view_sticky_scrolling_;
QAction *const action_view_coloured_bg_;
- QAction *const action_view_show_cursors_;
QAction *const action_about_;
-
-#ifdef ENABLE_DECODE
- QMenu *const menu_decoders_add_;
-#endif
};
} // namespace pv
#include "devices/hardwaredevice.hpp"
#include "devices/sessionfile.hpp"
+#include "toolbars/mainbar.hpp"
+
#include "view/analogsignal.hpp"
#include "view/decodetrace.hpp"
#include "view/logicsignal.hpp"
return device_;
}
+std::shared_ptr<pv::view::View> Session::main_view() const
+{
+ return main_view_;
+}
+
+void Session::set_main_bar(std::shared_ptr<pv::toolbars::MainBar> main_bar)
+{
+ main_bar_ = main_bar;
+}
+
+shared_ptr<pv::toolbars::MainBar> Session::main_bar() const
+{
+ return main_bar_;
+}
+
void Session::set_device(shared_ptr<devices::Device> device)
{
assert(device);
void Session::register_view(std::shared_ptr<pv::view::View> view)
{
+ if (views_.empty()) {
+ main_view_ = view;
+ }
+
views_.insert(view);
}
void Session::deregister_view(std::shared_ptr<pv::view::View> view)
{
views_.erase(view);
+
+ if (views_.empty()) {
+ main_view_.reset();
+
+ // Without a view there can be no main bar
+ main_bar_.reset();
+ }
}
double Session::get_samplerate() const
class Device;
}
+namespace toolbars {
+class MainBar;
+}
+
namespace view {
class View;
}
std::shared_ptr<devices::Device> device() const;
+ std::shared_ptr<pv::view::View> main_view() const;
+
+ void set_main_bar(std::shared_ptr<pv::toolbars::MainBar> main_bar);
+
+ std::shared_ptr<pv::toolbars::MainBar> main_bar() const;
+
/**
* Sets device instance that will be used in the next capture session.
*/
std::shared_ptr<devices::Device> device_;
std::unordered_set< std::shared_ptr<pv::view::View> > views_;
+ std::shared_ptr<pv::view::View> main_view_;
+
+ std::shared_ptr<pv::toolbars::MainBar> main_bar_;
mutable std::mutex sampling_mutex_; //!< Protects access to capture_state_.
capture_state capture_state_;
#include <QAction>
#include <QDebug>
+#include <QFileDialog>
#include <QHelpEvent>
#include <QMenu>
+#include <QMessageBox>
+#include <QSettings>
#include <QToolTip>
#include "mainbar.hpp"
+#include <boost/algorithm/string/join.hpp>
+
#include <pv/devicemanager.hpp>
#include <pv/devices/hardwaredevice.hpp>
+#include <pv/devices/inputfile.hpp>
+#include <pv/devices/sessionfile.hpp>
+#include <pv/dialogs/connect.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/util.hpp>
+#include <pv/view/view.hpp>
#include <pv/widgets/exportmenu.hpp>
#include <pv/widgets/importmenu.hpp>
+#ifdef ENABLE_DECODE
+#include <pv/widgets/decodermenu.hpp>
+#endif
#include <libsigrokcxx/libsigrokcxx.hpp>
using std::back_inserter;
+using std::cerr;
using std::copy;
+using std::endl;
using std::list;
using std::map;
using std::max;
using std::min;
+using std::pair;
using std::shared_ptr;
using std::string;
using std::vector;
using sigrok::ConfigKey;
using sigrok::Error;
using sigrok::InputFormat;
+using sigrok::OutputFormat;
+
+using boost::algorithm::join;
namespace pv {
namespace toolbars {
const uint64_t MainBar::MaxSampleCount = 1000000000000ULL;
const uint64_t MainBar::DefaultSampleCount = 1000000;
-MainBar::MainBar(Session &session, MainWindow &main_window) :
+const char *MainBar::SettingOpenDirectory = "MainWindow/OpenDirectory";
+const char *MainBar::SettingSaveDirectory = "MainWindow/SaveDirectory";
+
+MainBar::MainBar(Session &session, MainWindow &main_window,
+ string open_file_name, string open_file_format) :
QToolBar("Sampling Bar", &main_window),
+ 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),
- main_window_(main_window),
- device_selector_(this, session.device_manager(),
- main_window.action_connect()),
+ device_selector_(&main_window, session.device_manager(),
+ action_connect_),
configure_button_(this),
configure_button_action_(nullptr),
channels_button_(this),
run_stop_button_(this),
run_stop_button_action_(nullptr),
menu_button_(this)
+#ifdef ENABLE_DECODE
+ , menu_decoders_add_(new pv::widgets::DecoderMenu(this, true))
+#endif
{
setObjectName(QString::fromUtf8("MainBar"));
setFloatable(false);
setContextMenuPolicy(Qt::PreventContextMenu);
+ // Actions
+ action_open_->setText(tr("&Open..."));
+ action_open_->setIcon(QIcon::fromTheme("document-open",
+ QIcon(":/icons/document-open.png")));
+ action_open_->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_O));
+ action_open_->setObjectName(QString::fromUtf8("actionOpen"));
+
+ action_save_as_->setText(tr("&Save As..."));
+ action_save_as_->setIcon(QIcon::fromTheme("document-save-as",
+ QIcon(":/icons/document-save-as.png")));
+ action_save_as_->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_S));
+ action_save_as_->setObjectName(QString::fromUtf8("actionSaveAs"));
+
+ action_save_selection_as_->setText(tr("Save Selected &Range As..."));
+ action_save_selection_as_->setIcon(QIcon::fromTheme("document-save-as",
+ QIcon(":/icons/document-save-as.png")));
+ action_save_selection_as_->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_R));
+ action_save_selection_as_->setObjectName(QString::fromUtf8("actionSaveSelectionAs"));
+
+ widgets::ExportMenu *menu_file_export = new widgets::ExportMenu(this,
+ 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>)));
+
+ 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>)));
+
+ action_connect_->setText(tr("&Connect to Device..."));
+ action_connect_->setObjectName(QString::fromUtf8("actionConnect"));
+
+ 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);
+ action_view_zoom_in_->setObjectName(
+ QString::fromUtf8("actionViewZoomIn"));
+
+ 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);
+ action_view_zoom_out_->setObjectName(
+ QString::fromUtf8("actionViewZoomOut"));
+
+ 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));
+ action_view_zoom_fit_->setObjectName(
+ QString::fromUtf8("actionViewZoomFit"));
+
+ 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));
+ action_view_zoom_one_to_one_->setObjectName(
+ QString::fromUtf8("actionViewZoomOneToOne"));
+
+ 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));
+ action_view_show_cursors_->setObjectName(
+ QString::fromUtf8("actionViewShowCursors"));
+ 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(),
- main_window.action_open());
+ session.device_manager().context(), action_open_);
connect(import_menu,
SIGNAL(format_selected(std::shared_ptr<sigrok::InputFormat>)),
- &main_window_,
+ &main_window,
SLOT(import_file(std::shared_ptr<sigrok::InputFormat>)));
open_button->setMenu(import_menu);
- open_button->setDefaultAction(main_window.action_open());
+ 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(main_window.action_save_as());
- open_actions.push_back(main_window.action_save_selection_as());
+ open_actions.push_back(action_save_as_);
+ open_actions.push_back(action_save_selection_as_);
widgets::ExportMenu *export_menu = new widgets::ExportMenu(this,
session.device_manager().context(),
open_actions);
connect(export_menu,
SIGNAL(format_selected(std::shared_ptr<sigrok::OutputFormat>)),
- &main_window_,
+ &main_window,
SLOT(export_file(std::shared_ptr<sigrok::OutputFormat>)));
save_button->setMenu(export_menu);
- save_button->setDefaultAction(main_window.action_save_as());
+ save_button->setDefaultAction(action_save_as_);
save_button->setPopupMode(QToolButton::MenuButtonPopup);
// Device selector menu
// Setup the decoder button
#ifdef ENABLE_DECODE
+ menu_decoders_add_->setTitle(tr("&Add"));
+ 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(main_window_.menu_decoder_add());
+ add_decoder_button->setMenu(menu_decoders_add_);
#endif
- // Setup the burger menu
- QMenu *const menu = new QMenu(this);
-
- QMenu *const menu_view = new QMenu;
- menu_view->setTitle(tr("&View"));
- menu_view->addAction(main_window.action_view_sticky_scrolling());
- menu_view->addSeparator();
- menu_view->addAction(main_window.action_view_coloured_bg());
-
- QMenu *const menu_help = new QMenu;
- menu_help->setTitle(tr("&Help"));
- menu_help->addAction(main_window.action_about());
-
- menu->addAction(menu_view->menuAction());
- menu->addSeparator();
- menu->addAction(menu_help->menuAction());
- menu->addSeparator();
- menu->addAction(main_window.action_quit());
-
- menu_button_.setMenu(menu);
- menu_button_.setPopupMode(QToolButton::InstantPopup);
- menu_button_.setIcon(QIcon::fromTheme("menu",
- QIcon(":/icons/menu.svg")));
-
// Setup the toolbar
addWidget(open_button);
addWidget(save_button);
addSeparator();
- addAction(main_window.action_view_zoom_in());
- addAction(main_window.action_view_zoom_out());
- addAction(main_window.action_view_zoom_fit());
- addAction(main_window.action_view_zoom_one_to_one());
+ addAction(action_view_zoom_in_);
+ addAction(action_view_zoom_out_);
+ addAction(action_view_zoom_fit_);
+ addAction(action_view_zoom_one_to_one_);
addSeparator();
- addAction(main_window.action_view_show_cursors());
+ addAction(action_view_show_cursors_);
addSeparator();
connect(&run_stop_button_, SIGNAL(clicked()),
sample_count_.installEventFilter(this);
sample_rate_.installEventFilter(this);
+
+ QMetaObject::connectSlotsByName(this);
+
+ // Setup session_ events
+ connect(&session_, SIGNAL(capture_state_changed(int)), this,
+ SLOT(capture_state_changed(int)));
+ connect(&session_, SIGNAL(device_selected()), this,
+ SLOT(device_selected()));
+
+ // Figure out which file/device to use
+ if (open_file_name.empty())
+ select_init_device();
+ else
+ load_init_file(open_file_name, open_file_format);
+}
+
+Session &MainBar::session(void) const
+{
+ return session_;
}
void MainBar::update_device_list()
device_selector_.reset();
}
+QAction* MainBar::action_open() const
+{
+ return action_open_;
+}
+
+QAction* MainBar::action_save_as() const
+{
+ return action_save_as_;
+}
+
+QAction* MainBar::action_save_selection_as() const
+{
+ return action_save_selection_as_;
+}
+
+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::run_stop()
+{
+ switch (session_.get_capture_state()) {
+ case Session::Stopped:
+ session_.start_capture([&](QString message) {
+ session_error("Capture failed", message); });
+ break;
+ case Session::AwaitingTrigger:
+ case Session::Running:
+ session_.stop_capture();
+ break;
+ }
+}
+
+void MainBar::select_device(shared_ptr<devices::Device> device)
+{
+ try {
+ if (device)
+ session_.set_device(device);
+ else
+ session_.set_default_device();
+ } catch (const QString &e) {
+ QMessageBox msg(this);
+ msg.setText(e);
+ msg.setInformativeText(tr("Failed to Select Device"));
+ msg.setStandardButtons(QMessageBox::Ok);
+ msg.setIcon(QMessageBox::Warning);
+ msg.exec();
+ }
+}
+
+void MainBar::select_init_device()
+{
+ QSettings settings;
+ map<string, string> dev_info;
+ list<string> key_list;
+ shared_ptr<devices::HardwareDevice> device;
+
+ DeviceManager& device_manager = session_.device_manager();
+
+ // Re-select last used device if possible but only if it's not demo
+ settings.beginGroup("Device");
+ key_list.push_back("vendor");
+ key_list.push_back("model");
+ key_list.push_back("version");
+ key_list.push_back("serial_num");
+ key_list.push_back("connection_id");
+
+ for (string key : key_list) {
+ const QString k = QString::fromStdString(key);
+ if (!settings.contains(k))
+ continue;
+
+ const string value = settings.value(k).toString().toStdString();
+ if (!value.empty())
+ dev_info.insert(std::make_pair(key, value));
+ }
+
+ if (dev_info.count("model") > 0)
+ if (dev_info.at("model").find("Demo device") == std::string::npos)
+ device = device_manager.find_device_from_info(dev_info);
+
+ // When we can't find a device similar to the one we used last
+ // time and there is at least one device aside from demo, use it
+ if (!device) {
+ for (shared_ptr<devices::HardwareDevice> dev : device_manager.devices()) {
+ dev_info = device_manager.get_device_info(dev);
+
+ if (dev_info.count("model") > 0)
+ if (dev_info.at("model").find("Demo device") == std::string::npos) {
+ device = dev;
+ break;
+ }
+ }
+ }
+
+ select_device(device);
+ update_device_list();
+
+ settings.endGroup();
+}
+
+void MainBar::load_file(QString file_name,
+ std::shared_ptr<sigrok::InputFormat> format,
+ const std::map<std::string, Glib::VariantBase> &options)
+{
+ DeviceManager& device_manager = session_.device_manager();
+
+ const QString errorMessage(
+ QString("Failed to load file %1").arg(file_name));
+
+ try {
+ if (format)
+ session_.set_device(shared_ptr<devices::Device>(
+ new devices::InputFile(
+ device_manager.context(),
+ file_name.toStdString(),
+ format, options)));
+ else
+ session_.set_device(shared_ptr<devices::Device>(
+ new devices::SessionFile(
+ device_manager.context(),
+ file_name.toStdString())));
+ } catch (Error e) {
+ show_session_error(tr("Failed to load ") + file_name, e.what());
+ session_.set_default_device();
+ update_device_list();
+ return;
+ }
+
+ update_device_list();
+
+ session_.start_capture([&, errorMessage](QString infoMessage) {
+ session_error(errorMessage, infoMessage); });
+}
+
+void MainBar::load_init_file(const std::string &file_name,
+ const std::string &format)
+{
+ shared_ptr<InputFormat> input_format;
+
+ DeviceManager& device_manager = session_.device_manager();
+
+ if (!format.empty()) {
+ const map<string, shared_ptr<InputFormat> > formats =
+ device_manager.context()->input_formats();
+ const auto iter = find_if(formats.begin(), formats.end(),
+ [&](const pair<string, shared_ptr<InputFormat> > f) {
+ return f.first == format; });
+ if (iter == formats.end()) {
+ cerr << "Unexpected input format: " << format << endl;
+ return;
+ }
+
+ input_format = (*iter).second;
+ }
+
+ load_file(QString::fromStdString(file_name), input_format);
+}
+
void MainBar::update_sample_rate_selector()
{
Glib::VariantContainerBase gvar_dict;
update_sample_rate_selector();
}
+void MainBar::commit_sample_rate()
+{
+ uint64_t sample_rate = 0;
+
+ const shared_ptr<devices::Device> device =
+ device_selector_.selected_device();
+ if (!device)
+ return;
+
+ const shared_ptr<sigrok::Device> sr_dev = device->device();
+
+ sample_rate = sample_rate_.value();
+ if (sample_rate == 0)
+ return;
+
+ try {
+ sr_dev->config_set(ConfigKey::SAMPLERATE,
+ Glib::Variant<guint64>::create(sample_rate));
+ update_sample_rate_selector();
+ } catch (Error error) {
+ qDebug() << "Failed to configure samplerate.";
+ return;
+ }
+
+ // Devices with built-in memory might impose limits on certain
+ // configurations, so let's check what sample count the driver
+ // lets us use now.
+ update_sample_count_selector();
+}
+
void MainBar::commit_sample_count()
{
uint64_t sample_count = 0;
update_sample_rate_selector();
}
-void MainBar::commit_sample_rate()
+void MainBar::session_error(const QString text, const QString info_text)
{
- uint64_t sample_rate = 0;
+ QMetaObject::invokeMethod(this, "show_session_error",
+ Qt::QueuedConnection, Q_ARG(QString, text),
+ Q_ARG(QString, info_text));
+}
- const shared_ptr<devices::Device> device =
- device_selector_.selected_device();
- if (!device)
- return;
+void MainBar::show_session_error(const QString text, const QString info_text)
+{
+ QMessageBox msg(this);
+ msg.setText(text);
+ msg.setInformativeText(info_text);
+ msg.setStandardButtons(QMessageBox::Ok);
+ msg.setIcon(QMessageBox::Warning);
+ msg.exec();
+}
- const shared_ptr<sigrok::Device> sr_dev = device->device();
+void MainBar::capture_state_changed(int state)
+{
+ set_capture_state((pv::Session::capture_state)state);
+}
- sample_rate = sample_rate_.value();
- if (sample_rate == 0)
+void MainBar::add_decoder(srd_decoder *decoder)
+{
+#ifdef ENABLE_DECODE
+ assert(decoder);
+ session_.add_decoder(decoder);
+#else
+ (void)decoder;
+#endif
+}
+
+void MainBar::export_file(shared_ptr<OutputFormat> format,
+ bool selection_only)
+{
+ using pv::dialogs::StoreProgress;
+
+ // Stop any currently running capture session
+ session_.stop_capture();
+
+ QSettings settings;
+ const QString dir = settings.value(SettingSaveDirectory).toString();
+
+ std::pair<uint64_t, uint64_t> sample_range;
+
+ // Selection only? Verify that the cursors are active and fetch their values
+ if (selection_only) {
+ if (!session_.main_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)."));
+ return;
+ }
+
+ const double samplerate = session_.get_samplerate();
+
+ const pv::util::Timestamp& start_time = session_.main_view()->cursors()->first()->time();
+ const pv::util::Timestamp& end_time = session_.main_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;
+
+ sample_range = std::make_pair(start_sample, end_sample);
+ } else {
+ sample_range = std::make_pair(0, 0);
+ }
+
+ // Construct the filter
+ const vector<string> exts = format->extensions();
+ QString filter = tr("%1 files ").arg(
+ QString::fromStdString(format->description()));
+
+ if (exts.empty())
+ filter += "(*.*)";
+ else
+ filter += QString("(*.%1);;%2 (*.*)").arg(
+ QString::fromStdString(join(exts, ", *.")),
+ tr("All Files"));
+
+ // Show the file dialog
+ const QString file_name = QFileDialog::getSaveFileName(
+ this, tr("Save File"), dir, filter);
+
+ if (file_name.isEmpty())
return;
- try {
- sr_dev->config_set(ConfigKey::SAMPLERATE,
- Glib::Variant<guint64>::create(sample_rate));
- update_sample_rate_selector();
- } catch (Error error) {
- qDebug() << "Failed to configure samplerate.";
+ const QString abs_path = QFileInfo(file_name).absolutePath();
+ settings.setValue(SettingSaveDirectory, abs_path);
+
+ // Show the options dialog
+ map<string, Glib::VariantBase> options;
+ if (!format->options().empty()) {
+ dialogs::InputOutputOptions dlg(
+ tr("Export %1").arg(QString::fromStdString(
+ format->description())),
+ format->options(), this);
+ if (!dlg.exec())
+ return;
+ options = dlg.options();
+ }
+
+ StoreProgress *dlg = new StoreProgress(file_name, format, options,
+ sample_range, session_, this);
+ dlg->run();
+}
+
+void MainBar::import_file(shared_ptr<InputFormat> format)
+{
+ assert(format);
+
+ QSettings settings;
+ const QString dir = settings.value(SettingOpenDirectory).toString();
+
+ // 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, ", *.")));
+
+ // 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())));
+
+ if (file_name.isEmpty())
return;
+
+ // Show the options dialog
+ map<string, Glib::VariantBase> options;
+ if (!format->options().empty()) {
+ dialogs::InputOutputOptions dlg(
+ tr("Import %1").arg(QString::fromStdString(
+ format->description())),
+ format->options(), this);
+ if (!dlg.exec())
+ return;
+ options = dlg.options();
}
- // Devices with built-in memory might impose limits on certain
- // configurations, so let's check what sample count the driver
- // lets us use now.
- update_sample_count_selector();
+ load_file(file_name, format, options);
+
+ const QString abs_path = QFileInfo(file_name).absolutePath();
+ settings.setValue(SettingOpenDirectory, abs_path);
}
void MainBar::on_device_selected()
{
shared_ptr<devices::Device> device = device_selector_.selected_device();
- if (!device)
+ if (!device) {
+ reset_device_selector();
return;
+ }
- main_window_.select_device(device);
+ select_device(device);
update_device_config_widgets();
}
{
commit_sample_count();
commit_sample_rate();
- main_window_.run_stop();
+ run_stop();
}
void MainBar::on_config_changed()
commit_sample_rate();
}
+void MainBar::on_actionOpen_triggered()
+{
+ QSettings settings;
+ const QString dir = settings.value(SettingOpenDirectory).toString();
+
+ // Show the dialog
+ const QString file_name = QFileDialog::getOpenFileName(
+ this, tr("Open File"), dir, tr(
+ "Sigrok Sessions (*.sr);;"
+ "All Files (*.*)"));
+
+ if (!file_name.isEmpty()) {
+ load_file(file_name);
+
+ const QString abs_path = QFileInfo(file_name).absolutePath();
+ settings.setValue(SettingOpenDirectory, abs_path);
+ }
+}
+
+void MainBar::on_actionSaveAs_triggered()
+{
+ export_file(session_.device_manager().context()->output_formats()["srzip"]);
+}
+
+void MainBar::on_actionSaveSelectionAs_triggered()
+{
+ export_file(session_.device_manager().context()->output_formats()["srzip"], true);
+}
+
+void MainBar::on_actionConnect_triggered()
+{
+ // Stop any currently running capture session
+ session_.stop_capture();
+
+ dialogs::Connect dlg(this, session_.device_manager());
+
+ // If the user selected a device, select it in the device list. Select the
+ // current device otherwise.
+ if (dlg.exec())
+ select_device(dlg.get_selected_device());
+
+ update_device_list();
+}
+
+void MainBar::on_actionViewZoomIn_triggered()
+{
+ session_.main_view()->zoom(1);
+}
+
+void MainBar::on_actionViewZoomOut_triggered()
+{
+ session_.main_view()->zoom(-1);
+}
+
+void MainBar::on_actionViewZoomFit_triggered()
+{
+ session_.main_view()->zoom_fit(action_view_zoom_fit_->isChecked());
+}
+
+void MainBar::on_actionViewZoomOneToOne_triggered()
+{
+ session_.main_view()->zoom_one_to_one();
+}
+
+void MainBar::on_actionViewShowCursors_triggered()
+{
+ const bool show = !session_.main_view()->cursors_shown();
+ if (show)
+ session_.main_view()->centre_cursors();
+
+ session_.main_view()->show_cursors(show);
+}
+
bool MainBar::eventFilter(QObject *watched, QEvent *event)
{
if (sample_count_supported_ && (watched == &sample_count_ ||
#include <list>
#include <memory>
+#include <glibmm/variant.h>
+
#include <QComboBox>
#include <QDoubleSpinBox>
#include <QMenu>
namespace sigrok {
class Device;
class InputFormat;
+class OutputFormat;
}
Q_DECLARE_METATYPE(std::shared_ptr<sigrok::Device>)
static const uint64_t MaxSampleCount;
static const uint64_t DefaultSampleCount;
+ /**
+ * Name of the setting used to remember the directory
+ * containing the last file that was opened.
+ */
+ static const char *SettingOpenDirectory;
+
+ /**
+ * Name of the setting used to remember the directory
+ * containing the last file that was saved.
+ */
+ static const char *SettingSaveDirectory;
+
public:
- MainBar(Session &session, pv::MainWindow &main_window);
+ MainBar(Session &session, pv::MainWindow &main_window,
+ std::string open_file_name = std::string(),
+ std::string open_file_format = std::string());
+
+ Session &session(void) const;
void update_device_list();
void reset_device_selector();
+ QAction* action_open() const;
+ QAction* action_save_as() const;
+ QAction* action_save_selection_as() const;
+ QAction* action_connect() const;
+ QAction* action_quit() const;
+ QAction* action_view_zoom_in() const;
+ QAction* action_view_zoom_out() const;
+ QAction* action_view_zoom_fit() const;
+ QAction* action_view_zoom_one_to_one() const;
+ QAction* action_view_show_cursors() const;
+
private:
+ void run_stop();
+
+ void select_device(std::shared_ptr<devices::Device> device);
+
+ void select_init_device();
+
+ void load_file(QString file_name,
+ std::shared_ptr<sigrok::InputFormat> format = nullptr,
+ const std::map<std::string, Glib::VariantBase> &options =
+ std::map<std::string, Glib::VariantBase>());
+
+ void load_init_file(const std::string &file_name,
+ const std::string &format);
+
+ void save_selection_to_file();
+
void update_sample_rate_selector();
void update_sample_rate_selector_value();
void update_sample_count_selector();
void commit_sample_rate();
void commit_sample_count();
+ void session_error(const QString text, const QString info_text);
+
+ QAction *const action_open_;
+ QAction *const action_save_as_;
+ QAction *const action_save_selection_as_;
+ QAction *const action_connect_;
+ QAction *const action_view_zoom_in_;
+ QAction *const action_view_zoom_out_;
+ QAction *const action_view_zoom_fit_;
+ QAction *const action_view_zoom_one_to_one_;
+ QAction *const action_view_show_cursors_;
+
private Q_SLOTS:
+ void show_session_error(const QString text, const QString info_text);
+
+ void capture_state_changed(int state);
+
+ void add_decoder(srd_decoder *decoder);
+
+ void export_file(std::shared_ptr<sigrok::OutputFormat> format,
+ bool selection_only = false);
+ void import_file(std::shared_ptr<sigrok::InputFormat> format);
+
void on_device_selected();
void on_sample_count_changed();
void on_sample_rate_changed();
void on_config_changed();
+ void on_actionOpen_triggered();
+ void on_actionSaveAs_triggered();
+ void on_actionSaveSelectionAs_triggered();
+
+ void on_actionConnect_triggered();
+
+ void on_actionViewZoomIn_triggered();
+
+ void on_actionViewZoomOut_triggered();
+
+ void on_actionViewZoomFit_triggered();
+
+ void on_actionViewZoomOneToOne_triggered();
+
+ void on_actionViewShowCursors_triggered();
+
protected:
bool eventFilter(QObject *watched, QEvent *event);
private:
Session &session_;
- MainWindow &main_window_;
pv::widgets::DeviceToolButton device_selector_;
QAction *run_stop_button_action_;
QToolButton menu_button_;
+
+#ifdef ENABLE_DECODE
+ QMenu *const menu_decoders_add_;
+#endif
};
} // namespace toolbars