Commit 57f55429a9dd072757ffc87d223cb0c0cbec6362
Committed by
David Gräff
1 parent
832fe655
Exporting refactored: Plugin like structure with a central registry and GUI independence
Showing
17 changed files
with
655 additions
and
216 deletions
openhantek/src/exporting/exportcsv.cpp
0 → 100644
| 1 | +// SPDX-License-Identifier: GPL-2.0+ | |
| 2 | + | |
| 3 | +#include "exportcsv.h" | |
| 4 | +#include "exporterregistry.h" | |
| 5 | +#include "post/ppresult.h" | |
| 6 | +#include "settings.h" | |
| 7 | +#include "iconfont/QtAwesome.h" | |
| 8 | + | |
| 9 | +#include <QCoreApplication> | |
| 10 | +#include <QTextStream> | |
| 11 | +#include <QFile> | |
| 12 | +#include <QFileDialog> | |
| 13 | + | |
| 14 | +ExporterCSV::ExporterCSV() {} | |
| 15 | + | |
| 16 | +void ExporterCSV::create(ExporterRegistry *registry) { this->registry = registry; data.reset(); } | |
| 17 | + | |
| 18 | +QIcon ExporterCSV::icon() { return iconFont->icon(fa::filetexto); } | |
| 19 | + | |
| 20 | +QString ExporterCSV::name() { return QCoreApplication::tr("Export CSV"); } | |
| 21 | + | |
| 22 | +ExporterInterface::Type ExporterCSV::type() { return Type::SnapshotExport; } | |
| 23 | + | |
| 24 | +bool ExporterCSV::samples(const std::shared_ptr<PPresult> data) { | |
| 25 | + this->data = std::move(data); | |
| 26 | + return false; | |
| 27 | +} | |
| 28 | + | |
| 29 | +bool ExporterCSV::save() { | |
| 30 | + QStringList filters; | |
| 31 | + filters << QCoreApplication::tr("Comma-Separated Values (*.csv)"); | |
| 32 | + | |
| 33 | + QFileDialog fileDialog(nullptr, QCoreApplication::tr("Export file..."), QString(), filters.join(";;")); | |
| 34 | + fileDialog.setFileMode(QFileDialog::AnyFile); | |
| 35 | + fileDialog.setAcceptMode(QFileDialog::AcceptSave); | |
| 36 | + if (fileDialog.exec() != QDialog::Accepted) return false; | |
| 37 | + | |
| 38 | + QFile csvFile(fileDialog.selectedFiles().first()); | |
| 39 | + if (!csvFile.open(QIODevice::WriteOnly | QIODevice::Text)) return false; | |
| 40 | + | |
| 41 | + QTextStream csvStream(&csvFile); | |
| 42 | + csvStream.setRealNumberNotation(QTextStream::FixedNotation); | |
| 43 | + csvStream.setRealNumberPrecision(10); | |
| 44 | + | |
| 45 | + size_t chCount = registry->settings->scope.voltage.size(); | |
| 46 | + std::vector<const SampleValues *> voltageData(size_t(chCount), nullptr); | |
| 47 | + std::vector<const SampleValues *> spectrumData(size_t(chCount), nullptr); | |
| 48 | + size_t maxRow = 0; | |
| 49 | + bool isSpectrumUsed = false; | |
| 50 | + double timeInterval = 0; | |
| 51 | + double freqInterval = 0; | |
| 52 | + | |
| 53 | + for (ChannelID channel = 0; channel < chCount; ++channel) { | |
| 54 | + if (data->data(channel)) { | |
| 55 | + if (registry->settings->scope.voltage[channel].used) { | |
| 56 | + voltageData[channel] = &(data->data(channel)->voltage); | |
| 57 | + maxRow = std::max(maxRow, voltageData[channel]->sample.size()); | |
| 58 | + timeInterval = data->data(channel)->voltage.interval; | |
| 59 | + } | |
| 60 | + if (registry->settings->scope.spectrum[channel].used) { | |
| 61 | + spectrumData[channel] = &(data->data(channel)->spectrum); | |
| 62 | + maxRow = std::max(maxRow, spectrumData[channel]->sample.size()); | |
| 63 | + freqInterval = data->data(channel)->spectrum.interval; | |
| 64 | + isSpectrumUsed = true; | |
| 65 | + } | |
| 66 | + } | |
| 67 | + } | |
| 68 | + | |
| 69 | + // Start with channel names | |
| 70 | + csvStream << "\"t\""; | |
| 71 | + for (ChannelID channel = 0; channel < chCount; ++channel) { | |
| 72 | + if (voltageData[channel] != nullptr) { csvStream << ",\"" << registry->settings->scope.voltage[channel].name << "\""; } | |
| 73 | + } | |
| 74 | + if (isSpectrumUsed) { | |
| 75 | + csvStream << ",\"f\""; | |
| 76 | + for (ChannelID channel = 0; channel < chCount; ++channel) { | |
| 77 | + if (spectrumData[channel] != nullptr) { | |
| 78 | + csvStream << ",\"" << registry->settings->scope.spectrum[channel].name << "\""; | |
| 79 | + } | |
| 80 | + } | |
| 81 | + } | |
| 82 | + csvStream << "\n"; | |
| 83 | + | |
| 84 | + for (unsigned int row = 0; row < maxRow; ++row) { | |
| 85 | + | |
| 86 | + csvStream << timeInterval * row; | |
| 87 | + for (ChannelID channel = 0; channel < chCount; ++channel) { | |
| 88 | + if (voltageData[channel] != nullptr) { | |
| 89 | + csvStream << ","; | |
| 90 | + if (row < voltageData[channel]->sample.size()) { csvStream << voltageData[channel]->sample[row]; } | |
| 91 | + } | |
| 92 | + } | |
| 93 | + | |
| 94 | + if (isSpectrumUsed) { | |
| 95 | + csvStream << "," << freqInterval * row; | |
| 96 | + for (ChannelID channel = 0; channel < chCount; ++channel) { | |
| 97 | + if (spectrumData[channel] != nullptr) { | |
| 98 | + csvStream << ","; | |
| 99 | + if (row < spectrumData[channel]->sample.size()) { csvStream << spectrumData[channel]->sample[row]; } | |
| 100 | + } | |
| 101 | + } | |
| 102 | + } | |
| 103 | + csvStream << "\n"; | |
| 104 | + } | |
| 105 | + | |
| 106 | + csvFile.close(); | |
| 107 | + | |
| 108 | + return true; | |
| 109 | +} | |
| 110 | + | |
| 111 | +float ExporterCSV::progress() { return data ? 1.0f : 0; } | ... | ... |
openhantek/src/exporting/exportcsv.h
0 → 100644
| 1 | +// SPDX-License-Identifier: GPL-2.0+ | |
| 2 | + | |
| 3 | +#pragma once | |
| 4 | +#include "exporterinterface.h" | |
| 5 | + | |
| 6 | +class ExporterCSV : public ExporterInterface | |
| 7 | +{ | |
| 8 | +public: | |
| 9 | + ExporterCSV(); | |
| 10 | + virtual void create(ExporterRegistry *registry) override; | |
| 11 | + virtual QIcon icon() override; | |
| 12 | + virtual QString name() override; | |
| 13 | + virtual Type type() override; | |
| 14 | + virtual bool samples(const std::shared_ptr<PPresult>data) override; | |
| 15 | + virtual bool save() override; | |
| 16 | + virtual float progress() override; | |
| 17 | +private: | |
| 18 | + std::shared_ptr<PPresult> data; | |
| 19 | +}; | ... | ... |
openhantek/src/exporting/exporter.h deleted
| 1 | -// SPDX-License-Identifier: GPL-2.0+ | |
| 2 | - | |
| 3 | -#pragma once | |
| 4 | - | |
| 5 | -#include <QPainter> | |
| 6 | -#include <QPrinter> | |
| 7 | -#include <QSize> | |
| 8 | -#include <memory> | |
| 9 | -#include "exportsettings.h" | |
| 10 | - | |
| 11 | -class DsoSettings; | |
| 12 | -class PPresult; | |
| 13 | -struct DsoSettingsColorValues; | |
| 14 | -namespace Dso { struct ControlSpecification; } | |
| 15 | - | |
| 16 | -/// \brief Exports the oscilloscope screen to a file or prints it. | |
| 17 | -class Exporter { | |
| 18 | - public: | |
| 19 | - static Exporter *createPrintExporter(const Dso::ControlSpecification* deviceSpecification, DsoSettings *settings); | |
| 20 | - static Exporter *createSaveToFileExporter(const Dso::ControlSpecification* deviceSpecification, DsoSettings *settings); | |
| 21 | - | |
| 22 | - /// \brief Print the document (May be a file too) | |
| 23 | - bool exportSamples(const PPresult *result); | |
| 24 | - | |
| 25 | - private: | |
| 26 | - Exporter(const Dso::ControlSpecification* deviceSpecification, DsoSettings *settings, const QString &filename, ExportFormat format); | |
| 27 | - void setFormat(ExportFormat format); | |
| 28 | - bool exportCSV(const PPresult *result); | |
| 29 | - static std::unique_ptr<QPrinter> printPaintDevice(DsoSettings *settings); | |
| 30 | - void drawGrids(QPainter &painter, DsoSettingsColorValues *colorValues, double lineHeight, double scopeHeight, | |
| 31 | - int scopeWidth); | |
| 32 | - const Dso::ControlSpecification* deviceSpecification; | |
| 33 | - DsoSettings *settings; | |
| 34 | - std::unique_ptr<QPrinter> selectedPrinter; | |
| 35 | - | |
| 36 | - QString filename; | |
| 37 | - ExportFormat format; | |
| 38 | -}; |
openhantek/src/exporting/exporterinterface.h
0 → 100644
| 1 | +// SPDX-License-Identifier: GPL-2.0+ | |
| 2 | + | |
| 3 | +#pragma once | |
| 4 | + | |
| 5 | +#include <QIcon> | |
| 6 | +#include <QString> | |
| 7 | + | |
| 8 | +#include <memory> | |
| 9 | + | |
| 10 | +class ExporterRegistry; | |
| 11 | +class PPresult; | |
| 12 | + | |
| 13 | +/** | |
| 14 | + * Implement this interface and register your Exporter to the ExporterRegistry instance | |
| 15 | + * in the main routine to make an Exporter available. | |
| 16 | + */ | |
| 17 | +class ExporterInterface { | |
| 18 | +public: | |
| 19 | + | |
| 20 | + /** | |
| 21 | + * Starts up this exporter. Aquires resources etc. Do not call this directly, it | |
| 22 | + * will be called by the exporter registry at some point. Release your resources in the | |
| 23 | + * destructor as usual. | |
| 24 | + * @param registry The exporter registry instance. This is used to obtain a reference | |
| 25 | + * to the settings. | |
| 26 | + */ | |
| 27 | + virtual void create(ExporterRegistry *registry) = 0; | |
| 28 | + | |
| 29 | + /** | |
| 30 | + * @return Return the icon representation of this exporter. Will be used in graphical | |
| 31 | + * interfaces. | |
| 32 | + */ | |
| 33 | + virtual QIcon icon() = 0; | |
| 34 | + | |
| 35 | + /** | |
| 36 | + * @return Return the text representation / name of this exporter. Will be used in graphical | |
| 37 | + * interfaces. | |
| 38 | + */ | |
| 39 | + virtual QString name() = 0; | |
| 40 | + | |
| 41 | + /** | |
| 42 | + * Exporters can save only a single sample set or save data continously. | |
| 43 | + */ | |
| 44 | + enum class Type { SnapshotExport, ContinousExport }; | |
| 45 | + | |
| 46 | + /** | |
| 47 | + * @return Return the type of this exporter. | |
| 48 | + * @see ExporterInterface::Type | |
| 49 | + */ | |
| 50 | + virtual Type type() = 0; | |
| 51 | + | |
| 52 | + /** | |
| 53 | + * A new sample set from the ExporterRegistry. The exporter needs to be active to receive samples. | |
| 54 | + * If it is a snapshot exporter, only one set of samples will be received. | |
| 55 | + * @return Return true if you want to receive another sample or false if you are done (progres()==1). | |
| 56 | + */ | |
| 57 | + virtual bool samples(const std::shared_ptr<PPresult>) = 0; | |
| 58 | + | |
| 59 | + /** | |
| 60 | + * Exporter: Save your received data and perform any conversions necessary. | |
| 61 | + * This method will be called in the | |
| 62 | + * GUI thread context and can create and show dialogs if required. | |
| 63 | + * @return Return true if saving succedded otherwise false. | |
| 64 | + */ | |
| 65 | + virtual bool save() = 0; | |
| 66 | + | |
| 67 | + /** | |
| 68 | + * @brief The progress of receiving and processing samples. If the exporter returns 1, it will | |
| 69 | + * be called back by the GUI via the save() method. | |
| 70 | + * | |
| 71 | + * @return A number between 0..1 indicating the used capacity of this exporter. If this is a | |
| 72 | + * snapshot exporter, only 0 for "no samples processed yet" or 1 for "finished" will be returned. | |
| 73 | + * A continous exporter may report the used memory / reservered memory ratio here. | |
| 74 | + */ | |
| 75 | + virtual float progress() = 0; | |
| 76 | +protected: | |
| 77 | + ExporterRegistry *registry; | |
| 78 | +}; | ... | ... |
openhantek/src/exporting/exporterprocessor.cpp
0 → 100644
openhantek/src/exporting/exporterprocessor.h
0 → 100644
| 1 | +#pragma once | |
| 2 | + | |
| 3 | +#include "post/processor.h" | |
| 4 | + | |
| 5 | +class ExporterRegistry; | |
| 6 | + | |
| 7 | +class ExporterProcessor : public Processor | |
| 8 | +{ | |
| 9 | +public: | |
| 10 | + ExporterProcessor(ExporterRegistry* registry); | |
| 11 | + virtual void process(PPresult *) override; | |
| 12 | +private: | |
| 13 | + ExporterRegistry* registry; | |
| 14 | +}; | ... | ... |
openhantek/src/exporting/exporterregistry.cpp
0 → 100644
| 1 | +// SPDX-License-Identifier: GPL-2.0+ | |
| 2 | + | |
| 3 | +#include "exporterregistry.h" | |
| 4 | +#include "exporterinterface.h" | |
| 5 | + | |
| 6 | +#include <algorithm> | |
| 7 | + | |
| 8 | +#include "controlspecification.h" | |
| 9 | +#include "post/ppresult.h" | |
| 10 | +#include "settings.h" | |
| 11 | + | |
| 12 | +ExporterRegistry::ExporterRegistry(const Dso::ControlSpecification *deviceSpecification, DsoSettings *settings, | |
| 13 | + QObject *parent) | |
| 14 | + : QObject(parent), deviceSpecification(deviceSpecification), settings(settings) {} | |
| 15 | + | |
| 16 | +bool ExporterRegistry::processData(std::shared_ptr<PPresult> &data, ExporterInterface *const &exporter) { | |
| 17 | + if (!exporter->samples(data)) { | |
| 18 | + waitToSaveExporters.insert(exporter); | |
| 19 | + emit exporterProgressChanged(); | |
| 20 | + return true; | |
| 21 | + } | |
| 22 | + return false; | |
| 23 | +} | |
| 24 | + | |
| 25 | +void ExporterRegistry::addRawSamples(PPresult *d) { | |
| 26 | + if (settings->exporting.useProcessedSamples) return; | |
| 27 | + std::shared_ptr<PPresult> data(d); | |
| 28 | + enabledExporters.remove_if([&data, this](ExporterInterface *const &i) { return processData(data, i); }); | |
| 29 | +} | |
| 30 | + | |
| 31 | +void ExporterRegistry::input(std::shared_ptr<PPresult> data) { | |
| 32 | + if (!settings->exporting.useProcessedSamples) return; | |
| 33 | + enabledExporters.remove_if([&data, this](ExporterInterface *const &i) { return processData(data, i); }); | |
| 34 | +} | |
| 35 | + | |
| 36 | +void ExporterRegistry::registerExporter(ExporterInterface *exporter) { | |
| 37 | + exporters.push_back(exporter); | |
| 38 | + exporter->create(this); | |
| 39 | +} | |
| 40 | + | |
| 41 | +void ExporterRegistry::setExporterEnabled(ExporterInterface *exporter, bool enabled) { | |
| 42 | + bool wasInList = false; | |
| 43 | + enabledExporters.remove_if([exporter, &wasInList](ExporterInterface *inlist) { | |
| 44 | + if (inlist == exporter) { | |
| 45 | + wasInList = true; | |
| 46 | + return true; | |
| 47 | + } else | |
| 48 | + return false; | |
| 49 | + }); | |
| 50 | + | |
| 51 | + if (enabled) { | |
| 52 | + // If the exporter was waiting for the user save confirmation, | |
| 53 | + // reset it instead. | |
| 54 | + auto localFind = waitToSaveExporters.find(exporter); | |
| 55 | + if (localFind != waitToSaveExporters.end()) { | |
| 56 | + waitToSaveExporters.erase(localFind); | |
| 57 | + exporter->create(this); | |
| 58 | + } | |
| 59 | + enabledExporters.push_back(exporter); | |
| 60 | + } else if (wasInList) { | |
| 61 | + // If exporter made some progress: Add to waiting for GUI list | |
| 62 | + if (exporter->progress() > 0) { | |
| 63 | + waitToSaveExporters.insert(exporter); | |
| 64 | + emit exporterProgressChanged(); | |
| 65 | + } else // Reset exporter | |
| 66 | + exporter->create(this); | |
| 67 | + } | |
| 68 | +} | |
| 69 | + | |
| 70 | +void ExporterRegistry::checkForWaitingExporters() { | |
| 71 | + for (ExporterInterface *exporter : waitToSaveExporters) { | |
| 72 | + if (exporter->save()) { | |
| 73 | + emit exporterStatusChanged(exporter->name(), tr("Data saved")); | |
| 74 | + } else { | |
| 75 | + emit exporterStatusChanged(exporter->name(), tr("No data exported")); | |
| 76 | + } | |
| 77 | + exporter->create(this); | |
| 78 | + } | |
| 79 | + waitToSaveExporters.clear(); | |
| 80 | +} | |
| 81 | + | |
| 82 | +std::vector<ExporterInterface *>::const_iterator ExporterRegistry::begin() { return exporters.begin(); } | |
| 83 | + | |
| 84 | +std::vector<ExporterInterface *>::const_iterator ExporterRegistry::end() { return exporters.end(); } | ... | ... |
openhantek/src/exporting/exporterregistry.h
0 → 100644
| 1 | +// SPDX-License-Identifier: GPL-2.0+ | |
| 2 | + | |
| 3 | +#pragma once | |
| 4 | + | |
| 5 | +#include <QObject> | |
| 6 | +#include <memory> | |
| 7 | +#include <set> | |
| 8 | +#include <vector> | |
| 9 | + | |
| 10 | +// Post processing forwards | |
| 11 | +class Processor; | |
| 12 | +class PPresult; | |
| 13 | + | |
| 14 | +// Settings forwards | |
| 15 | +class DsoSettings; | |
| 16 | +namespace Dso { | |
| 17 | +struct ControlSpecification; | |
| 18 | +} | |
| 19 | + | |
| 20 | +// Exporter forwards | |
| 21 | +class ExporterInterface; | |
| 22 | + | |
| 23 | +class ExporterRegistry : public QObject { | |
| 24 | + Q_OBJECT | |
| 25 | + public: | |
| 26 | + explicit ExporterRegistry(const Dso::ControlSpecification *deviceSpecification, DsoSettings *settings, | |
| 27 | + QObject *parent = nullptr); | |
| 28 | + | |
| 29 | + // Sample input. This will proably be performed in the post processing | |
| 30 | + // thread context. Do not open GUI dialogs or interrupt the control flow. | |
| 31 | + void addRawSamples(PPresult *data); | |
| 32 | + void input(std::shared_ptr<PPresult> data); | |
| 33 | + | |
| 34 | + void registerExporter(ExporterInterface *exporter); | |
| 35 | + void setExporterEnabled(ExporterInterface *exporter, bool enabled); | |
| 36 | + | |
| 37 | + void checkForWaitingExporters(); | |
| 38 | + | |
| 39 | + // Iterate over this class object | |
| 40 | + std::vector<ExporterInterface *>::const_iterator begin(); | |
| 41 | + std::vector<ExporterInterface *>::const_iterator end(); | |
| 42 | + | |
| 43 | + /// Device specifications | |
| 44 | + const Dso::ControlSpecification *deviceSpecification; | |
| 45 | + const DsoSettings *settings; | |
| 46 | + | |
| 47 | + private: | |
| 48 | + /// List of all available exporters | |
| 49 | + std::vector<ExporterInterface *> exporters; | |
| 50 | + /// List of exporters that collect samples at the moment | |
| 51 | + std::list<ExporterInterface *> enabledExporters; | |
| 52 | + /// List of exporters that wait to be called back by the user to save their work | |
| 53 | + std::set<ExporterInterface *> waitToSaveExporters; | |
| 54 | + | |
| 55 | + /// Process data from addRawSamples() or input() in the given exporter. Add the | |
| 56 | + /// exporter to waitToSaveExporters if it finishes. | |
| 57 | + /// | |
| 58 | + /// @return Return true if the exporter has finished and want to be removed from the | |
| 59 | + /// enabledExporters list. | |
| 60 | + bool processData(std::shared_ptr<PPresult> &data, ExporterInterface *const &exporter); | |
| 61 | + signals: | |
| 62 | + void exporterStatusChanged(const QString &exporterName, const QString &status); | |
| 63 | + void exporterProgressChanged(); | |
| 64 | +}; | ... | ... |
openhantek/src/exporting/exportimage.cpp
0 → 100644
| 1 | +// SPDX-License-Identifier: GPL-2.0+ | |
| 2 | + | |
| 3 | +#include "exportimage.h" | |
| 4 | +#include "exporterregistry.h" | |
| 5 | +#include "iconfont/QtAwesome.h" | |
| 6 | +#include "legacyexportdrawer.h" | |
| 7 | +#include "post/ppresult.h" | |
| 8 | +#include "settings.h" | |
| 9 | +#include "viewsettings.h" | |
| 10 | + | |
| 11 | +#include <QCoreApplication> | |
| 12 | +#include <QFileDialog> | |
| 13 | +#include <QPrinter> | |
| 14 | + | |
| 15 | +ExporterImage::ExporterImage() {} | |
| 16 | + | |
| 17 | +void ExporterImage::create(ExporterRegistry *registry) { this->registry = registry; data.reset(); } | |
| 18 | + | |
| 19 | +QIcon ExporterImage::icon() { return iconFont->icon(fa::image); } | |
| 20 | + | |
| 21 | +QString ExporterImage::name() { return QCoreApplication::tr("Export Image/PDF"); } | |
| 22 | + | |
| 23 | +ExporterInterface::Type ExporterImage::type() { return Type::SnapshotExport; } | |
| 24 | + | |
| 25 | +bool ExporterImage::samples(const std::shared_ptr<PPresult> data) { | |
| 26 | + this->data = std::move(data); | |
| 27 | + return false; | |
| 28 | +} | |
| 29 | + | |
| 30 | +bool ExporterImage::save() { | |
| 31 | + QStringList filters; | |
| 32 | + filters << QCoreApplication::tr("Portable Document Format (*.pdf)") | |
| 33 | + << QCoreApplication::tr("Image (*.png *.xpm *.jpg)"); | |
| 34 | + | |
| 35 | + QFileDialog fileDialog(nullptr, QCoreApplication::tr("Export file..."), QString(), filters.join(";;")); | |
| 36 | + fileDialog.setFileMode(QFileDialog::AnyFile); | |
| 37 | + fileDialog.setAcceptMode(QFileDialog::AcceptSave); | |
| 38 | + if (fileDialog.exec() != QDialog::Accepted) return false; | |
| 39 | + | |
| 40 | + bool isPdf = filters.indexOf(fileDialog.selectedNameFilter()) == 0; | |
| 41 | + std::unique_ptr<QPaintDevice> paintDevice; | |
| 42 | + | |
| 43 | + const DsoSettingsColorValues *colorValues = &(registry->settings->view.print); | |
| 44 | + | |
| 45 | + if (!isPdf) { | |
| 46 | + // We need a QPixmap for image-export | |
| 47 | + QPixmap *qPixmap = new QPixmap(registry->settings->exporting.imageSize); | |
| 48 | + qPixmap->fill(colorValues->background); | |
| 49 | + paintDevice = std::unique_ptr<QPaintDevice>(qPixmap); | |
| 50 | + } else { | |
| 51 | + // We need a QPrinter for printing, pdf- and ps-export | |
| 52 | + std::unique_ptr<QPrinter> printer = std::unique_ptr<QPrinter>(new QPrinter(QPrinter::HighResolution)); | |
| 53 | + printer->setOrientation(registry->settings->view.zoom ? QPrinter::Portrait : QPrinter::Landscape); | |
| 54 | + printer->setPageMargins(20, 20, 20, 20, QPrinter::Millimeter); | |
| 55 | + printer->setOutputFileName(fileDialog.selectedFiles().first()); | |
| 56 | + printer->setOutputFormat(QPrinter::PdfFormat); | |
| 57 | + paintDevice = std::move(printer); | |
| 58 | + } | |
| 59 | + | |
| 60 | + if (!paintDevice) return false; | |
| 61 | + | |
| 62 | + LegacyExportDrawer::exportSamples(data.get(), paintDevice.get(), registry->deviceSpecification, registry->settings, | |
| 63 | + false, colorValues); | |
| 64 | + | |
| 65 | + if (!isPdf) static_cast<QPixmap *>(paintDevice.get())->save(fileDialog.selectedFiles().first()); | |
| 66 | + return true; | |
| 67 | +} | |
| 68 | + | |
| 69 | +float ExporterImage::progress() { return data ? 1.0f : 0; } | ... | ... |
openhantek/src/exporting/exportimage.h
0 → 100644
| 1 | +// SPDX-License-Identifier: GPL-2.0+ | |
| 2 | + | |
| 3 | +#pragma once | |
| 4 | +#include "exporterinterface.h" | |
| 5 | + | |
| 6 | +class ExporterImage : public ExporterInterface | |
| 7 | +{ | |
| 8 | +public: | |
| 9 | + ExporterImage(); | |
| 10 | + virtual void create(ExporterRegistry *registry) override; | |
| 11 | + virtual QIcon icon() override; | |
| 12 | + virtual QString name() override; | |
| 13 | + virtual Type type() override; | |
| 14 | + virtual bool samples(const std::shared_ptr<PPresult>data) override; | |
| 15 | + virtual bool save() override; | |
| 16 | + virtual float progress() override; | |
| 17 | +private: | |
| 18 | + std::shared_ptr<PPresult> data; | |
| 19 | +}; | ... | ... |
openhantek/src/exporting/exportprint.cpp
0 → 100644
| 1 | +// SPDX-License-Identifier: GPL-2.0+ | |
| 2 | + | |
| 3 | +#include "exportprint.h" | |
| 4 | +#include "exporterregistry.h" | |
| 5 | +#include "iconfont/QtAwesome.h" | |
| 6 | +#include "legacyexportdrawer.h" | |
| 7 | +#include "post/ppresult.h" | |
| 8 | +#include "settings.h" | |
| 9 | +#include "viewsettings.h" | |
| 10 | + | |
| 11 | +#include <QCoreApplication> | |
| 12 | +#include <QPrintDialog> | |
| 13 | +#include <QPrinter> | |
| 14 | + | |
| 15 | +ExporterPrint::ExporterPrint() {} | |
| 16 | + | |
| 17 | +void ExporterPrint::create(ExporterRegistry *registry) { this->registry = registry; data.reset(); } | |
| 18 | + | |
| 19 | +QIcon ExporterPrint::icon() { return iconFont->icon(fa::print); } | |
| 20 | + | |
| 21 | +QString ExporterPrint::name() { return QCoreApplication::tr("Print"); } | |
| 22 | + | |
| 23 | +ExporterInterface::Type ExporterPrint::type() { return Type::SnapshotExport; } | |
| 24 | + | |
| 25 | +bool ExporterPrint::samples(const std::shared_ptr<PPresult> data) { | |
| 26 | + this->data = std::move(data); | |
| 27 | + return false; | |
| 28 | +} | |
| 29 | + | |
| 30 | +bool ExporterPrint::save() { | |
| 31 | + // We need a QPrinter for printing, pdf- and ps-export | |
| 32 | + std::unique_ptr<QPrinter> printer = std::unique_ptr<QPrinter>(new QPrinter(QPrinter::HighResolution)); | |
| 33 | + printer->setOrientation(registry->settings->view.zoom ? QPrinter::Portrait : QPrinter::Landscape); | |
| 34 | + printer->setPageMargins(20, 20, 20, 20, QPrinter::Millimeter); | |
| 35 | + | |
| 36 | + // Show the printing dialog | |
| 37 | + QPrintDialog dialog(printer.get()); | |
| 38 | + dialog.setWindowTitle(QCoreApplication::tr("Print oscillograph")); | |
| 39 | + if (dialog.exec() != QDialog::Accepted) { return false; } | |
| 40 | + | |
| 41 | + const DsoSettingsColorValues *colorValues = &(registry->settings->view.print); | |
| 42 | + | |
| 43 | + LegacyExportDrawer::exportSamples(data.get(), printer.get(), registry->deviceSpecification, registry->settings, | |
| 44 | + true, colorValues); | |
| 45 | + | |
| 46 | + return true; | |
| 47 | +} | |
| 48 | + | |
| 49 | +float ExporterPrint::progress() { return data ? 1.0f : 0; } | ... | ... |
openhantek/src/exporting/exportprint.h
0 → 100644
| 1 | +// SPDX-License-Identifier: GPL-2.0+ | |
| 2 | + | |
| 3 | +#pragma once | |
| 4 | +#include "exporterinterface.h" | |
| 5 | + | |
| 6 | +class ExporterPrint : public ExporterInterface | |
| 7 | +{ | |
| 8 | +public: | |
| 9 | + ExporterPrint(); | |
| 10 | + virtual void create(ExporterRegistry *registry) override; | |
| 11 | + virtual QIcon icon() override; | |
| 12 | + virtual QString name() override; | |
| 13 | + virtual Type type() override; | |
| 14 | + virtual bool samples(const std::shared_ptr<PPresult>data) override; | |
| 15 | + virtual bool save() override; | |
| 16 | + virtual float progress() override; | |
| 17 | +private: | |
| 18 | + std::shared_ptr<PPresult> data; | |
| 19 | +}; | ... | ... |
openhantek/src/exporting/exportsettings.h
| ... | ... | @@ -4,10 +4,9 @@ |
| 4 | 4 | |
| 5 | 5 | #include <QSize> |
| 6 | 6 | |
| 7 | -/// \brief Holds the general options of the program. | |
| 7 | +/// \brief Holds the export options of the program. | |
| 8 | 8 | struct DsoSettingsExport { |
| 9 | 9 | QSize imageSize = QSize(640, 480); ///< Size of exported images in pixels |
| 10 | + unsigned exportSizeBytes = 1024*1024*10; ///< For exporters that save a continous stream. Default: 10 Megabytes | |
| 11 | + bool useProcessedSamples = true; ///< Export raw or processed samples | |
| 10 | 12 | }; |
| 11 | - | |
| 12 | -/// \brief Possible file formats for the export. | |
| 13 | -enum ExportFormat { EXPORT_FORMAT_PRINTER, EXPORT_FORMAT_PDF, EXPORT_FORMAT_IMAGE, EXPORT_FORMAT_CSV }; | ... | ... |
openhantek/src/exporting/exporter.cpp renamed to openhantek/src/exporting/legacyexportdrawer.cpp
| ... | ... | @@ -5,101 +5,29 @@ |
| 5 | 5 | #include <memory> |
| 6 | 6 | |
| 7 | 7 | #include <QCoreApplication> |
| 8 | -#include <QFile> | |
| 9 | -#include <QFileDialog> | |
| 10 | 8 | #include <QImage> |
| 11 | -#include <QMutex> | |
| 12 | 9 | #include <QPainter> |
| 13 | -#include <QPixmap> | |
| 14 | -#include <QPrintDialog> | |
| 15 | -#include <QPrinter> | |
| 16 | -#include <QTextStream> | |
| 17 | 10 | |
| 18 | -#include "exporter.h" | |
| 11 | +#include "legacyexportdrawer.h" | |
| 19 | 12 | |
| 20 | 13 | #include "controlspecification.h" |
| 21 | 14 | #include "post/graphgenerator.h" |
| 22 | 15 | #include "post/ppresult.h" |
| 23 | 16 | #include "settings.h" |
| 24 | -#include "utils/dsoStrings.h" | |
| 25 | 17 | #include "utils/printutils.h" |
| 26 | 18 | #include "viewconstants.h" |
| 27 | 19 | |
| 28 | 20 | #define tr(msg) QCoreApplication::translate("Exporter", msg) |
| 29 | 21 | |
| 30 | -Exporter::Exporter(const Dso::ControlSpecification *deviceSpecification, DsoSettings *settings, const QString &filename, | |
| 31 | - ExportFormat format) | |
| 32 | - : deviceSpecification(deviceSpecification), settings(settings), filename(filename), format(format) {} | |
| 33 | - | |
| 34 | -Exporter *Exporter::createPrintExporter(const Dso::ControlSpecification *deviceSpecification, DsoSettings *settings) { | |
| 35 | - std::unique_ptr<QPrinter> printer = printPaintDevice(settings); | |
| 36 | - // Show the printing dialog | |
| 37 | - QPrintDialog dialog(printer.get()); | |
| 38 | - dialog.setWindowTitle(tr("Print oscillograph")); | |
| 39 | - if (dialog.exec() != QDialog::Accepted) { return nullptr; } | |
| 40 | - | |
| 41 | - Exporter *exporter = new Exporter(deviceSpecification, settings, QString(), EXPORT_FORMAT_PRINTER); | |
| 42 | - exporter->selectedPrinter = std::move(printer); | |
| 43 | - return exporter; | |
| 44 | -} | |
| 45 | - | |
| 46 | -Exporter *Exporter::createSaveToFileExporter(const Dso::ControlSpecification *deviceSpecification, | |
| 47 | - DsoSettings *settings) { | |
| 48 | - QStringList filters; | |
| 49 | - filters << tr("Portable Document Format (*.pdf)") << tr("Image (*.png *.xpm *.jpg)") | |
| 50 | - << tr("Comma-Separated Values (*.csv)"); | |
| 51 | - | |
| 52 | - QFileDialog fileDialog(nullptr, tr("Export file..."), QString(), filters.join(";;")); | |
| 53 | - fileDialog.setFileMode(QFileDialog::AnyFile); | |
| 54 | - fileDialog.setAcceptMode(QFileDialog::AcceptSave); | |
| 55 | - if (fileDialog.exec() != QDialog::Accepted) return nullptr; | |
| 56 | - | |
| 57 | - return new Exporter(deviceSpecification, settings, fileDialog.selectedFiles().first(), | |
| 58 | - (ExportFormat)(EXPORT_FORMAT_PDF + filters.indexOf(fileDialog.selectedNameFilter()))); | |
| 59 | -} | |
| 60 | - | |
| 61 | -std::unique_ptr<QPrinter> Exporter::printPaintDevice(DsoSettings *settings) { | |
| 62 | - // We need a QPrinter for printing, pdf- and ps-export | |
| 63 | - std::unique_ptr<QPrinter> printer = std::unique_ptr<QPrinter>(new QPrinter(QPrinter::HighResolution)); | |
| 64 | - printer->setOrientation(settings->view.zoom ? QPrinter::Portrait : QPrinter::Landscape); | |
| 65 | - printer->setPageMargins(20, 20, 20, 20, QPrinter::Millimeter); | |
| 66 | - return printer; | |
| 67 | -} | |
| 68 | - | |
| 69 | -bool Exporter::exportSamples(const PPresult *result) { | |
| 70 | - if (this->format == EXPORT_FORMAT_CSV) { return exportCSV(result); } | |
| 71 | - | |
| 72 | - // Choose the color values we need | |
| 73 | - DsoSettingsColorValues *colorValues; | |
| 74 | - if (this->format == EXPORT_FORMAT_IMAGE && settings->view.screenColorImages) | |
| 75 | - colorValues = &(settings->view.screen); | |
| 76 | - else | |
| 77 | - colorValues = &(settings->view.print); | |
| 78 | - | |
| 79 | - std::unique_ptr<QPaintDevice> paintDevice; | |
| 80 | - | |
| 81 | - if (this->format == EXPORT_FORMAT_IMAGE) { | |
| 82 | - // We need a QPixmap for image-export | |
| 83 | - QPixmap *qPixmap = new QPixmap(settings->exporting.imageSize); | |
| 84 | - qPixmap->fill(colorValues->background); | |
| 85 | - paintDevice = std::unique_ptr<QPaintDevice>(qPixmap); | |
| 86 | - } else if (this->format == EXPORT_FORMAT_PRINTER) { | |
| 87 | - paintDevice = std::move(selectedPrinter); | |
| 88 | - } else { | |
| 89 | - std::unique_ptr<QPrinter> printer = printPaintDevice(settings); | |
| 90 | - printer->setOutputFileName(this->filename); | |
| 91 | - printer->setOutputFormat((this->format == EXPORT_FORMAT_PDF) ? QPrinter::PdfFormat : QPrinter::NativeFormat); | |
| 92 | - paintDevice = std::move(printer); | |
| 93 | - } | |
| 94 | - | |
| 95 | - if (!paintDevice) return false; | |
| 96 | - | |
| 22 | +bool LegacyExportDrawer::exportSamples(const PPresult *result, QPaintDevice* paintDevice, | |
| 23 | + const Dso::ControlSpecification *deviceSpecification, | |
| 24 | + const DsoSettings *settings, bool isPrinter, const DsoSettingsColorValues *colorValues) { | |
| 97 | 25 | // Create a painter for our device |
| 98 | - QPainter painter(paintDevice.get()); | |
| 26 | + QPainter painter(paintDevice); | |
| 99 | 27 | |
| 100 | 28 | // Get line height |
| 101 | 29 | QFont font; |
| 102 | - QFontMetrics fontMetrics(font, paintDevice.get()); | |
| 30 | + QFontMetrics fontMetrics(font, paintDevice); | |
| 103 | 31 | double lineHeight = fontMetrics.height(); |
| 104 | 32 | |
| 105 | 33 | painter.setBrush(Qt::SolidPattern); |
| ... | ... | @@ -150,12 +78,12 @@ bool Exporter::exportSamples(const PPresult *result) { |
| 150 | 78 | painter.drawText(QRectF(0, top, lineHeight * 4, lineHeight), settings->scope.voltage[channel].name); |
| 151 | 79 | // Print coupling/math mode |
| 152 | 80 | if ((unsigned int)channel < deviceSpecification->channels) |
| 81 | + painter.drawText(QRectF(lineHeight * 4, top, lineHeight * 2, lineHeight), | |
| 82 | + Dso::couplingString(settings->scope.coupling(channel, deviceSpecification))); | |
| 83 | + else | |
| 153 | 84 | painter.drawText( |
| 154 | 85 | QRectF(lineHeight * 4, top, lineHeight * 2, lineHeight), |
| 155 | - Dso::couplingString(settings->scope.coupling(channel, deviceSpecification))); | |
| 156 | - else | |
| 157 | - painter.drawText(QRectF(lineHeight * 4, top, lineHeight * 2, lineHeight), | |
| 158 | - Dso::mathModeString(settings->scope.voltage[channel].math)); | |
| 86 | + Dso::mathModeString(Dso::getMathMode(settings->scope.voltage[channel]))); | |
| 159 | 87 | |
| 160 | 88 | // Print voltage gain |
| 161 | 89 | painter.drawText(QRectF(lineHeight * 6, top, stretchBase * 2, lineHeight), |
| ... | ... | @@ -325,90 +253,17 @@ bool Exporter::exportSamples(const PPresult *result) { |
| 325 | 253 | } |
| 326 | 254 | } // dataanalyser mutex release |
| 327 | 255 | |
| 328 | - drawGrids(painter, colorValues, lineHeight, scopeHeight, paintDevice->width()); | |
| 256 | + drawGrids(painter, colorValues, lineHeight, scopeHeight, paintDevice->width(), | |
| 257 | + isPrinter, settings->view.zoom); | |
| 329 | 258 | painter.end(); |
| 330 | 259 | |
| 331 | - if (this->format == EXPORT_FORMAT_IMAGE) static_cast<QPixmap *>(paintDevice.get())->save(this->filename); | |
| 332 | - | |
| 333 | - return true; | |
| 334 | -} | |
| 335 | - | |
| 336 | -bool Exporter::exportCSV(const PPresult *result) { | |
| 337 | - QFile csvFile(this->filename); | |
| 338 | - if (!csvFile.open(QIODevice::WriteOnly | QIODevice::Text)) return false; | |
| 339 | - | |
| 340 | - QTextStream csvStream(&csvFile); | |
| 341 | - | |
| 342 | - size_t chCount = settings->scope.voltage.size(); | |
| 343 | - std::vector<const SampleValues *> voltageData(size_t(chCount), nullptr); | |
| 344 | - std::vector<const SampleValues *> spectrumData(size_t(chCount), nullptr); | |
| 345 | - size_t maxRow = 0; | |
| 346 | - bool isSpectrumUsed = false; | |
| 347 | - double timeInterval = 0; | |
| 348 | - double freqInterval = 0; | |
| 349 | - | |
| 350 | - for (ChannelID channel = 0; channel < chCount; ++channel) { | |
| 351 | - if (result->data(channel)) { | |
| 352 | - if (settings->scope.voltage[channel].used) { | |
| 353 | - voltageData[channel] = &(result->data(channel)->voltage); | |
| 354 | - maxRow = std::max(maxRow, voltageData[channel]->sample.size()); | |
| 355 | - timeInterval = result->data(channel)->voltage.interval; | |
| 356 | - } | |
| 357 | - if (settings->scope.spectrum[channel].used) { | |
| 358 | - spectrumData[channel] = &(result->data(channel)->spectrum); | |
| 359 | - maxRow = std::max(maxRow, spectrumData[channel]->sample.size()); | |
| 360 | - freqInterval = result->data(channel)->spectrum.interval; | |
| 361 | - isSpectrumUsed = true; | |
| 362 | - } | |
| 363 | - } | |
| 364 | - } | |
| 365 | - | |
| 366 | - // Start with channel names | |
| 367 | - csvStream << "\"t\""; | |
| 368 | - for (ChannelID channel = 0; channel < chCount; ++channel) { | |
| 369 | - if (voltageData[channel] != nullptr) { csvStream << ",\"" << settings->scope.voltage[channel].name << "\""; } | |
| 370 | - } | |
| 371 | - if (isSpectrumUsed) { | |
| 372 | - csvStream << ",\"f\""; | |
| 373 | - for (ChannelID channel = 0; channel < chCount; ++channel) { | |
| 374 | - if (spectrumData[channel] != nullptr) { | |
| 375 | - csvStream << ",\"" << settings->scope.spectrum[channel].name << "\""; | |
| 376 | - } | |
| 377 | - } | |
| 378 | - } | |
| 379 | - csvStream << "\n"; | |
| 380 | - | |
| 381 | - for (unsigned int row = 0; row < maxRow; ++row) { | |
| 382 | - | |
| 383 | - csvStream << timeInterval * row; | |
| 384 | - for (ChannelID channel = 0; channel < chCount; ++channel) { | |
| 385 | - if (voltageData[channel] != nullptr) { | |
| 386 | - csvStream << ","; | |
| 387 | - if (row < voltageData[channel]->sample.size()) { csvStream << voltageData[channel]->sample[row]; } | |
| 388 | - } | |
| 389 | - } | |
| 390 | - | |
| 391 | - if (isSpectrumUsed) { | |
| 392 | - csvStream << "," << freqInterval * row; | |
| 393 | - for (ChannelID channel = 0; channel < chCount; ++channel) { | |
| 394 | - if (spectrumData[channel] != nullptr) { | |
| 395 | - csvStream << ","; | |
| 396 | - if (row < spectrumData[channel]->sample.size()) { csvStream << spectrumData[channel]->sample[row]; } | |
| 397 | - } | |
| 398 | - } | |
| 399 | - } | |
| 400 | - csvStream << "\n"; | |
| 401 | - } | |
| 402 | - | |
| 403 | - csvFile.close(); | |
| 404 | - | |
| 405 | 260 | return true; |
| 406 | 261 | } |
| 407 | 262 | |
| 408 | -void Exporter::drawGrids(QPainter &painter, DsoSettingsColorValues *colorValues, double lineHeight, double scopeHeight, | |
| 409 | - int scopeWidth) { | |
| 263 | +void LegacyExportDrawer::drawGrids(QPainter &painter, const DsoSettingsColorValues *colorValues, double lineHeight, double scopeHeight, | |
| 264 | + int scopeWidth, bool isPrinter, bool zoom) { | |
| 410 | 265 | painter.setRenderHint(QPainter::Antialiasing, false); |
| 411 | - for (int zoomed = 0; zoomed < (settings->view.zoom ? 2 : 1); ++zoomed) { | |
| 266 | + for (int zoomed = 0; zoomed < (zoom ? 2 : 1); ++zoomed) { | |
| 412 | 267 | // Set DIVS_TIME x DIVS_VOLTAGE matrix for oscillograph |
| 413 | 268 | painter.setMatrix(QMatrix((scopeWidth - 1) / DIVS_TIME, 0, 0, -(scopeHeight - 1) / DIVS_VOLTAGE, |
| 414 | 269 | (double)(scopeWidth - 1) / 2, |
| ... | ... | @@ -418,7 +273,7 @@ void Exporter::drawGrids(QPainter &painter, DsoSettingsColorValues *colorValues, |
| 418 | 273 | // Grid lines |
| 419 | 274 | painter.setPen(QPen(colorValues->grid, 0)); |
| 420 | 275 | |
| 421 | - if (this->format < EXPORT_FORMAT_IMAGE) { | |
| 276 | + if (isPrinter) { | |
| 422 | 277 | // Draw vertical lines |
| 423 | 278 | for (int div = 1; div < DIVS_TIME / 2; ++div) { |
| 424 | 279 | for (int dot = 1; dot < DIVS_VOLTAGE / 2 * 5; ++dot) { | ... | ... |
openhantek/src/exporting/legacyexportdrawer.h
0 → 100644
| 1 | +// SPDX-License-Identifier: GPL-2.0+ | |
| 2 | + | |
| 3 | +#pragma once | |
| 4 | + | |
| 5 | +#include <QPainter> | |
| 6 | +#include <QPrinter> | |
| 7 | +#include <QSize> | |
| 8 | +#include <memory> | |
| 9 | +#include "exportsettings.h" | |
| 10 | + | |
| 11 | +class DsoSettings; | |
| 12 | +class PPresult; | |
| 13 | +struct DsoSettingsColorValues; | |
| 14 | +namespace Dso { struct ControlSpecification; } | |
| 15 | + | |
| 16 | +/// \brief Exports the oscilloscope screen to a file or prints it. | |
| 17 | +/// TODO | |
| 18 | +/// Rewrite image exporter with OpenGL drawn grid and graphs | |
| 19 | +/// | |
| 20 | +/// Sources: | |
| 21 | +/// http://doc.qt.io/qt-5/qoffscreensurface.html | |
| 22 | +/// http://doc.qt.io/qt-5/qopenglframebufferobject.html | |
| 23 | +/// | |
| 24 | +/// https://dangelog.wordpress.com/2013/02/10/using-fbos-instead-of-pbuffers-in-qt-5-2/ | |
| 25 | +class LegacyExportDrawer { | |
| 26 | + public: | |
| 27 | + /// Draw the graphs coming from source and labels to the destination paintdevice. | |
| 28 | + static bool exportSamples(const PPresult *source, QPaintDevice* dest, | |
| 29 | + const Dso::ControlSpecification* deviceSpecification, | |
| 30 | + const DsoSettings *settings, bool isPrinter, const DsoSettingsColorValues *colorValues); | |
| 31 | + | |
| 32 | + private: | |
| 33 | + static void drawGrids(QPainter &painter, const DsoSettingsColorValues *colorValues, double lineHeight, double scopeHeight, | |
| 34 | + int scopeWidth, bool isPrinter, bool zoom); | |
| 35 | +}; | ... | ... |
openhantek/src/exporting/readme.md
0 → 100644
| 1 | +# Content | |
| 2 | +This directory contains exporting functionality and exporters, namely | |
| 3 | + | |
| 4 | +* Export to comma separated value file (CSV): Write to a user selected file, | |
| 5 | +* Export to an image/pdf: Writes an image/pdf to a user selected file, | |
| 6 | +* Print exporter: Creates a printable document and opens the print dialog. | |
| 7 | + | |
| 8 | +All export classes (exportcsv, exportimage, exportprint) implement the | |
| 9 | +ExporterInterface and are registered to the ExporterRegistry in the main.cpp. | |
| 10 | + | |
| 11 | +Some export classes are still using the legacyExportDrawer class to | |
| 12 | +draw the grid and paint all the labels, values and graphs. | |
| 13 | + | |
| 14 | +# Dependency | |
| 15 | +* Files in this directory depend on the result class of the post processing directory. | |
| 16 | +* Classes in here depend on the user settings (../viewsetting.h, ../scopesetting.h) | ... | ... |
openhantek/src/main.cpp
| ... | ... | @@ -12,19 +12,34 @@ |
| 12 | 12 | #include <libusb-1.0/libusb.h> |
| 13 | 13 | #include <memory> |
| 14 | 14 | |
| 15 | +// Settings | |
| 16 | +#include "settings.h" | |
| 17 | +#include "viewconstants.h" | |
| 18 | + | |
| 19 | +// DSO core logic | |
| 20 | +#include "dsomodel.h" | |
| 21 | +#include "hantekdsocontrol.h" | |
| 22 | +#include "usb/usbdevice.h" | |
| 23 | + | |
| 24 | +// Post processing | |
| 15 | 25 | #include "post/graphgenerator.h" |
| 16 | 26 | #include "post/mathchannelgenerator.h" |
| 17 | 27 | #include "post/postprocessing.h" |
| 18 | 28 | #include "post/spectrumgenerator.h" |
| 19 | 29 | |
| 20 | -#include "dsomodel.h" | |
| 21 | -#include "hantekdsocontrol.h" | |
| 30 | +// Exporter | |
| 31 | +#include "exporting/exportcsv.h" | |
| 32 | +#include "exporting/exporterprocessor.h" | |
| 33 | +#include "exporting/exporterregistry.h" | |
| 34 | +#include "exporting/exportimage.h" | |
| 35 | +#include "exporting/exportprint.h" | |
| 36 | + | |
| 37 | +// GUI | |
| 38 | +#include "iconfont/QtAwesome.h" | |
| 22 | 39 | #include "mainwindow.h" |
| 23 | 40 | #include "selectdevice/selectsupporteddevice.h" |
| 24 | -#include "settings.h" | |
| 25 | -#include "usb/usbdevice.h" | |
| 26 | -#include "viewconstants.h" | |
| 27 | 41 | |
| 42 | +// OpenGL setup | |
| 28 | 43 | #include "glscope.h" |
| 29 | 44 | |
| 30 | 45 | #ifndef VERSION |
| ... | ... | @@ -71,6 +86,10 @@ int main(int argc, char *argv[]) { |
| 71 | 86 | QCoreApplication::setOrganizationDomain("www.openhantek.org"); |
| 72 | 87 | QCoreApplication::setApplicationName("OpenHantek"); |
| 73 | 88 | QCoreApplication::setApplicationVersion(VERSION); |
| 89 | + QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps, true); | |
| 90 | +#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)) | |
| 91 | + QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling, true); | |
| 92 | +#endif | |
| 74 | 93 | |
| 75 | 94 | bool useGles = false; |
| 76 | 95 | { |
| ... | ... | @@ -126,34 +145,55 @@ int main(int argc, char *argv[]) { |
| 126 | 145 | &QCoreApplication::quit); |
| 127 | 146 | |
| 128 | 147 | //////// Create settings object //////// |
| 129 | - auto settings = std::unique_ptr<DsoSettings>(new DsoSettings(device->getModel()->spec())); | |
| 148 | + DsoSettings settings(device->getModel()->spec()); | |
| 149 | + | |
| 150 | + //////// Create exporters //////// | |
| 151 | + ExporterRegistry exportRegistry(device->getModel()->spec(), &settings); | |
| 152 | + | |
| 153 | + ExporterCSV exporterCSV; | |
| 154 | + ExporterImage exportImage; | |
| 155 | + ExporterPrint exportPrint; | |
| 156 | + | |
| 157 | + ExporterProcessor samplesToExportRaw(&exportRegistry); | |
| 158 | + | |
| 159 | + exportRegistry.registerExporter(&exporterCSV); | |
| 160 | + exportRegistry.registerExporter(&exportImage); | |
| 161 | + exportRegistry.registerExporter(&exportPrint); | |
| 130 | 162 | |
| 131 | 163 | //////// Create post processing objects //////// |
| 132 | 164 | QThread postProcessingThread; |
| 133 | 165 | postProcessingThread.setObjectName("postProcessingThread"); |
| 134 | - PostProcessing postProcessing(settings->scope.countChannels()); | |
| 166 | + PostProcessing postProcessing(settings.scope.countChannels()); | |
| 135 | 167 | |
| 136 | - SpectrumGenerator spectrumGenerator(&settings->scope); | |
| 137 | - MathChannelGenerator mathchannelGenerator(&settings->scope, device->getModel()->spec()->channels); | |
| 138 | - GraphGenerator graphGenerator(&settings->scope, device->getModel()->spec()->isSoftwareTriggerDevice); | |
| 168 | + SpectrumGenerator spectrumGenerator(&settings.scope, &settings.post); | |
| 169 | + MathChannelGenerator mathchannelGenerator(&settings.scope, device->getModel()->spec()->channels); | |
| 170 | + GraphGenerator graphGenerator(&settings.scope, device->getModel()->spec()->isSoftwareTriggerDevice); | |
| 139 | 171 | |
| 172 | + postProcessing.registerProcessor(&samplesToExportRaw); | |
| 140 | 173 | postProcessing.registerProcessor(&mathchannelGenerator); |
| 141 | 174 | postProcessing.registerProcessor(&spectrumGenerator); |
| 142 | 175 | postProcessing.registerProcessor(&graphGenerator); |
| 143 | 176 | |
| 144 | 177 | postProcessing.moveToThread(&postProcessingThread); |
| 145 | 178 | QObject::connect(&dsoControl, &HantekDsoControl::samplesAvailable, &postProcessing, &PostProcessing::input); |
| 179 | + QObject::connect(&postProcessing, &PostProcessing::processingFinished, &exportRegistry, &ExporterRegistry::input, | |
| 180 | + Qt::DirectConnection); | |
| 146 | 181 | |
| 147 | 182 | //////// Create main window //////// |
| 148 | - MainWindow openHantekMainWindow(&dsoControl, settings.get()); | |
| 183 | + iconFont->initFontAwesome(); | |
| 184 | + MainWindow openHantekMainWindow(&dsoControl, &settings, &exportRegistry); | |
| 149 | 185 | QObject::connect(&postProcessing, &PostProcessing::processingFinished, &openHantekMainWindow, |
| 150 | 186 | &MainWindow::showNewData); |
| 187 | + QObject::connect(&exportRegistry, &ExporterRegistry::exporterProgressChanged, &openHantekMainWindow, | |
| 188 | + &MainWindow::exporterProgressChanged); | |
| 189 | + QObject::connect(&exportRegistry, &ExporterRegistry::exporterStatusChanged, &openHantekMainWindow, | |
| 190 | + &MainWindow::exporterStatusChanged); | |
| 151 | 191 | openHantekMainWindow.show(); |
| 152 | 192 | |
| 153 | - applySettingsToDevice(&dsoControl, &settings->scope, device->getModel()->spec()); | |
| 193 | + applySettingsToDevice(&dsoControl, &settings.scope, device->getModel()->spec()); | |
| 154 | 194 | |
| 155 | 195 | //////// Start DSO thread and go into GUI main loop |
| 156 | - dsoControl.startSampling(); | |
| 196 | + dsoControl.enableSampling(true); | |
| 157 | 197 | postProcessingThread.start(); |
| 158 | 198 | dsoControlThread.start(); |
| 159 | 199 | int res = openHantekApplication.exec(); | ... | ... |