diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3365eb7be..b1e6ca483 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,391 +1,392 @@ find_package(SharedMimeInfo REQUIRED) set(KDE_FRONTEND true) set(KDEFRONTEND_DIR kdefrontend) set(BACKEND_DIR backend) set(COMMONFRONTEND_DIR commonfrontend) set(CANTOR_DIR cantor) set(TOOLS_DIR tools) set(CMAKE_AUTOMOC ON) set(SRC_BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR} PARENT_SCOPE) set(GUI_SOURCES ${KDEFRONTEND_DIR}/GuiObserver.cpp ${KDEFRONTEND_DIR}/GuiTools.cpp ${KDEFRONTEND_DIR}/HistoryDialog.cpp ${KDEFRONTEND_DIR}/MainWin.cpp ${KDEFRONTEND_DIR}/SettingsDialog.cpp ${KDEFRONTEND_DIR}/SettingsGeneralPage.cpp ${KDEFRONTEND_DIR}/SettingsWorksheetPage.cpp ${KDEFRONTEND_DIR}/SettingsPage.h ${KDEFRONTEND_DIR}/TemplateHandler.cpp ${KDEFRONTEND_DIR}/ThemeHandler.cpp ${KDEFRONTEND_DIR}/datasources/AsciiOptionsWidget.cpp ${KDEFRONTEND_DIR}/datasources/BinaryOptionsWidget.cpp ${KDEFRONTEND_DIR}/datasources/DatabaseManagerDialog.cpp ${KDEFRONTEND_DIR}/datasources/DatabaseManagerWidget.cpp ${KDEFRONTEND_DIR}/datasources/HDF5OptionsWidget.cpp ${KDEFRONTEND_DIR}/datasources/FileInfoDialog.cpp ${KDEFRONTEND_DIR}/datasources/ImageOptionsWidget.cpp ${KDEFRONTEND_DIR}/datasources/ImportDialog.cpp ${KDEFRONTEND_DIR}/datasources/ImportFileWidget.cpp ${KDEFRONTEND_DIR}/datasources/ImportFileDialog.cpp ${KDEFRONTEND_DIR}/datasources/ImportProjectDialog.cpp ${KDEFRONTEND_DIR}/datasources/ImportSQLDatabaseDialog.cpp ${KDEFRONTEND_DIR}/datasources/ImportSQLDatabaseWidget.cpp ${KDEFRONTEND_DIR}/datasources/NetCDFOptionsWidget.cpp ${KDEFRONTEND_DIR}/datasources/FITSOptionsWidget.cpp ${KDEFRONTEND_DIR}/dockwidgets/AxisDock.cpp ${KDEFRONTEND_DIR}/dockwidgets/NoteDock.cpp ${KDEFRONTEND_DIR}/dockwidgets/CartesianPlotDock.cpp ${KDEFRONTEND_DIR}/dockwidgets/CartesianPlotLegendDock.cpp ${KDEFRONTEND_DIR}/dockwidgets/HistogramDock.cpp ${KDEFRONTEND_DIR}/dockwidgets/BarChartPlotDock.cpp ${KDEFRONTEND_DIR}/dockwidgets/CustomPointDock.cpp ${KDEFRONTEND_DIR}/dockwidgets/ColumnDock.cpp ${KDEFRONTEND_DIR}/dockwidgets/LiveDataDock.cpp ${KDEFRONTEND_DIR}/dockwidgets/MatrixDock.cpp ${KDEFRONTEND_DIR}/dockwidgets/ProjectDock.cpp ${KDEFRONTEND_DIR}/dockwidgets/SpreadsheetDock.cpp ${KDEFRONTEND_DIR}/dockwidgets/XYCurveDock.cpp ${KDEFRONTEND_DIR}/dockwidgets/XYEquationCurveDock.cpp ${KDEFRONTEND_DIR}/dockwidgets/XYDataReductionCurveDock.cpp ${KDEFRONTEND_DIR}/dockwidgets/XYDifferentiationCurveDock.cpp ${KDEFRONTEND_DIR}/dockwidgets/XYIntegrationCurveDock.cpp ${KDEFRONTEND_DIR}/dockwidgets/XYInterpolationCurveDock.cpp ${KDEFRONTEND_DIR}/dockwidgets/XYSmoothCurveDock.cpp ${KDEFRONTEND_DIR}/dockwidgets/XYFitCurveDock.cpp ${KDEFRONTEND_DIR}/dockwidgets/XYFourierFilterCurveDock.cpp ${KDEFRONTEND_DIR}/dockwidgets/XYFourierTransformCurveDock.cpp ${KDEFRONTEND_DIR}/dockwidgets/WorksheetDock.cpp ${KDEFRONTEND_DIR}/matrix/MatrixFunctionDialog.cpp ${KDEFRONTEND_DIR}/spreadsheet/PlotDataDialog.cpp ${KDEFRONTEND_DIR}/spreadsheet/EquidistantValuesDialog.cpp ${KDEFRONTEND_DIR}/spreadsheet/ExportSpreadsheetDialog.cpp ${KDEFRONTEND_DIR}/spreadsheet/DropValuesDialog.cpp ${KDEFRONTEND_DIR}/spreadsheet/FunctionValuesDialog.cpp ${KDEFRONTEND_DIR}/spreadsheet/RandomValuesDialog.cpp ${KDEFRONTEND_DIR}/spreadsheet/SortDialog.cpp ${KDEFRONTEND_DIR}/spreadsheet/StatisticsDialog.cpp ${KDEFRONTEND_DIR}/worksheet/ExportWorksheetDialog.cpp ${KDEFRONTEND_DIR}/worksheet/GridDialog.cpp ${KDEFRONTEND_DIR}/worksheet/DynamicPresenterWidget.cpp ${KDEFRONTEND_DIR}/worksheet/PresenterWidget.cpp ${KDEFRONTEND_DIR}/worksheet/SlidingPanel.cpp ${KDEFRONTEND_DIR}/widgets/ConstantsWidget.cpp ${KDEFRONTEND_DIR}/widgets/ThemesComboBox.cpp ${KDEFRONTEND_DIR}/widgets/ThemesWidget.cpp ${KDEFRONTEND_DIR}/widgets/ExpressionTextEdit.cpp ${KDEFRONTEND_DIR}/widgets/FitOptionsWidget.cpp ${KDEFRONTEND_DIR}/widgets/FitParametersWidget.cpp ${KDEFRONTEND_DIR}/widgets/FunctionsWidget.cpp ${KDEFRONTEND_DIR}/widgets/LabelWidget.cpp ${KDEFRONTEND_DIR}/widgets/DatapickerImageWidget.cpp ${KDEFRONTEND_DIR}/widgets/DatapickerCurveWidget.cpp ${KDEFRONTEND_DIR}/widgets/FITSHeaderEditWidget.cpp ${KDEFRONTEND_DIR}/widgets/FITSHeaderEditNewKeywordDialog.cpp ${KDEFRONTEND_DIR}/widgets/FITSHeaderEditAddUnitDialog.cpp ${KDEFRONTEND_DIR}/widgets/FITSHeaderEditDialog.cpp ${KDEFRONTEND_DIR}/widgets/ResizableTextEdit.cpp ) set(UI_SOURCES ${KDEFRONTEND_DIR}/ui/constantswidget.ui ${KDEFRONTEND_DIR}/ui/functionswidget.ui ${KDEFRONTEND_DIR}/ui/fitoptionswidget.ui ${KDEFRONTEND_DIR}/ui/fitparameterswidget.ui ${KDEFRONTEND_DIR}/ui/labelwidget.ui ${KDEFRONTEND_DIR}/ui/settingsgeneralpage.ui ${KDEFRONTEND_DIR}/ui/settingsworksheetpage.ui ${KDEFRONTEND_DIR}/ui/settingsprintingpage.ui ${KDEFRONTEND_DIR}/ui/datasources/asciioptionswidget.ui ${KDEFRONTEND_DIR}/ui/datasources/binaryoptionswidget.ui ${KDEFRONTEND_DIR}/ui/datasources/databasemanagerwidget.ui ${KDEFRONTEND_DIR}/ui/datasources/hdf5optionswidget.ui ${KDEFRONTEND_DIR}/ui/datasources/imageoptionswidget.ui ${KDEFRONTEND_DIR}/ui/datasources/importfilewidget.ui ${KDEFRONTEND_DIR}/ui/datasources/importprojectwidget.ui ${KDEFRONTEND_DIR}/ui/datasources/importsqldatabasewidget.ui ${KDEFRONTEND_DIR}/ui/datasources/netcdfoptionswidget.ui ${KDEFRONTEND_DIR}/ui/datasources/fitsoptionswidget.ui ${KDEFRONTEND_DIR}/ui/dockwidgets/axisdock.ui ${KDEFRONTEND_DIR}/ui/dockwidgets/cartesianplotdock.ui ${KDEFRONTEND_DIR}/ui/dockwidgets/cartesianplotlegenddock.ui ${KDEFRONTEND_DIR}/ui/dockwidgets/histogramdock.ui ${KDEFRONTEND_DIR}/ui/dockwidgets/histogramdockgeneraltab.ui ${KDEFRONTEND_DIR}/ui/dockwidgets/barchartplotdock.ui ${KDEFRONTEND_DIR}/ui/dockwidgets/columndock.ui ${KDEFRONTEND_DIR}/ui/dockwidgets/custompointdock.ui ${KDEFRONTEND_DIR}/ui/dockwidgets/livedatadock.ui ${KDEFRONTEND_DIR}/ui/dockwidgets/notedock.ui ${KDEFRONTEND_DIR}/ui/dockwidgets/matrixdock.ui ${KDEFRONTEND_DIR}/ui/dockwidgets/projectdock.ui ${KDEFRONTEND_DIR}/ui/dockwidgets/spreadsheetdock.ui ${KDEFRONTEND_DIR}/ui/dockwidgets/xycurvedock.ui ${KDEFRONTEND_DIR}/ui/dockwidgets/xycurvedockgeneraltab.ui ${KDEFRONTEND_DIR}/ui/dockwidgets/xydatareductioncurvedockgeneraltab.ui ${KDEFRONTEND_DIR}/ui/dockwidgets/xydifferentiationcurvedockgeneraltab.ui ${KDEFRONTEND_DIR}/ui/dockwidgets/xyintegrationcurvedockgeneraltab.ui ${KDEFRONTEND_DIR}/ui/dockwidgets/xyinterpolationcurvedockgeneraltab.ui ${KDEFRONTEND_DIR}/ui/dockwidgets/xysmoothcurvedockgeneraltab.ui ${KDEFRONTEND_DIR}/ui/dockwidgets/xyfitcurvedockgeneraltab.ui ${KDEFRONTEND_DIR}/ui/dockwidgets/xyfourierfiltercurvedockgeneraltab.ui ${KDEFRONTEND_DIR}/ui/dockwidgets/xyfouriertransformcurvedockgeneraltab.ui ${KDEFRONTEND_DIR}/ui/dockwidgets/xyequationcurvedockgeneraltab.ui ${KDEFRONTEND_DIR}/ui/dockwidgets/worksheetdock.ui ${KDEFRONTEND_DIR}/ui/matrix/matrixfunctionwidget.ui ${KDEFRONTEND_DIR}/ui/spreadsheet/plotdatawidget.ui ${KDEFRONTEND_DIR}/ui/spreadsheet/equidistantvalueswidget.ui ${KDEFRONTEND_DIR}/ui/spreadsheet/exportspreadsheetwidget.ui ${KDEFRONTEND_DIR}/ui/spreadsheet/dropvalueswidget.ui ${KDEFRONTEND_DIR}/ui/spreadsheet/functionvalueswidget.ui ${KDEFRONTEND_DIR}/ui/spreadsheet/randomvalueswidget.ui ${KDEFRONTEND_DIR}/ui/worksheet/exportworksheetwidget.ui ${KDEFRONTEND_DIR}/ui/datapickerimagewidget.ui ${KDEFRONTEND_DIR}/ui/datapickercurvewidget.ui ${KDEFRONTEND_DIR}/ui/fitsheadereditwidget.ui ${KDEFRONTEND_DIR}/ui/fitsheadereditnewkeywordwidget.ui ${KDEFRONTEND_DIR}/ui/fitsheadereditaddunitwidget.ui ) set(BACKEND_SOURCES ${BACKEND_DIR}/core/Folder.cpp ${BACKEND_DIR}/core/AbstractAspect.cpp ${BACKEND_DIR}/core/AbstractColumn.cpp ${BACKEND_DIR}/core/AbstractColumnPrivate.cpp ${BACKEND_DIR}/core/abstractcolumncommands.cpp ${BACKEND_DIR}/core/AbstractFilter.cpp ${BACKEND_DIR}/core/AbstractSimpleFilter.cpp ${BACKEND_DIR}/core/column/Column.cpp ${BACKEND_DIR}/core/column/ColumnPrivate.cpp ${BACKEND_DIR}/core/column/ColumnStringIO.cpp ${BACKEND_DIR}/core/column/columncommands.cpp ${BACKEND_DIR}/core/AbstractScriptingEngine.cpp ${BACKEND_DIR}/core/AbstractScript.cpp ${BACKEND_DIR}/core/ScriptingEngineManager.cpp ${BACKEND_DIR}/core/Project.cpp ${BACKEND_DIR}/core/AbstractPart.cpp ${BACKEND_DIR}/core/Workbook.cpp ${BACKEND_DIR}/core/AspectTreeModel.cpp ${BACKEND_DIR}/core/datatypes/SimpleCopyThroughFilter.h ${BACKEND_DIR}/core/datatypes/Double2DateTimeFilter.h ${BACKEND_DIR}/core/datatypes/Double2DayOfWeekFilter.h ${BACKEND_DIR}/core/datatypes/Double2IntegerFilter.h ${BACKEND_DIR}/core/datatypes/Double2MonthFilter.h ${BACKEND_DIR}/core/datatypes/Double2StringFilter.cpp ${BACKEND_DIR}/core/datatypes/Integer2DateTimeFilter.h ${BACKEND_DIR}/core/datatypes/Integer2DayOfWeekFilter.h ${BACKEND_DIR}/core/datatypes/Integer2DoubleFilter.h ${BACKEND_DIR}/core/datatypes/Integer2MonthFilter.h ${BACKEND_DIR}/core/datatypes/Integer2StringFilter.h ${BACKEND_DIR}/core/datatypes/String2DayOfWeekFilter.h ${BACKEND_DIR}/core/datatypes/String2DoubleFilter.h ${BACKEND_DIR}/core/datatypes/String2IntegerFilter.h ${BACKEND_DIR}/core/datatypes/String2MonthFilter.h ${BACKEND_DIR}/core/datatypes/String2DateTimeFilter.cpp ${BACKEND_DIR}/core/datatypes/DateTime2DoubleFilter.h ${BACKEND_DIR}/core/datatypes/DateTime2IntegerFilter.h ${BACKEND_DIR}/core/datatypes/DateTime2StringFilter.cpp ${BACKEND_DIR}/core/datatypes/Month2DoubleFilter.h ${BACKEND_DIR}/core/datatypes/Month2IntegerFilter.h ${BACKEND_DIR}/core/datatypes/DayOfWeek2DoubleFilter.h ${BACKEND_DIR}/core/datatypes/DayOfWeek2IntegerFilter.h ${BACKEND_DIR}/core/plugin/PluginLoader.cpp ${BACKEND_DIR}/core/plugin/PluginManager.cpp ${BACKEND_DIR}/datasources/AbstractDataSource.cpp ${BACKEND_DIR}/datasources/LiveDataSource.cpp ${BACKEND_DIR}/datasources/filters/AbstractFileFilter.cpp ${BACKEND_DIR}/datasources/filters/AsciiFilter.cpp ${BACKEND_DIR}/datasources/filters/BinaryFilter.cpp ${BACKEND_DIR}/datasources/filters/HDF5Filter.cpp ${BACKEND_DIR}/datasources/filters/ImageFilter.cpp + ${BACKEND_DIR}/datasources/filters/JsonFilter.cpp ${BACKEND_DIR}/datasources/filters/NetCDFFilter.cpp ${BACKEND_DIR}/datasources/filters/FITSFilter.cpp ${BACKEND_DIR}/datasources/projects/ProjectParser.cpp ${BACKEND_DIR}/datasources/projects/LabPlotProjectParser.cpp ${BACKEND_DIR}/datasources/projects/OriginProjectParser.cpp ${BACKEND_DIR}/gsl/ExpressionParser.cpp ${BACKEND_DIR}/matrix/Matrix.cpp ${BACKEND_DIR}/matrix/matrixcommands.cpp ${BACKEND_DIR}/matrix/MatrixModel.cpp ${BACKEND_DIR}/spreadsheet/Spreadsheet.cpp ${BACKEND_DIR}/spreadsheet/SpreadsheetModel.cpp ${BACKEND_DIR}/lib/XmlStreamReader.cpp ${BACKEND_DIR}/note/Note.cpp ${BACKEND_DIR}/worksheet/WorksheetElement.cpp ${BACKEND_DIR}/worksheet/TextLabel.cpp ${BACKEND_DIR}/worksheet/Worksheet.cpp ${BACKEND_DIR}/worksheet/WorksheetElementContainer.cpp ${BACKEND_DIR}/worksheet/WorksheetElementGroup.cpp ${BACKEND_DIR}/worksheet/plots/AbstractPlot.cpp ${BACKEND_DIR}/worksheet/plots/AbstractCoordinateSystem.cpp ${BACKEND_DIR}/worksheet/plots/PlotArea.cpp ${BACKEND_DIR}/worksheet/plots/cartesian/Axis.cpp ${BACKEND_DIR}/worksheet/plots/cartesian/CartesianCoordinateSystem.cpp ${BACKEND_DIR}/worksheet/plots/cartesian/CartesianPlot.cpp ${BACKEND_DIR}/worksheet/plots/cartesian/CartesianPlotLegend.cpp ${BACKEND_DIR}/worksheet/plots/cartesian/Histogram.cpp ${BACKEND_DIR}/worksheet/plots/cartesian/BarChartPlot.cpp ${BACKEND_DIR}/worksheet/plots/cartesian/CustomPoint.cpp ${BACKEND_DIR}/worksheet/plots/cartesian/Symbol.cpp ${BACKEND_DIR}/worksheet/plots/cartesian/XYAnalysisCurve.cpp ${BACKEND_DIR}/worksheet/plots/cartesian/XYCurve.cpp ${BACKEND_DIR}/worksheet/plots/cartesian/XYEquationCurve.cpp ${BACKEND_DIR}/worksheet/plots/cartesian/XYDataReductionCurve.cpp ${BACKEND_DIR}/worksheet/plots/cartesian/XYDifferentiationCurve.cpp ${BACKEND_DIR}/worksheet/plots/cartesian/XYIntegrationCurve.cpp ${BACKEND_DIR}/worksheet/plots/cartesian/XYInterpolationCurve.cpp ${BACKEND_DIR}/worksheet/plots/cartesian/XYSmoothCurve.cpp ${BACKEND_DIR}/worksheet/plots/cartesian/XYFitCurve.cpp ${BACKEND_DIR}/worksheet/plots/cartesian/XYFourierFilterCurve.cpp ${BACKEND_DIR}/worksheet/plots/cartesian/XYFourierTransformCurve.cpp ${BACKEND_DIR}/lib/SignallingUndoCommand.cpp ${BACKEND_DIR}/datapicker/DatapickerPoint.cpp ${BACKEND_DIR}/datapicker/DatapickerImage.cpp ${BACKEND_DIR}/datapicker/Datapicker.cpp ${BACKEND_DIR}/datapicker/Transform.cpp ${BACKEND_DIR}/datapicker/ImageEditor.cpp ${BACKEND_DIR}/datapicker/Segment.cpp ${BACKEND_DIR}/datapicker/Segments.cpp ${BACKEND_DIR}/datapicker/DatapickerCurve.cpp ) set(NSL_SOURCES ${BACKEND_DIR}/nsl/nsl_dft.c ${BACKEND_DIR}/nsl/nsl_diff.c ${BACKEND_DIR}/nsl/nsl_filter.c ${BACKEND_DIR}/nsl/nsl_fit.c ${BACKEND_DIR}/nsl/nsl_geom.c ${BACKEND_DIR}/nsl/nsl_geom_linesim.c ${BACKEND_DIR}/nsl/nsl_int.c ${BACKEND_DIR}/nsl/nsl_interp.c ${BACKEND_DIR}/nsl/nsl_math.c ${BACKEND_DIR}/nsl/nsl_sf_basic.c ${BACKEND_DIR}/nsl/nsl_sf_kernel.c ${BACKEND_DIR}/nsl/nsl_sf_poly.c ${BACKEND_DIR}/nsl/nsl_sf_stats.c ${BACKEND_DIR}/nsl/nsl_sf_window.c ${BACKEND_DIR}/nsl/nsl_smooth.c ${BACKEND_DIR}/nsl/nsl_sort.c ${BACKEND_DIR}/nsl/nsl_stats.c ) IF (NOT MSVC_FOUND) IF (NOT LIBCERF_FOUND) list(APPEND NSL_SOURCES ${BACKEND_DIR}/nsl/Faddeeva.c ) ENDIF () ENDIF () set(COMMONFRONTEND_SOURCES ${COMMONFRONTEND_DIR}/matrix/MatrixView.cpp ${COMMONFRONTEND_DIR}/note/NoteView.cpp ${COMMONFRONTEND_DIR}/spreadsheet/SpreadsheetCommentsHeaderModel.cpp ${COMMONFRONTEND_DIR}/spreadsheet/SpreadsheetHeaderView.cpp ${COMMONFRONTEND_DIR}/spreadsheet/SpreadsheetItemDelegate.cpp ${COMMONFRONTEND_DIR}/spreadsheet/SpreadsheetView.cpp ${COMMONFRONTEND_DIR}/workbook/WorkbookView.cpp ${COMMONFRONTEND_DIR}/worksheet/WorksheetView.cpp ${COMMONFRONTEND_DIR}/ProjectExplorer.cpp ${COMMONFRONTEND_DIR}/core/PartMdiView.cpp ${COMMONFRONTEND_DIR}/widgets/TreeViewComboBox.cpp ${COMMONFRONTEND_DIR}/widgets/qxtspanslider.cpp ${COMMONFRONTEND_DIR}/datapicker/DatapickerView.cpp ${COMMONFRONTEND_DIR}/datapicker/DatapickerImageView.cpp ) IF (${CANTOR_LIBS_FOUND}) set(CANTOR_SOURCES ${KDEFRONTEND_DIR}/dockwidgets/CantorWorksheetDock.cpp ${BACKEND_DIR}/cantorWorksheet/VariableParser.cpp ${BACKEND_DIR}/cantorWorksheet/CantorWorksheet.cpp ${COMMONFRONTEND_DIR}/cantorWorksheet/CantorWorksheetView.cpp ) set(CANTOR_UI_SOURCES ${KDEFRONTEND_DIR}/ui/dockwidgets/cantorworksheetdock.ui) set(UI_SOURCES ${UI_SOURCES} ${CANTOR_UI_SOURCES}) ELSE () set(CANTOR_SOURCES "") ENDIF () set(TOOLS_SOURCES ${TOOLS_DIR}/EquationHighlighter.cpp ${TOOLS_DIR}/ImageTools.cpp ${TOOLS_DIR}/TeXRenderer.cpp ) bison_target(GslParser ${BACKEND_DIR}/gsl/parser.y ${CMAKE_CURRENT_BINARY_DIR}/gsl_parser.c ) set(GENERATED_SOURCES ${BISON_GslParser_OUTPUTS} ) ############################################################################## INCLUDE_DIRECTORIES( . ${BACKEND_DIR}/gsl ${GSL_INCLUDE_DIR} ) set( LABPLOT_SRCS ${GUI_SOURCES} ) ki18n_wrap_ui( LABPLOT_SRCS ${UI_SOURCES} ) # static library add_library( labplot2lib STATIC ${LABPLOT_SRCS} ${BACKEND_SOURCES} ${NSL_SOURCES} ${CANTOR_SOURCES} ${DATASOURCES_SOURCES} ${COMMONFRONTEND_SOURCES} ${TOOLS_SOURCES} ${GENERATED_SOURCES} ${QTMOC_HDRS} ) # set_property(TARGET ${objlib} PROPERTY POSITION_INDEPENDENT_CODE 1) # TODO: remove KF5::KDELibs4Support target_link_libraries( labplot2lib KF5::KDELibs4Support KF5::Archive KF5::XmlGui Qt5::Svg Qt5::Core ${GSL_LIBRARIES} ${GSL_CBLAS_LIBRARIES} ${QT_QTSQL_LIBRARIES} ) IF (Qt5SerialPort_FOUND) target_link_libraries( labplot2lib Qt5::SerialPort ) ENDIF () IF (KF5SyntaxHighlighting_FOUND) target_link_libraries( labplot2lib KF5::SyntaxHighlighting ) ENDIF () #TODO: KF5::NewStuff IF (CANTOR_LIBS_FOUND) target_link_libraries( labplot2lib ${CANTOR_LIBS} ) ENDIF () IF (HDF5_FOUND) target_link_libraries( labplot2lib ${HDF5_LIBRARIES} ) ENDIF () IF (FFTW_FOUND) target_link_libraries( labplot2lib ${FFTW_LIBRARIES} ) ENDIF () IF (NETCDF_FOUND) target_link_libraries( labplot2lib ${NETCDF_LIBRARY} ) ENDIF () IF (CFITSIO_FOUND) target_link_libraries( labplot2lib ${CFITSIO_LIBRARY} ) ENDIF () IF (LIBCERF_FOUND) target_link_libraries( labplot2lib ${LIBCERF_LIBRARY} ) ENDIF () IF (ENABLE_LIBORIGIN) target_link_libraries( labplot2lib liborigin-static ) ENDIF () # icons for the executable on Windows and Mac OS X set(LABPLOT_ICONS ${CMAKE_CURRENT_SOURCE_DIR}/../icons/16-apps-labplot2.png ${CMAKE_CURRENT_SOURCE_DIR}/../icons/32-apps-labplot2.png ${CMAKE_CURRENT_SOURCE_DIR}/../icons/48-apps-labplot2.png ${CMAKE_CURRENT_SOURCE_DIR}/../icons/64-apps-labplot2.png ${CMAKE_CURRENT_SOURCE_DIR}/../icons/128-apps-labplot2.png ${CMAKE_CURRENT_SOURCE_DIR}/../icons/256-apps-labplot2.png ${CMAKE_CURRENT_SOURCE_DIR}/../icons/512-apps-labplot2.png ) # main executable set(LABPLOT_SOURCE ${KDEFRONTEND_DIR}/LabPlot.cpp) ecm_add_app_icon(LABPLOT_SOURCE ICONS ${LABPLOT_ICONS}) add_executable( labplot2 ${LABPLOT_SOURCE} ) target_link_libraries( labplot2 labplot2lib ) ############## installation ################################ install( TARGETS labplot2 DESTINATION ${INSTALL_TARGETS_DEFAULT_ARGS} ) install( FILES ${KDEFRONTEND_DIR}/labplot2ui.rc DESTINATION ${KXMLGUI_INSTALL_DIR}/${PROJECT_NAME} ) install( FILES ${KDEFRONTEND_DIR}/splash.png ${KDEFRONTEND_DIR}/labplot2.ico DESTINATION ${DATA_INSTALL_DIR}/${PROJECT_NAME} ) install( PROGRAMS org.kde.labplot2.desktop DESTINATION ${XDG_APPS_INSTALL_DIR} ) install( FILES labplot2.xml DESTINATION ${XDG_MIME_INSTALL_DIR} ) install( FILES labplot2_themes.knsrc DESTINATION ${CONFIG_INSTALL_DIR} ) update_xdg_mimetypes( ${XDG_MIME_INSTALL_DIR} ) diff --git a/src/backend/datasources/filters/JsonFilter.cpp b/src/backend/datasources/filters/JsonFilter.cpp new file mode 100644 index 000000000..32b76c4e4 --- /dev/null +++ b/src/backend/datasources/filters/JsonFilter.cpp @@ -0,0 +1,716 @@ +#include "backend/datasources/filters/JsonFilter.h" +#include "backend/datasources/filters/JsonFilterPrivate.h" +#include "backend/datasources/AbstractDataSource.h" +#include "backend/core/column/Column.h" + +#include +#include +#include +#include +#include +#include +#include + +/*! +\class JsonFilter +\brief Manages the import/export of data from/to a file formatted using JSON. + +\ingroup datasources +*/ +JsonFilter::JsonFilter() : AbstractFileFilter(), d(new JsonFilterPrivate(this)) {} + +JsonFilter::~JsonFilter() {} + +/*! +reads the content of the device \c device. +*/ +void JsonFilter::readDataFromDevice(QIODevice& device, AbstractDataSource* dataSource, AbstractFileFilter::ImportMode importMode, int lines) { + d->readDataFromDevice(device, dataSource, importMode, lines); +} + +/*! +reads the content of the file \c fileName. +*/ +QVector JsonFilter::readDataFromFile(const QString& fileName, AbstractDataSource* dataSource, AbstractFileFilter::ImportMode importMode, int lines) { + d->readDataFromFile(fileName, dataSource, importMode, lines); + return QVector(); //TODO: remove this later once all read*-functions in the filter classes don't return any preview strings anymore +} + +QVector JsonFilter::preview(const QString& fileName) { + return d->preview(fileName); +} + +QVector JsonFilter::preview(QIODevice &device) { + return d->preview(device); +} + +/*! +writes the content of the data source \c dataSource to the file \c fileName. +*/ +void JsonFilter::write(const QString& fileName, AbstractDataSource* dataSource) { + d->write(fileName, dataSource); +} + +/////////////////////////////////////////////////////////////////////// +/*! +loads the predefined filter settings for \c filterName +*/ +void JsonFilter::loadFilterSettings(const QString& filterName) { + Q_UNUSED(filterName); +} + +/*! +saves the current settings as a new filter with the name \c filterName +*/ +void JsonFilter::saveFilterSettings(const QString& filterName) const { + Q_UNUSED(filterName); +} + +/*! +returns the list of all predefined data types. +*/ +QStringList JsonFilter::dataTypes() { + const QMetaObject& mo = AbstractColumn::staticMetaObject; + const QMetaEnum& me = mo.enumerator(mo.indexOfEnumerator("ColumnMode")); + QStringList list; + for (int i = 0; i <= 100; ++i) // me.keyCount() does not work because we have holes in enum + if (me.valueToKey(i)) + list << me.valueToKey(i); + return list; +} + +/*! +returns the list of all predefined data container types. +*/ +QStringList JsonFilter::dataContainerTypes() { + return (QStringList() << "Object" << "Array"); +} + +void JsonFilter::setDataContainerName(const QString name) { + d->containerName = name; +} +QString JsonFilter::dataContainerName() const { + return d->containerName; +} + +void JsonFilter::setDataContainerType(const JsonFilter::DataContainerType type) { + d->containerType = type; +} +JsonFilter::DataContainerType JsonFilter::dataContainerType() const { + return d->containerType; +} + +void JsonFilter::setDataRowType(QJsonValue::Type type) { + d->rowType = type; +} +QJsonValue::Type JsonFilter::dataRowType() const { + return d->rowType; +} + +void JsonFilter::setDateTimeFormat(const QString &f) { + d->dateTimeFormat = f; +} +QString JsonFilter::dateTimeFormat() const { + return d->dateTimeFormat; +} + +void JsonFilter::setNumberFormat(QLocale::Language lang) { + d->numberFormat = lang; +} +QLocale::Language JsonFilter::numberFormat() const { + return d->numberFormat; +} + +void JsonFilter::setNaNValueToZero(bool b) { + if (b) + d->nanValue = 0; + else + d->nanValue = NAN; +} +bool JsonFilter::NaNValueToZeroEnabled() const { + if (d->nanValue == 0) + return true; + return false; +} + +void JsonFilter::setCreateIndexEnabled(bool b){ + d->createIndexEnabled = b; +} +QVector JsonFilter::columnModes() { + return d->columnModes; +} + +void JsonFilter::setStartRow(const int r) { + d->startRow = r; +} +int JsonFilter::startRow() const { + return d->startRow; +} + +void JsonFilter::setEndRow(const int r) { + d->endRow = r; +} +int JsonFilter::endRow() const { + return d->endRow; +} + +void JsonFilter::setStartColumn(const int c) { + d->startColumn = c; +} +int JsonFilter::startColumn() const { + return d->startColumn; +} + +void JsonFilter::setEndColumn(const int c) { + d->endColumn = c; +} +int JsonFilter::endColumn() const { + return d->endColumn; +} + +//##################################################################### +//################### Private implementation ########################## +//##################################################################### +JsonFilterPrivate::JsonFilterPrivate(JsonFilter* owner) : q(owner), + containerName(), + containerType(JsonFilter::Object), + rowType(QJsonValue::Object), + numberFormat(QLocale::C), + createIndexEnabled(false), + startRow(1), + endRow(-1), + startColumn(1), + endColumn(-1), + m_actualRows(0), + m_actualCols(0), + m_prepared(false), + m_columnOffset(0) { + +} + +int JsonFilterPrivate::checkRow(QJsonValueRef value, int& countCols) { + switch(rowType){ + //TODO: implement other value types + case QJsonValue::Array: { + QJsonArray row = value.toArray(); + if(row.isEmpty()) + return 1; + countCols = (countCols == -1 || countCols > row.count()) ? row.count() : countCols; + break; + } + case QJsonValue::Object: { + QJsonObject row = value.toObject(); + if(row.isEmpty()) + return 1; + countCols = (countCols == -1 || countCols > row.count()) ? row.count() : countCols; + break; + } + case QJsonValue::Double: + case QJsonValue::String: + case QJsonValue::Bool: + case QJsonValue::Null: + case QJsonValue::Undefined: + return 1; + } + return 0; +} +/*! +returns -1 if a parse error has occurred, 1 if the current row type not supported and 0 otherwise. +*/ +int JsonFilterPrivate::parseColumnModes(QJsonValue row) { + columnModes.resize(m_actualCols); + + int colIndexInContainer = startColumn - 1; + for(int i = 0; i < m_actualCols; i++){ + if(createIndexEnabled && i == 0){ + columnModes[i] = AbstractColumn::Integer; + continue; + } + + QJsonValue columnValue; + switch (rowType) { + //TODO: implement other value types + case QJsonValue::Array: { + QJsonArray arr = row.toArray(); + if(arr.count() < colIndexInContainer + 1) + return -1; + columnValue = *(row.toArray().begin() + colIndexInContainer); + break; + } + case QJsonValue::Object: { + QJsonObject obj = row.toObject(); + if(obj.count() < colIndexInContainer + 1) + return -1; + columnValue = *(row.toObject().begin() + colIndexInContainer); + break; + } + case QJsonValue::Double: + case QJsonValue::String: + case QJsonValue::Bool: + case QJsonValue::Null: + case QJsonValue::Undefined: + return 1; + } + + switch (columnValue.type()) { + case QJsonValue::Double: + columnModes[i] = AbstractColumn::Numeric; + break; + case QJsonValue::String: + columnModes[i] = AbstractFileFilter::columnMode(columnValue.toString(), dateTimeFormat, numberFormat); + break; + case QJsonValue::Array: + case QJsonValue::Object: + case QJsonValue::Bool: + case QJsonValue::Null: + case QJsonValue::Undefined: + return -1; + } + colIndexInContainer++; + } + return 0; +} + +QString JsonFilterPrivate::getEmptyValue(AbstractColumn::ColumnMode mode){ + switch (mode) { + case AbstractColumn::Numeric: + return QString::number(nanValue, 'g', 16); + case AbstractColumn::Integer: + return QString::number(0); + case AbstractColumn::DateTime: + case AbstractColumn::Text: + case AbstractColumn::Month: + case AbstractColumn::Day: + default: + return QString(); + } +} + +void JsonFilterPrivate::setEmptyValue(int column, int row){ + switch (columnModes[column]) { + case AbstractColumn::Numeric: + static_cast*>(m_dataContainer[column])->operator[](row) = nanValue; + break; + case AbstractColumn::Integer: + static_cast*>(m_dataContainer[column])->operator[](row) = 0; + break; + case AbstractColumn::DateTime: + static_cast*>(m_dataContainer[column])->operator[](row) = QDateTime(); + break; + case AbstractColumn::Text: + static_cast*>(m_dataContainer[column])->operator[](row) = ""; + break; + case AbstractColumn::Month: + case AbstractColumn::Day: + break; + } +} + +void JsonFilterPrivate::setValueFromString(int column, int row, QString valueString){ + QLocale locale(numberFormat); + switch (columnModes[column]) { + case AbstractColumn::Numeric: { + bool isNumber; + const double value = locale.toDouble(valueString, &isNumber); + static_cast*>(m_dataContainer[column])->operator[](row) = isNumber ? value : nanValue; + break; + } + case AbstractColumn::Integer: { + bool isNumber; + const int value = locale.toInt(valueString, &isNumber); + static_cast*>(m_dataContainer[column])->operator[](row) = isNumber ? value : 0; + break; + } + case AbstractColumn::DateTime: { + const QDateTime valueDateTime = QDateTime::fromString(valueString, dateTimeFormat); + static_cast*>(m_dataContainer[column])->operator[](row) = + valueDateTime.isValid() ? valueDateTime : QDateTime(); + break; + } + case AbstractColumn::Text: + static_cast*>(m_dataContainer[column])->operator[](row) = valueString; + break; + case AbstractColumn::Month: + case AbstractColumn::Day: + break; + } +} + +/*! +returns -1 if the device couldn't be opened, 1 if the current read position in the device is at the end, +2 if a parse error has occurred and 0 otherwise. +*/ +int JsonFilterPrivate::prepareDeviceToRead(QIODevice& device) { + DEBUG("device is sequential = " << device.isSequential()); + + if (!device.open(QIODevice::ReadOnly)) + return -1; + + if (device.atEnd() && !device.isSequential()) // empty file + return 1; + + QJsonParseError err; + QJsonDocument doc = QJsonDocument::fromJson(device.readAll(), &err); + + if(err.error != QJsonParseError::NoError || doc.isEmpty()) + return 1; + + int countRows = 0; + int countCols = -1; + QJsonValue firstRow; + switch(containerType) { + case JsonFilter::Array: { + QJsonArray arr; + if(!containerName.isEmpty()) + arr = doc.object()[containerName].toArray(); + else + arr = doc.array(); + + if(arr.count() < startRow) + return 2; + + int endRowOffset = (endRow == -1 || endRow > arr.count()) ? arr.count() : endRow; + firstRow = *(arr.begin() + (startRow - 1)); + for(QJsonArray::iterator it = arr.begin() + (startRow - 1); it != arr.begin() + endRowOffset; ++it) { + if(checkRow(*it, countCols) != 0) + return 2; + countRows++; + } + break; + } + case JsonFilter::Object: { + QJsonObject obj = doc.object(); + if(!containerName.isEmpty()) + obj = obj[containerName].toObject(); + + if(obj.count() < startRow) + return 2; + + int startRowOffset = startRow - 1; + int endRowOffset = (endRow == -1 || endRow > obj.count()) ? obj.count() : endRow; + firstRow = *(obj.begin() + startRowOffset); + for(QJsonObject::iterator it = obj.begin() + startRowOffset; it != obj.begin() + endRowOffset; ++it) { + if(checkRow(*it, countCols) != 0) + return 2; + countRows++; + } + break; + } + } + + if(endColumn == -1 || endColumn > countCols) + endColumn = countCols; + + m_actualRows = countRows; + m_actualCols = endColumn - startColumn + 1 + createIndexEnabled; + m_preparedDoc = doc; + + if(parseColumnModes(firstRow) != 0) + return 2; + // reset to start of file + if (!device.isSequential()) + device.seek(0); + + DEBUG("start/end column: = " << startColumn << ' ' << endColumn); + DEBUG("start/end rows = " << startRow << ' ' << endRow); + DEBUG("actual cols/rows = " << m_actualCols << ' ' << m_actualRows); + + return 0; +} + +/*! +reads the content of the file \c fileName to the data source \c dataSource. Uses the settings defined in the data source. +*/ +void JsonFilterPrivate::readDataFromFile(const QString& fileName, AbstractDataSource* dataSource, AbstractFileFilter::ImportMode importMode, int lines) { + KFilterDev device(fileName); + readDataFromDevice(device, dataSource, importMode, lines); +} + +/*! +reads the content of device \c device to the data source \c dataSource. Uses the settings defined in the data source. +*/ +void JsonFilterPrivate::readDataFromDevice(QIODevice& device, AbstractDataSource* dataSource, AbstractFileFilter::ImportMode importMode, int lines) { + Q_UNUSED(lines) + + if(!m_prepared) { + const int deviceError = prepareDeviceToRead(device); + if(deviceError != 0){ + DEBUG("Device error = " << deviceError); + return; + } + //TODO: support other modes and vector names + m_columnOffset = dataSource->prepareImport(m_dataContainer, importMode, m_actualRows, m_actualCols, QStringList(), columnModes); + m_prepared = true; + } + + DEBUG("reading " << m_actualRows << " lines"); + for(int i = 0; i < m_actualRows; ++i) { + QJsonValue row; + switch (containerType) { + case JsonFilter::Array: { + if (containerName.isEmpty()) + row = *(m_preparedDoc.array().begin() + startRow + i); + else + row = *(m_preparedDoc.object()[containerName].toArray().begin() + startRow + i); + break; + } + case JsonFilter::Object: { + if (containerName.isEmpty()) + row = *(m_preparedDoc.object().begin() + startRow + i); + else + row = *(m_preparedDoc.object()[containerName].toObject().begin() + startRow + i); + break; + } + } + + int colIndex = 0; + for(int n = 0; n < m_actualCols; ++n) { + if(createIndexEnabled && n == 0) { + static_cast*>(m_dataContainer[n])->operator[](i) = i + 1; + continue; + } + QJsonValue value; + switch(rowType){ + //TODO: implement other value types + case QJsonValue::Array: { + value = *(row.toArray().begin() + colIndex); + } + case QJsonValue::Object: { + value = *(row.toObject().begin() + colIndex); + } + case QJsonValue::Double: + case QJsonValue::String: + case QJsonValue::Bool: + case QJsonValue::Null: + case QJsonValue::Undefined: + break; + } + + switch(value.type()) { + case QJsonValue::Double: + if(columnModes[n] == AbstractColumn::Numeric) + static_cast*>(m_dataContainer[n])->operator[](i) = value.toDouble(); + else + setEmptyValue(n, i + startRow - 1); + break; + case QJsonValue::String: + setValueFromString(n, i, value.toString()); + break; + case QJsonValue::Array: + case QJsonValue::Object: + case QJsonValue::Bool: + case QJsonValue::Null: + case QJsonValue::Undefined: + setEmptyValue(n, i + startRow - 1); + break; + } + colIndex++; + } + emit q->completed(100 * i/m_actualRows); + } + //TODO: fix (startColumn + m_actualCols - 1) + dataSource->finalizeImport(m_columnOffset, startColumn, startColumn + m_actualCols - 1, dateTimeFormat, importMode); +} + +/*! +generates the preview for device \c device. +*/ +QVector JsonFilterPrivate::preview(QIODevice &device) { + QVector dataStrings; + const int deviceError = prepareDeviceToRead(device); + if (deviceError != 0) { + DEBUG("Device error = " << deviceError); + return dataStrings; + } + + DEBUG("reading " << m_actualRows << " lines"); + for(int i = 0; i < m_actualRows; ++i) { + QJsonValue row; + switch (containerType) { + case JsonFilter::Object: { + if (containerName.isEmpty()) + row = *(m_preparedDoc.object().begin() + startRow + i); + else + row = *(m_preparedDoc.object()[containerName].toObject().begin() + startRow + i); + break; + } + case JsonFilter::Array: { + if (containerName.isEmpty()) + row = *(m_preparedDoc.array().begin() + startRow + i); + else + row = *(m_preparedDoc.object()[containerName].toArray().begin() + startRow + i); + break; + } + } + + QStringList lineString; + int colIndex = 0; + for(int n = 0; n < m_actualCols; ++n) { + if(createIndexEnabled && n == 0) { + lineString += QString::number(i + 1); + continue; + } + QJsonValue value; + switch(rowType){ + case QJsonValue::Object: { + value = *(row.toObject().begin() + colIndex); + } + case QJsonValue::Array: { + value = *(row.toArray().begin() + colIndex); + } + //TODO: implement other value types + case QJsonValue::Double: + case QJsonValue::String: + case QJsonValue::Bool: + case QJsonValue::Null: + case QJsonValue::Undefined: + break; + } + switch(value.type()) { + case QJsonValue::Double: + if(columnModes[n] == AbstractColumn::Numeric) + lineString += QString::number(value.toDouble(), 'g', 16); + else + lineString += lineString += QLatin1String(""); + break; + case QJsonValue::String: { + //TODO: add parsing string before appending + lineString += value.toString(); + break; + } + case QJsonValue::Array: + case QJsonValue::Object: + case QJsonValue::Bool: + case QJsonValue::Null: + case QJsonValue::Undefined: + lineString += QLatin1String(""); + break; + } + colIndex++; + } + dataStrings << lineString; + emit q->completed(100 * i/m_actualRows); + } + return dataStrings; +} + +/*! +generates the preview for the file \c fileName. +*/ +QVector JsonFilterPrivate::preview(const QString& fileName) { + KFilterDev device(fileName); + return preview(device); +} + +/*! +writes the content of \c dataSource to the file \c fileName. +*/ +void JsonFilterPrivate::write(const QString& fileName, AbstractDataSource* dataSource) { + Q_UNUSED(fileName); + Q_UNUSED(dataSource); + + //TODO: save data to json file +} + +//############################################################################## +//################## Serialization/Deserialization ########################### +//############################################################################## +/*! +Saves as XML. +*/ +void JsonFilter::save(QXmlStreamWriter* writer) const { + writer->writeStartElement("jsonFilter"); + writer->writeAttribute("containerName", d->containerName); + writer->writeAttribute("containerType", QString::number(d->containerType)); + writer->writeAttribute("rowType", QString::number(d->rowType)); + writer->writeAttribute("dateTimeFormat", d->dateTimeFormat); + writer->writeAttribute("numberFormat", QString::number(d->numberFormat)); + writer->writeAttribute("createIndex", QString::number(d->createIndexEnabled)); + writer->writeAttribute("nanValue", QString::number(d->nanValue)); + writer->writeAttribute("startRow", QString::number(d->startRow)); + writer->writeAttribute("endRow", QString::number(d->endRow)); + writer->writeAttribute("startColumn", QString::number(d->startColumn)); + writer->writeAttribute("endColumn", QString::number(d->endColumn)); + + writer->writeEndElement(); +} + +/*! +Loads from XML. +*/ +bool JsonFilter::load(XmlStreamReader* reader) { + if (!reader->isStartElement() || reader->name() != "jsonFilter") { + reader->raiseError(i18n("no json filter element found")); + return false; + } + QString attributeWarning = i18n("Attribute '%1' missing or empty, default value is used"); + QXmlStreamAttributes attribs = reader->attributes(); + + QString str = attribs.value("containerName").toString(); + if (str.isEmpty()) + reader->raiseWarning(attributeWarning.arg("'containerName'")); + else + d->containerName = str; + + str = attribs.value("containerType").toString(); + if (str.isEmpty()) + reader->raiseWarning(attributeWarning.arg("'containerType'")); + else + d->containerType = static_cast(str.toInt()); + + str = attribs.value("rowType").toString(); + if (str.isEmpty()) + reader->raiseWarning(attributeWarning.arg("'rowType'")); + else + d->rowType = static_cast(str.toInt()); + + str = attribs.value("dateTimeFormat").toString(); + if (str.isEmpty()) + reader->raiseWarning(attributeWarning.arg("'dateTimeFormat'")); + else + d->dateTimeFormat = str; + + str = attribs.value("numberFormat").toString(); + if (str.isEmpty()) + reader->raiseWarning(attributeWarning.arg("'numberFormat'")); + else + d->numberFormat = static_cast(str.toInt()); + + str = attribs.value("createIndex").toString(); + if (str.isEmpty()) + reader->raiseWarning(attributeWarning.arg("'createIndex'")); + else + d->createIndexEnabled = str.toInt(); + + str = attribs.value("nanValue").toString(); + if (str.isEmpty()) + reader->raiseWarning(attributeWarning.arg("'nanValue'")); + else + d->nanValue = str.toDouble(); + + str = attribs.value("startRow").toString(); + if (str.isEmpty()) + reader->raiseWarning(attributeWarning.arg("'startRow'")); + else + d->startRow = str.toInt(); + + str = attribs.value("endRow").toString(); + if (str.isEmpty()) + reader->raiseWarning(attributeWarning.arg("'endRow'")); + else + d->endRow = str.toInt(); + + str = attribs.value("startColumn").toString(); + if (str.isEmpty()) + reader->raiseWarning(attributeWarning.arg("'startColumn'")); + else + d->startColumn = str.toInt(); + + str = attribs.value("endColumn").toString(); + if (str.isEmpty()) + reader->raiseWarning(attributeWarning.arg("'endColumn'")); + else + d->endColumn = str.toInt(); + + return true; +} \ No newline at end of file diff --git a/src/backend/datasources/filters/JsonFilter.h b/src/backend/datasources/filters/JsonFilter.h new file mode 100644 index 000000000..ccb2400da --- /dev/null +++ b/src/backend/datasources/filters/JsonFilter.h @@ -0,0 +1,71 @@ +#ifndef JSONFILTER_H +#define JSONFILTER_H + +#include "backend/datasources/filters/AbstractFileFilter.h" +#include "backend/core/AbstractColumn.h" +#include + +class QStringList; +class QIODevice; +class JsonFilterPrivate; + +class JsonFilter : public AbstractFileFilter { + Q_OBJECT + +public: + enum DataContainerType {Array, Object}; + + JsonFilter(); + ~JsonFilter() override; + + static QStringList dataTypes(); + static QStringList dataContainerTypes(); + + // read data from any device + void readDataFromDevice(QIODevice& device, AbstractDataSource*, + AbstractFileFilter::ImportMode = AbstractFileFilter::Replace, int lines = -1); + // overloaded function to read from file + QVector readDataFromFile(const QString& fileName, AbstractDataSource* = nullptr, + AbstractFileFilter::ImportMode = AbstractFileFilter::Replace, int lines = -1) override; + void write(const QString& fileName, AbstractDataSource*) override; + + QVector preview(const QString& fileName); + QVector preview(QIODevice& device); + + void loadFilterSettings(const QString&) override; + void saveFilterSettings(const QString&) const override; + + void setDataContainerName(const QString); + QString dataContainerName() const; + void setDataContainerType(const JsonFilter::DataContainerType); + JsonFilter::DataContainerType dataContainerType() const; + void setDataRowType(const QJsonValue::Type); + QJsonValue::Type dataRowType() const; + + void setDateTimeFormat(const QString&); + QString dateTimeFormat() const; + void setNumberFormat(QLocale::Language); + QLocale::Language numberFormat() const; + void setNaNValueToZero(const bool); + bool NaNValueToZeroEnabled() const; + void setCreateIndexEnabled(const bool); + QVector columnModes(); + + void setStartRow(const int); + int startRow() const; + void setEndRow(const int); + int endRow() const; + void setStartColumn(const int); + int startColumn() const; + void setEndColumn(const int); + int endColumn() const; + + void save(QXmlStreamWriter*) const override; + bool load(XmlStreamReader*) override; + +private: + std::unique_ptr const d; + friend class JsonFilterPrivate; +}; + +#endif diff --git a/src/backend/datasources/filters/JsonFilterPrivate.h b/src/backend/datasources/filters/JsonFilterPrivate.h new file mode 100644 index 000000000..52fdfe86d --- /dev/null +++ b/src/backend/datasources/filters/JsonFilterPrivate.h @@ -0,0 +1,56 @@ +#ifndef JSONFILTERPRIVATE_H +#define JSONFILTERPRIVATE_H + +#include + +class KFilterDev; +class AbstractDataSource; +class AbstractColumn; + +class JsonFilterPrivate { + +public: + JsonFilterPrivate ( JsonFilter* owner ); + + int checkRow(QJsonValueRef value, int &countCols); + int parseColumnModes(QJsonValue value); + QString getEmptyValue(AbstractColumn::ColumnMode); + void setEmptyValue(int column, int row); + void setValueFromString(int column, int row, QString value); + + int prepareDeviceToRead(QIODevice&); + void readDataFromDevice(QIODevice& device, AbstractDataSource* = nullptr, + AbstractFileFilter::ImportMode = AbstractFileFilter::Replace, int lines = -1); + void readDataFromFile(const QString& fileName, AbstractDataSource* = nullptr, + AbstractFileFilter::ImportMode = AbstractFileFilter::Replace, int lines = -1); + void write(const QString& fileName, AbstractDataSource*); + QVector preview(const QString& fileName); + QVector preview(QIODevice& device); + + const JsonFilter* q; + + QString containerName; + JsonFilter::DataContainerType containerType; + QJsonValue::Type rowType; + + QString dateTimeFormat; + QLocale::Language numberFormat; + double nanValue; + bool createIndexEnabled; + QVector columnModes; + + int startRow; // start row + int endRow; // end row + int startColumn; // start column + int endColumn; // end column + +private: + int m_actualRows; + int m_actualCols; + int m_prepared; + int m_columnOffset; // indexes the "start column" in the datasource. Data will be imported starting from this column. + QVector m_dataContainer; // pointers to the actual data containers (columns). + QJsonDocument m_preparedDoc; // parsed Json document +}; + +#endif