diff --git a/src/backend/core/AbstractAspect.h b/src/backend/core/AbstractAspect.h index 5c0a85b6f..a45023114 100644 --- a/src/backend/core/AbstractAspect.h +++ b/src/backend/core/AbstractAspect.h @@ -1,298 +1,298 @@ /*************************************************************************** File : AbstractAspect.h Project : LabPlot -------------------------------------------------------------------- Copyright : (C) 2007-2009 by Tilman Benkert (thzs@gmx.net) Copyright : (C) 2007-2010 by Knut Franke (knut.franke@gmx.de) Copyright : (C) 2011-2015 by Alexander Semke (alexander.semke@web.de) Description : Base class for all objects in a Project. ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301 USA * * * ***************************************************************************/ #ifndef ABSTRACT_ASPECT_H #define ABSTRACT_ASPECT_H #include #include class AbstractAspectPrivate; class Folder; class Project; class XmlStreamReader; class QDateTime; class QDropEvent; class QIcon; class QMenu; class QUndoCommand; class QUndoStack; class QXmlStreamWriter; /// Information about class inheritance /// enum values are chosen such that @verbatim inherits(base)@endverbatim /// returns true iff the class inherits from @verbatim base@endverbatim. /// /// AspectType is used in GuiObserver to select the correct dock widget. enum class AspectType : quint64 { AbstractAspect = 0, // classes without inheriters AbstractFilter = 0x0100001, DatapickerCurve = 0x0100002, DatapickerPoint = 0x0100004, WorksheetElement = 0x0200000, Axis = 0x0210001, CartesianPlotLegend = 0x0210002, CustomPoint = 0x0210004, Histogram = 0x0210008, PlotArea = 0x0210010, TextLabel = 0x0210020, WorksheetElementContainer = 0x0220000, AbstractPlot = 0x0221000, CartesianPlot = 0x0221001, WorksheetElementGroup = 0x0222000, XYCurve = 0x0240000, XYEquationCurve = 0x0240001, XYAnalysisCurve = 0x0280000, XYConvolution = 0x0280001, XYCorrelationCurve = 0x0280002, XYDataReductionCurve = 0x0280004, XYDifferentiationCurve = 0x0280008, XYFitCurve = 0x0280010, XYFourierFilterCurve = 0x0280020, XYFourierTransformCurve = 0x0280040, XYInterpolationCurve = 0x0280080, XYIntegrationCurve = 0x0280100, XYSmoothCurve = 0x0280200, AbstractPart = 0x0400000, AbstractDataSource = 0x0410000, Matrix = 0x0411000, Spreadsheet = 0x0412000, LiveDataSource = 0x0412001, MQTTTopic = 0x0412002, CantorWorksheet = 0x0420001, Datapicker = 0x0420002, DatapickerImage = 0x0420004, Note = 0x0420008, Workbook = 0x0420010, Worksheet = 0x0420020, AbstractColumn = 0x1000000, Column = 0x1000001, SimpleFilterColumn = 0x1000002, ColumnStringIO = 0x1000004, Folder = 0x2000000, Project = 0x2000001, MQTTClient = 0x2000002, MQTTSubscription = 0x2000004, }; class AbstractAspect : public QObject { Q_OBJECT public: enum ChildIndexFlag { IncludeHidden = 0x01, Recursive = 0x02, Compress = 0x04 }; Q_DECLARE_FLAGS(ChildIndexFlags, ChildIndexFlag) friend class AspectChildAddCmd; friend class AspectChildRemoveCmd; friend class AbstractAspectPrivate; AbstractAspect(const QString& name, AspectType type); ~AbstractAspect() override; QString name() const; QString comment() const; void setCreationTime(const QDateTime&); QDateTime creationTime() const; virtual Project* project(); virtual QString path() const; void setHidden(bool); bool hidden() const; void setSelected(bool); void setIsLoading(bool); bool isLoading() const; virtual QIcon icon() const; virtual QMenu* createContextMenu(); AspectType type() const; bool inherits(AspectType type) const; //functions related to the handling of the tree-like project structure AbstractAspect* parentAspect() const; AbstractAspect* parent(AspectType type) const; void setParentAspect(AbstractAspect*); Folder* folder(); bool isDescendantOf(AbstractAspect* other); void addChild(AbstractAspect*); void addChildFast(AbstractAspect*); virtual void finalizeAdd() {}; QVector children(AspectType type, ChildIndexFlags flags=nullptr) const; void insertChildBefore(AbstractAspect* child, AbstractAspect* before); void insertChildBeforeFast(AbstractAspect* child, AbstractAspect* before); void reparent(AbstractAspect* newParent, int newIndex = -1); void removeChild(AbstractAspect*); void removeAllChildren(); virtual QVector dependsOn() const; virtual bool isDraggable() const; virtual QVector dropableOn() const; virtual void processDropEvent(QDropEvent*) {}; template T* ancestor() const { AbstractAspect* parent = parentAspect(); while (parent) { T* ancestorAspect = dynamic_cast(parent); if (ancestorAspect) return ancestorAspect; parent = parent->parentAspect(); } return nullptr; } template QVector children(ChildIndexFlags flags = nullptr) const { QVector result; for (auto* child: children()) { if (flags & IncludeHidden || !child->hidden()) { T* i = dynamic_cast(child); if (i) result << i; - if (flags & Recursive) + if (child && flags & Recursive) result << child->template children(flags); } } return result; } template T* child(int index, ChildIndexFlags flags=nullptr) const { int i = 0; for (auto* child: children()) { T* c = dynamic_cast(child); if (c && (flags & IncludeHidden || !child->hidden()) && index == i++) return c; } return nullptr; } template T* child(const QString& name) const { for (auto* child: children()) { T* c = dynamic_cast(child); if (c && child->name() == name) return c; } return nullptr; } template int childCount(ChildIndexFlags flags = nullptr) const { int result = 0; for (auto* child: children()) { T* i = dynamic_cast(child); if (i && (flags & IncludeHidden || !child->hidden())) result++; } return result; } template int indexOfChild(const AbstractAspect* child, ChildIndexFlags flags = nullptr) const { int index = 0; for (auto* c: children()) { if (child == c) return index; T* i = dynamic_cast(c); if (i && (flags & IncludeHidden || !c->hidden())) index++; } return -1; } //undo/redo related functions void setUndoAware(bool); virtual QUndoStack* undoStack() const; void exec(QUndoCommand*); void exec(QUndoCommand* command, const char* preChangeSignal, const char* postChangeSignal, QGenericArgument val0 = QGenericArgument(), QGenericArgument val1 = QGenericArgument(), QGenericArgument val2 = QGenericArgument(), QGenericArgument val3 = QGenericArgument()); void beginMacro(const QString& text); void endMacro(); //save/load virtual void save(QXmlStreamWriter*) const = 0; virtual bool load(XmlStreamReader*, bool preview) = 0; protected: void info(const QString& text) { emit statusInfo(text); } //serialization/deserialization bool readBasicAttributes(XmlStreamReader*); void writeBasicAttributes(QXmlStreamWriter*) const; void writeCommentElement(QXmlStreamWriter*) const; bool readCommentElement(XmlStreamReader*); const AspectType m_type; private: AbstractAspectPrivate* d; QString uniqueNameFor(const QString&) const; const QVector children() const; void connectChild(AbstractAspect*); public slots: bool setName(const QString&, bool autoUnique = true); void setComment(const QString&); void remove(); protected slots: virtual void childSelected(const AbstractAspect*); virtual void childDeselected(const AbstractAspect*); signals: void aspectDescriptionAboutToChange(const AbstractAspect*); void aspectDescriptionChanged(const AbstractAspect*); void aspectAboutToBeAdded(const AbstractAspect* parent, const AbstractAspect* before, const AbstractAspect* child); void aspectAdded(const AbstractAspect*); void aspectAboutToBeRemoved(const AbstractAspect*); void aspectRemoved(const AbstractAspect* parent, const AbstractAspect* before, const AbstractAspect* child); void aspectHiddenAboutToChange(const AbstractAspect*); void aspectHiddenChanged(const AbstractAspect*); void statusInfo(const QString&); void renameRequested(); //selection/deselection in model (project explorer) void selected(const AbstractAspect*); void deselected(const AbstractAspect*); //selection/deselection in view void childAspectSelectedInView(const AbstractAspect*); void childAspectDeselectedInView(const AbstractAspect*); }; Q_DECLARE_OPERATORS_FOR_FLAGS(AbstractAspect::ChildIndexFlags) #endif // ifndef ABSTRACT_ASPECT_H diff --git a/src/backend/datasources/filters/HDF5Filter.cpp b/src/backend/datasources/filters/HDF5Filter.cpp index 3974ce81e..f5663e834 100644 --- a/src/backend/datasources/filters/HDF5Filter.cpp +++ b/src/backend/datasources/filters/HDF5Filter.cpp @@ -1,1931 +1,1935 @@ /*************************************************************************** File : HDF5Filter.cpp Project : LabPlot Description : HDF5 I/O-filter -------------------------------------------------------------------- Copyright : (C) 2015-2018 by Stefan Gerlach (stefan.gerlach@uni.kn) Copyright : (C) 2017 Alexander Semke (alexander.semke@web.de) ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301 USA * * * ***************************************************************************/ /* TODO: * Feature: implement missing data types and ranks * Performance: only fill dataPointer or dataStrings (not both) */ #include "backend/datasources/filters/HDF5Filter.h" #include "backend/datasources/filters/HDF5FilterPrivate.h" #include "backend/datasources/LiveDataSource.h" #include "backend/core/column/Column.h" #include #include #include #include /*! \class HDF5Filter \brief Manages the import/export of data from/to a HDF5 file. \ingroup datasources */ HDF5Filter::HDF5Filter():AbstractFileFilter(HDF5), d(new HDF5FilterPrivate(this)) {} HDF5Filter::~HDF5Filter() = default; /*! parses the content of the file \c fileName. */ void HDF5Filter::parse(const QString & fileName, QTreeWidgetItem* rootItem) { d->parse(fileName, rootItem); } /*! reads the content of the data set \c dataSet from file \c fileName. */ QVector HDF5Filter::readCurrentDataSet(const QString& fileName, AbstractDataSource* dataSource, bool &ok, AbstractFileFilter::ImportMode importMode, int lines) { return d->readCurrentDataSet(fileName, dataSource, ok, importMode, lines); } /*! reads the content of the file \c fileName to the data source \c dataSource. */ void HDF5Filter::readDataFromFile(const QString& fileName, AbstractDataSource* dataSource, AbstractFileFilter::ImportMode mode) { d->readDataFromFile(fileName, dataSource, mode); } /*! writes the content of the data source \c dataSource to the file \c fileName. */ void HDF5Filter::write(const QString& fileName, AbstractDataSource* dataSource) { d->write(fileName, dataSource); } /////////////////////////////////////////////////////////////////////// /*! loads the predefined filter settings for \c filterName */ void HDF5Filter::loadFilterSettings(const QString& filterName) { Q_UNUSED(filterName); } /*! saves the current settings as a new filter with the name \c filterName */ void HDF5Filter::saveFilterSettings(const QString& filterName) const { Q_UNUSED(filterName); } /////////////////////////////////////////////////////////////////////// void HDF5Filter::setCurrentDataSetName(const QString& ds) { d->currentDataSetName = ds; } const QString HDF5Filter::currentDataSetName() const { return d->currentDataSetName; } void HDF5Filter::setStartRow(const int s) { d->startRow = s; } int HDF5Filter::startRow() const { return d->startRow; } void HDF5Filter::setEndRow(const int e) { d->endRow = e; } int HDF5Filter::endRow() const { return d->endRow; } void HDF5Filter::setStartColumn(const int c) { d->startColumn = c; } int HDF5Filter::startColumn() const { return d->startColumn; } void HDF5Filter::setEndColumn(const int c) { d->endColumn = c; } int HDF5Filter::endColumn() const { return d->endColumn; } QString HDF5Filter::fileInfoString(const QString& fileName) { DEBUG("HDF5Filter::fileInfoString()"); QString info; #ifdef HAVE_HDF5 QByteArray bafileName = fileName.toLatin1(); DEBUG("fileName = " << bafileName.data()); // check file type first htri_t isHdf5 = H5Fis_hdf5(bafileName.data()); if (isHdf5 == 0) { DEBUG(bafileName.data() << " is not a HDF5 file! isHdf5 = " << isHdf5 << " Giving up."); return i18n("Not a HDF5 file"); } if (isHdf5 < 0) { DEBUG("H5Fis_hdf5() failed on " << bafileName.data() << "! Giving up."); return i18n("Failed checking file"); } // open file hid_t file = H5Fopen(bafileName.data(), H5F_ACC_RDONLY, H5P_DEFAULT); HDF5FilterPrivate::handleError((int)file, "H5Fopen", fileName); if (file < 0) { DEBUG("Opening file " << bafileName.data() << " failed! Giving up."); return i18n("Failed opening HDF5 file"); } hsize_t size; herr_t status = H5Fget_filesize(file, &size); if (status >= 0) { info += i18n("File size: %1 bytes", QString::number(size)); info += QLatin1String("
"); } hssize_t freesize = H5Fget_freespace(file); info += i18n("Free space: %1 bytes", QString::number(freesize)); info += QLatin1String("
"); info += QLatin1String("
"); ssize_t objectCount; objectCount = H5Fget_obj_count(file, H5F_OBJ_FILE); info += i18n("Number of files: %1", QString::number(objectCount)); info += QLatin1String("
"); objectCount = H5Fget_obj_count(file, H5F_OBJ_DATASET); info += i18n("Number of data sets: %1", QString::number(objectCount)); info += QLatin1String("
"); objectCount = H5Fget_obj_count(file, H5F_OBJ_GROUP); info += i18n("Number of groups: %1", QString::number(objectCount)); info += QLatin1String("
"); objectCount = H5Fget_obj_count(file, H5F_OBJ_DATATYPE); info += i18n("Number of named datatypes: %1", QString::number(objectCount)); info += QLatin1String("
"); objectCount = H5Fget_obj_count(file, H5F_OBJ_ATTR); info += i18n("Number of attributes: %1", QString::number(objectCount)); info += QLatin1String("
"); objectCount = H5Fget_obj_count(file, H5F_OBJ_ALL); info += i18n("Number of all objects: %1", QString::number(objectCount)); info += QLatin1String("
"); #ifdef HAVE_AT_LEAST_HDF5_1_10_0 // using H5Fget_info2 struct (see H5Fpublic.h) H5F_info2_t file_info; status = H5Fget_info2(file, &file_info); if (status >= 0) { info += QLatin1String("
"); info += i18n("Version of superblock: %1", QString::number(file_info.super.version)); info += QLatin1String("
"); info += i18n("Size of superblock: %1 bytes", QString::number(file_info.super.super_size)); info += QLatin1String("
"); info += i18n("Size of superblock extension: %1 bytes", QString::number(file_info.super.super_ext_size)); info += QLatin1String("
"); info += i18n("Version of free-space manager: %1", QString::number(file_info.free.version)); info += QLatin1String("
"); info += i18n("Size of free-space manager metadata: %1 bytes", QString::number(file_info.free.meta_size)); info += QLatin1String("
"); info += i18n("Total size of free space: %1 bytes", QString::number(file_info.free.tot_space)); info += QLatin1String("
"); info += i18n("Version of shared object header: %1", QString::number(file_info.sohm.version)); info += QLatin1String("
"); info += i18n("Size of shared object header: %1 bytes", QString::number(file_info.sohm.hdr_size)); info += QLatin1String("
"); info += i18n("Size of all shared object header indexes: %1 bytes", QString::number(file_info.sohm.msgs_info.index_size)); info += QLatin1String("
"); info += i18n("Size of the heap: %1 bytes", QString::number(file_info.sohm.msgs_info.heap_size)); info += QLatin1String("
"); } #else // using H5Fget_info1 struct (named H5F_info_t in HDF5 1.8) H5F_info_t file_info; status = H5Fget_info(file, &file_info); if (status >= 0) { info += i18n("Size of superblock extension: %1 bytes", QString::number(file_info.super_ext_size)); info += QLatin1String("
"); info += i18n("Size of shared object header: %1 bytes", QString::number(file_info.sohm.hdr_size)); info += QLatin1String("
"); info += i18n("Size of all shared object header indexes: %1 bytes", QString::number(file_info.sohm.msgs_info.index_size)); info += QLatin1String("
"); info += i18n("Size of the heap: %1 bytes", QString::number(file_info.sohm.msgs_info.heap_size)); info += QLatin1String("
"); } #endif // cache information //see https://support.hdfgroup.org/HDF5/doc/RM/RM_H5F.html info += QLatin1String("
"); H5AC_cache_config_t config; config.version = H5AC__CURR_CACHE_CONFIG_VERSION; status = H5Fget_mdc_config(file, &config); if (status >= 0) { info += i18n("Cache config version: %1", QString::number(config.version)); info += QLatin1String("
"); info += i18n("Adaptive cache resize report function enabled: %1", config.rpt_fcn_enabled ? i18n("Yes") : i18n("No")); info += QLatin1String("
"); info += i18n("Cache initial maximum size: %1 bytes", QString::number(config.initial_size)); info += QLatin1String("
"); info += i18n("Adaptive cache maximum size: %1 bytes", QString::number(config.max_size)); info += QLatin1String("
"); info += i18n("Adaptive cache minimum size: %1 bytes", QString::number(config.min_size)); info += QLatin1String("
"); //TODO: more settings } double hit_rate; status = H5Fget_mdc_hit_rate(file, &hit_rate); + Q_UNUSED(status); info += i18n("Metadata cache hit rate: %1", QString::number(hit_rate)); info += QLatin1String("
"); //TODO: herr_t H5Fget_mdc_image_info(hid_t file_id, haddr_t *image_addr, hsize_t *image_len) size_t max_size, min_clean_size, cur_size; int cur_num_entries; status = H5Fget_mdc_size(file, &max_size, &min_clean_size, &cur_size, &cur_num_entries); if (status >= 0) { info += i18n("Current cache maximum size: %1 bytes", QString::number(max_size)); info += QLatin1String("
"); info += i18n("Current cache minimum clean size: %1 bytes", QString::number(min_clean_size)); info += QLatin1String("
"); info += i18n("Current cache size: %1 bytes", QString::number(cur_size)); info += QLatin1String("
"); info += i18n("Current number of entries in the cache: %1", QString::number(cur_num_entries)); info += QLatin1String("
"); } //TODO: 1.10 herr_t H5Fget_metadata_read_retry_info( hid_t file_id, H5F_retry_info_t *info ) /* TODO: not available hbool_t atomicMode; status = H5Fget_mpi_atomicity(file, &atomicMode); if (status >= 0) { info += i18n("MPI file access atomic mode: %1", atomicMode ? i18n("Yes") : i18n("No")); info += QLatin1String("
"); }*/ #ifdef HAVE_AT_LEAST_HDF5_1_10_0 hbool_t is_enabled, is_currently_logging; status = H5Fget_mdc_logging_status(file, &is_enabled, &is_currently_logging); if (status >= 0) { info += i18n("Logging enabled: %1", is_enabled ? i18n("Yes") : i18n("No")); info += QLatin1String("
"); info += i18n("Events are currently logged: %1", is_currently_logging ? i18n("Yes") : i18n("No")); info += QLatin1String("
"); } #endif #ifdef HAVE_AT_LEAST_HDF5_1_10_1 unsigned int accesses[2], hits[2], misses[2], evictions[2], bypasses[2]; status = H5Fget_page_buffering_stats(file, accesses, hits, misses, evictions, bypasses); if (status >= 0) { info += i18n("Metadata/raw data page buffer accesses: %1 %2", QString::number(accesses[0]), QString::number(accesses[1])); info += QLatin1String("
"); info += i18n("Metadata/raw data page buffer hits: %1 %2", QString::number(hits[0]), QString::number(hits[1])); info += QLatin1String("
"); info += i18n("Metadata/raw data page buffer misses: %1 %2", QString::number(misses[0]), QString::number(misses[1])); info += QLatin1String("
"); info += i18n("Metadata/raw data page buffer evictions: %1 %2", QString::number(evictions[0]), QString::number(evictions[1])); info += QLatin1String("
"); info += i18n("Metadata/raw data accesses bypassing page buffer: %1 %2", QString::number(bypasses[0]), QString::number(bypasses[1])); info += QLatin1String("
"); } else { info += i18n("Page buffer disabled"); info += QLatin1String("
"); DEBUG("H5Fget_page_buffering_stats() status = " << status); } #endif #else Q_UNUSED(fileName); #endif return info; } /*! * Get file content in DDL (Data Description Language) format * uses "h5dump" */ QString HDF5Filter::fileDDLString(const QString& fileName) { DEBUG("HDF5Filter::fileDDLString()"); QString DDLString; #ifdef Q_OS_LINUX auto* proc = new QProcess(); QStringList args; args << "-H" << fileName; proc->start( "h5dump", args); if (proc->waitForReadyRead(1000) == false) DDLString += i18n("Reading from file %1 failed.", fileName); else { DDLString += proc->readAll(); DDLString.replace('\n', "
\n"); DDLString.replace("\t","    "); //DEBUG(" DDL string: " << DDLString.toStdString()); } #else //TODO: h5dump on Win, Mac Q_UNUSED(fileName) #endif return DDLString; } //##################################################################### //################### Private implementation ########################## //##################################################################### HDF5FilterPrivate::HDF5FilterPrivate(HDF5Filter* owner) : q(owner) { #ifdef HAVE_HDF5 m_status = 0; #endif } #ifdef HAVE_HDF5 void HDF5FilterPrivate::handleError(int err, const QString& function, const QString& arg) { #ifdef NDEBUG Q_UNUSED(err) Q_UNUSED(function) Q_UNUSED(arg) #else if (err < 0) { DEBUG("ERROR " << err << ": " << function.toStdString() << "() - " << arg.toStdString()); } #endif } QString HDF5FilterPrivate::translateHDF5Order(H5T_order_t o) { QString order; switch (o) { case H5T_ORDER_LE: order = "LE"; break; case H5T_ORDER_BE: order = "BE"; break; case H5T_ORDER_VAX: order = "VAX"; break; case H5T_ORDER_MIXED: order = "MIXED"; break; case H5T_ORDER_NONE: order = "NONE"; break; case H5T_ORDER_ERROR: order = "ERROR"; break; } return order; } QString HDF5FilterPrivate::translateHDF5Type(hid_t t) { QString type; if (H5Tequal(t, H5T_STD_I8LE) || H5Tequal(t, H5T_STD_I8BE)) type = "CHAR"; else if (H5Tequal(t, H5T_STD_U8LE) || H5Tequal(t, H5T_STD_U8BE)) type = "UCHAR"; else if (H5Tequal(t, H5T_STD_I16LE) || H5Tequal(t, H5T_STD_I16BE)) type = "SHORT"; else if (H5Tequal(t, H5T_STD_U16LE) || H5Tequal(t, H5T_STD_U16BE)) type = "USHORT"; else if (H5Tequal(t, H5T_STD_I32LE) || H5Tequal(t, H5T_STD_I32BE)) type = "INT"; else if (H5Tequal(t, H5T_STD_U32LE) || H5Tequal(t, H5T_STD_U32BE)) type = "UINT"; else if (H5Tequal(t, H5T_NATIVE_LONG)) type = "LONG"; else if (H5Tequal(t, H5T_NATIVE_ULONG)) type = "ULONG"; else if (H5Tequal(t, H5T_STD_I64LE) || H5Tequal(t, H5T_STD_I64BE)) type = "LLONG"; else if (H5Tequal(t, H5T_STD_U64LE) || H5Tequal(t, H5T_STD_U64BE)) type = "ULLONG"; else if (H5Tequal(t, H5T_IEEE_F32LE) || H5Tequal(t, H5T_IEEE_F32BE)) type = "FLOAT"; else if (H5Tequal(t, H5T_IEEE_F64LE) || H5Tequal(t, H5T_IEEE_F64BE)) type = "DOUBLE"; else if (H5Tequal(t, H5T_NATIVE_LDOUBLE)) type = "LDOUBLE"; else type = "UNKNOWN"; return type; } QString HDF5FilterPrivate::translateHDF5Class(H5T_class_t c) { QString dclass; switch (c) { case H5T_INTEGER: dclass = "INTEGER"; break; case H5T_FLOAT: dclass = "FLOAT"; break; case H5T_STRING: dclass = "STRING"; break; case H5T_BITFIELD: dclass = "BITFIELD"; break; case H5T_OPAQUE: dclass = "OPAQUE"; break; case H5T_COMPOUND: dclass = "COMPOUND"; break; case H5T_ARRAY: dclass = "ARRAY"; break; case H5T_ENUM: dclass = "ENUM"; break; case H5T_REFERENCE: dclass = "REFERENCE"; break; case H5T_VLEN: dclass = "VLEN"; break; case H5T_TIME: dclass = "TIME"; break; case H5T_NCLASSES: dclass = "NCLASSES"; break; case H5T_NO_CLASS: dclass = "NOCLASS"; break; } return dclass; } QStringList HDF5FilterPrivate::readHDF5Compound(hid_t tid) { size_t typeSize = H5Tget_size(tid); QString line; line += QLatin1String("COMPOUND(") + QString::number(typeSize) + QLatin1String(") : ("); int members = H5Tget_nmembers(tid); handleError(members, "H5Tget_nmembers"); for (int i = 0; i < members; ++i) { H5T_class_t mclass = H5Tget_member_class(tid, i); handleError((int)mclass, "H5Tget_member_class"); hid_t mtype = H5Tget_member_type(tid, i); handleError((int)mtype, "H5Tget_member_type"); size_t size = H5Tget_size(mtype); handleError((int)size, "H5Tget_size"); QString typeString = translateHDF5Class(mclass); if (mclass == H5T_INTEGER || mclass == H5T_FLOAT) typeString = translateHDF5Type(mtype); line += H5Tget_member_name(tid, i) + QLatin1String("[") + typeString + QLatin1String("(") + QString::number(size) + QLatin1String(")]"); if (i == members-1) line += QLatin1String(")"); else line += QLatin1String(","); m_status = H5Tclose(mtype); handleError(m_status, "H5Tclose"); } QStringList dataString; dataString << line; return dataString; } template QStringList HDF5FilterPrivate::readHDF5Data1D(hid_t dataset, hid_t type, int rows, int lines, void* dataContainer) { DEBUG("readHDF5Data1D() rows = " << rows << ", lines = " << lines); QStringList dataString; // we read all rows of data T* data = new T[rows]; m_status = H5Dread(dataset, type, H5S_ALL, H5S_ALL, H5P_DEFAULT, data); handleError(m_status, "H5Dread"); DEBUG(" startRow = " << startRow << ", endRow = " << endRow); DEBUG(" dataContainer = " << dataContainer); for (int i = startRow - 1; i < qMin(endRow, lines + startRow - 1); ++i) { if (dataContainer) // read to data source static_cast*>(dataContainer)->operator[](i-startRow+1) = data[i]; else // for preview dataString << QString::number(static_cast(data[i])); } delete[] data; return dataString; } QStringList HDF5FilterPrivate::readHDF5CompoundData1D(hid_t dataset, hid_t tid, int rows, int lines, QVector& dataContainer) { DEBUG("HDF5FilterPrivate::readHDF5CompoundData1D()"); DEBUG(" dataContainer size = " << dataContainer.size()); int members = H5Tget_nmembers(tid); handleError(members, "H5Tget_nmembers"); DEBUG(" # members = " << members); QStringList dataString; if (!dataContainer[0]) { for (int i = 0; i < qMin(rows, lines); ++i) dataString << QLatin1String("("); dataContainer.resize(members); // avoid "index out of range" for preview } for (int m = 0; m < members; ++m) { hid_t mtype = H5Tget_member_type(tid, m); handleError((int)mtype, "H5Tget_member_type"); size_t msize = H5Tget_size(mtype); handleError((int)msize, "H5Tget_size"); hid_t ctype = H5Tcreate(H5T_COMPOUND, msize); handleError((int)ctype, "H5Tcreate"); m_status = H5Tinsert(ctype, H5Tget_member_name(tid, m), 0, mtype); handleError(m_status, "H5Tinsert"); QStringList mdataString; if (H5Tequal(mtype, H5T_STD_I8LE) || H5Tequal(mtype, H5T_STD_I8BE)) mdataString = readHDF5Data1D(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, lines, dataContainer[m]); else if (H5Tequal(mtype, H5T_NATIVE_CHAR)) { switch (sizeof(H5T_NATIVE_CHAR)) { case 1: mdataString = readHDF5Data1D(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, lines, dataContainer[m]); break; case 2: mdataString = readHDF5Data1D(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, lines, dataContainer[m]); break; case 4: mdataString = readHDF5Data1D(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, lines, dataContainer[m]); break; case 8: mdataString = readHDF5Data1D(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, lines, dataContainer[m]); break; } } else if (H5Tequal(mtype, H5T_STD_U8LE) || H5Tequal(mtype, H5T_STD_U8BE)) mdataString = readHDF5Data1D(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, lines, dataContainer[m]); else if (H5Tequal(mtype, H5T_NATIVE_UCHAR)) { switch (sizeof(H5T_NATIVE_UCHAR)) { case 1: mdataString = readHDF5Data1D(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, lines, dataContainer[m]); break; case 2: mdataString = readHDF5Data1D(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, lines, dataContainer[m]); break; case 4: mdataString = readHDF5Data1D(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, lines, dataContainer[m]); break; case 8: mdataString = readHDF5Data1D(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, lines, dataContainer[m]); break; } } else if (H5Tequal(mtype, H5T_STD_I16LE) || H5Tequal(mtype, H5T_STD_I16BE) || H5Tequal(mtype, H5T_NATIVE_SHORT)) mdataString = readHDF5Data1D(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, lines, dataContainer[m]); else if (H5Tequal(mtype, H5T_STD_U16LE) || H5Tequal(mtype, H5T_STD_U16BE) || H5Tequal(mtype, H5T_NATIVE_SHORT)) mdataString = readHDF5Data1D(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, lines, dataContainer[m]); else if (H5Tequal(mtype, H5T_STD_I32LE) || H5Tequal(mtype, H5T_STD_I32BE) || H5Tequal(mtype, H5T_NATIVE_INT)) mdataString = readHDF5Data1D(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, lines, dataContainer[m]); else if (H5Tequal(mtype, H5T_STD_U32LE) || H5Tequal(mtype, H5T_STD_U32BE) || H5Tequal(mtype, H5T_NATIVE_UINT)) mdataString = readHDF5Data1D(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, lines, dataContainer[m]); else if (H5Tequal(mtype, H5T_NATIVE_LONG)) mdataString = readHDF5Data1D(dataset, ctype, rows, lines, dataContainer[m]); else if (H5Tequal(mtype, H5T_NATIVE_ULONG)) mdataString = readHDF5Data1D(dataset, ctype, rows, lines, dataContainer[m]); else if (H5Tequal(mtype, H5T_STD_I64LE) || H5Tequal(mtype, H5T_STD_I64BE) || H5Tequal(mtype, H5T_NATIVE_LLONG)) mdataString = readHDF5Data1D(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, lines, dataContainer[m]); else if (H5Tequal(mtype, H5T_STD_U64LE) || H5Tequal(mtype, H5T_STD_U64BE) || H5Tequal(mtype, H5T_NATIVE_ULLONG)) mdataString = readHDF5Data1D(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, lines, dataContainer[m]); else if (H5Tequal(mtype, H5T_IEEE_F32LE) || H5Tequal(mtype, H5T_IEEE_F32BE)) mdataString = readHDF5Data1D(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, lines, dataContainer[m]); else if (H5Tequal(mtype, H5T_IEEE_F64LE) || H5Tequal(mtype, H5T_IEEE_F64BE)) mdataString = readHDF5Data1D(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, lines, dataContainer[m]); else if (H5Tequal(mtype, H5T_NATIVE_LDOUBLE)) mdataString = readHDF5Data1D(dataset, ctype, rows, lines, dataContainer[m]); else { if (dataContainer[m]) { for (int i = startRow-1; i < qMin(endRow, lines + startRow - 1); ++i) static_cast*>(dataContainer[m])->operator[](i - startRow + 1) = 0; } else { for (int i = 0; i < qMin(rows, lines); ++i) mdataString << QLatin1String("_"); } H5T_class_t mclass = H5Tget_member_class(tid, m); handleError((int)mclass, "H5Tget_member_class"); DEBUG("unsupported type of class " << translateHDF5Class(mclass).toStdString()); } if (!dataContainer[0]) { for (int i = 0; i < qMin(rows, lines); ++i) { dataString[i] += mdataString[i]; if (m < members - 1) dataString[i] += QLatin1String(","); } } H5Tclose(ctype); } if (!dataContainer[0]) { for (int i = 0; i < qMin(rows, lines); ++i) dataString[i] += QLatin1String(")"); } return dataString; } template QVector HDF5FilterPrivate::readHDF5Data2D(hid_t dataset, hid_t type, int rows, int cols, int lines, QVector& dataPointer) { DEBUG("readHDF5Data2D() rows = " << rows << ", cols =" << cols << ", lines =" << lines); QVector dataStrings; + if (rows == 0 || cols == 0) + return dataStrings; + T** data = (T**) malloc(rows*sizeof(T*)); data[0] = (T*) malloc(cols*rows*sizeof(T)); for (int i = 1; i < rows; ++i) data[i] = data[0] + i*cols; m_status = H5Dread(dataset, type, H5S_ALL, H5S_ALL, H5P_DEFAULT, &data[0][0]); handleError(m_status,"H5Dread"); for (int i = 0; i < qMin(rows, lines); ++i) { QStringList line; line.reserve(cols); for (int j = 0; j < cols; ++j) { if (dataPointer[0]) static_cast*>(dataPointer[j-startColumn+1])->operator[](i-startRow+1) = data[i][j]; else line << QString::number(static_cast(data[i][j])); } dataStrings << line; } free(data[0]); free(data); QDEBUG(dataStrings); return dataStrings; } QVector HDF5FilterPrivate::readHDF5CompoundData2D(hid_t dataset, hid_t tid, int rows, int cols, int lines) { DEBUG("readHDF5CompoundData2D() rows =" << rows << "cols =" << cols << "lines =" << lines); int members = H5Tget_nmembers(tid); handleError(members, "H5Tget_nmembers"); DEBUG(" # members =" << members); QVector dataStrings; for (int i = 0; i < qMin(rows, lines); ++i) { QStringList lineStrings; for (int j = 0; j < cols; ++j) lineStrings << QLatin1String("("); dataStrings << lineStrings; } //QStringList* data = new QStringList[members]; for (int m = 0; m < members; ++m) { hid_t mtype = H5Tget_member_type(tid, m); handleError((int)mtype, "H5Tget_member_type"); size_t msize = H5Tget_size(mtype); handleError((int)msize, "H5Tget_size"); hid_t ctype = H5Tcreate(H5T_COMPOUND, msize); handleError((int)ctype, "H5Tcreate"); m_status = H5Tinsert(ctype, H5Tget_member_name(tid, m), 0, mtype); handleError(m_status, "H5Tinsert"); // dummy container for all data columns // initially contains one pointer set to NULL QVector dummy(1, nullptr); QVector mdataStrings; if (H5Tequal(mtype, H5T_STD_I8LE) || H5Tequal(mtype, H5T_STD_I8BE)) mdataStrings = readHDF5Data2D(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, cols, lines, dummy); else if (H5Tequal(mtype, H5T_NATIVE_CHAR)) { switch (sizeof(H5T_NATIVE_CHAR)) { case 1: mdataStrings = readHDF5Data2D(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, cols, lines, dummy); break; case 2: mdataStrings = readHDF5Data2D(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, cols, lines, dummy); break; case 4: mdataStrings = readHDF5Data2D(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, cols, lines, dummy); break; case 8: mdataStrings = readHDF5Data2D(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, cols, lines, dummy); break; } } else if (H5Tequal(mtype, H5T_STD_U8LE) || H5Tequal(mtype, H5T_STD_U8BE)) mdataStrings = readHDF5Data2D(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, cols, lines, dummy); else if (H5Tequal(mtype, H5T_NATIVE_UCHAR)) { switch (sizeof(H5T_NATIVE_UCHAR)) { case 1: mdataStrings = readHDF5Data2D(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, cols, lines, dummy); break; case 2: mdataStrings = readHDF5Data2D(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, cols, lines, dummy); break; case 4: mdataStrings = readHDF5Data2D(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, cols, lines, dummy); break; case 8: mdataStrings = readHDF5Data2D(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, cols, lines, dummy); break; } } else if (H5Tequal(mtype, H5T_STD_I16LE) || H5Tequal(mtype, H5T_STD_I16BE)|| H5Tequal(mtype, H5T_NATIVE_SHORT)) mdataStrings = readHDF5Data2D(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, cols, lines, dummy); else if (H5Tequal(mtype, H5T_STD_U16LE) || H5Tequal(mtype, H5T_STD_U16BE) || H5Tequal(mtype, H5T_NATIVE_USHORT)) mdataStrings = readHDF5Data2D(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, cols, lines, dummy); else if (H5Tequal(mtype, H5T_STD_I32LE) || H5Tequal(mtype, H5T_STD_I32BE) || H5Tequal(mtype, H5T_NATIVE_INT)) mdataStrings = readHDF5Data2D(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, cols, lines, dummy); else if (H5Tequal(mtype, H5T_STD_U32LE) || H5Tequal(mtype, H5T_STD_U32BE) || H5Tequal(mtype, H5T_NATIVE_UINT)) mdataStrings = readHDF5Data2D(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, cols, lines, dummy); else if (H5Tequal(mtype, H5T_NATIVE_LONG)) mdataStrings = readHDF5Data2D(dataset, ctype, rows, cols, lines, dummy); else if (H5Tequal(mtype, H5T_NATIVE_ULONG)) mdataStrings = readHDF5Data2D(dataset, ctype, rows, cols, lines, dummy); else if (H5Tequal(mtype, H5T_STD_I64LE) || H5Tequal(mtype, H5T_STD_I64BE) || H5Tequal(mtype, H5T_NATIVE_LLONG)) mdataStrings = readHDF5Data2D(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, cols, lines, dummy); else if (H5Tequal(mtype, H5T_STD_U64LE) || H5Tequal(mtype, H5T_STD_U64BE) || H5Tequal(mtype, H5T_NATIVE_ULLONG)) mdataStrings = readHDF5Data2D(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, cols, lines, dummy); else if (H5Tequal(mtype, H5T_IEEE_F32LE) || H5Tequal(mtype, H5T_IEEE_F32BE)) mdataStrings = readHDF5Data2D(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, cols, lines, dummy); else if (H5Tequal(mtype, H5T_IEEE_F64LE) || H5Tequal(mtype, H5T_IEEE_F64BE)) mdataStrings = readHDF5Data2D(dataset, H5Tget_native_type(ctype, H5T_DIR_DEFAULT), rows, cols, lines, dummy); else if (H5Tequal(mtype, H5T_NATIVE_LDOUBLE)) mdataStrings = readHDF5Data2D(dataset, ctype, rows, cols, lines, dummy); else { for (int i = 0; i < qMin(rows, lines); ++i) { QStringList lineString; for (int j = 0; j < cols; ++j) lineString << QLatin1String("_"); mdataStrings << lineString; } #ifndef NDEBUG H5T_class_t mclass = H5Tget_member_class(tid, m); #endif DEBUG("unsupported class " << translateHDF5Class(mclass).toStdString()); } m_status = H5Tclose(ctype); handleError(m_status, "H5Tclose"); for (int i = 0; i < qMin(rows, lines); i++) { for (int j = 0; j < cols; j++) { dataStrings[i][j] += mdataStrings[i][j]; if (m < members-1) dataStrings[i][j] += QLatin1String(","); } } } for (int i = 0; i < qMin(rows, lines); ++i) { for (int j = 0; j < cols; ++j) dataStrings[i][j] += QLatin1String(")"); } QDEBUG("dataStrings =" << dataStrings); return dataStrings; } QStringList HDF5FilterPrivate::readHDF5Attr(hid_t aid) { QStringList attr; char name[MAXNAMELENGTH]; m_status = H5Aget_name(aid, MAXNAMELENGTH, name); handleError(m_status, "H5Aget_name"); attr << QString(name); // DEBUG(" name =" << QString(name)); hid_t aspace = H5Aget_space(aid); // the dimensions of the attribute data handleError((int)aspace, "H5Aget_space"); hid_t atype = H5Aget_type(aid); handleError((int)atype, "H5Aget_type"); hid_t aclass = H5Tget_class(atype); handleError((int)aclass, "H5Aget_class"); if (aclass == H5T_STRING) { char buf[MAXSTRINGLENGTH]; // buffer to read attr value hid_t amem = H5Tget_native_type(atype, H5T_DIR_ASCEND); handleError((int)amem, "H5Tget_native_type"); m_status = H5Aread(aid, amem, buf); handleError(m_status, "H5Aread"); attr << QLatin1String("=") << QString(buf); m_status = H5Tclose(amem); handleError(m_status, "H5Tclose"); } else if (aclass == H5T_INTEGER) { if (H5Tequal(atype, H5T_STD_I8LE)) { qint8 value; m_status = H5Aread(aid, H5T_STD_I8LE, &value); handleError(m_status, "H5Aread"); attr << QLatin1String("=") << QString::number(value); } else if (H5Tequal(atype, H5T_STD_I8BE)) { qint8 value; m_status = H5Aread(aid, H5T_STD_I8BE, &value); handleError(m_status, "H5Aread"); attr << QLatin1String("=") << QString::number(value); } else if (H5Tequal(atype, H5T_NATIVE_CHAR)) { switch (sizeof(H5T_NATIVE_CHAR)) { case 1: { qint8 value; m_status = H5Aread(aid, H5T_NATIVE_CHAR, &value); handleError(m_status, "H5Aread"); attr << QLatin1String("=") << QString::number(value); break; } case 2: { qint16 value; m_status = H5Aread(aid, H5T_NATIVE_CHAR, &value); handleError(m_status, "H5Aread"); attr << QLatin1String("=") << QString::number(value); break; } case 4: { qint32 value; m_status = H5Aread(aid, H5T_NATIVE_CHAR, &value); handleError(m_status, "H5Aread"); attr << QLatin1String("=") << QString::number(value); break; } case 8: { qint64 value; m_status = H5Aread(aid, H5T_NATIVE_CHAR, &value); handleError(m_status, "H5Aread"); attr << QLatin1String("=") << QString::number(value); break; } default: DEBUG("unknown size " << sizeof(H5T_NATIVE_CHAR) << " of H5T_NATIVE_CHAR"); return QStringList(QString()); } } else if (H5Tequal(atype, H5T_STD_U8LE)) { uint8_t value; m_status = H5Aread(aid, H5T_STD_U8LE, &value); handleError(m_status, "H5Aread"); attr << QLatin1String("=") << QString::number(value); } else if (H5Tequal(atype, H5T_STD_U8BE)) { uint8_t value; m_status = H5Aread(aid, H5T_STD_U8BE, &value); handleError(m_status, "H5Aread"); attr << QLatin1String("=") << QString::number(value); } else if (H5Tequal(atype, H5T_NATIVE_UCHAR)) { switch (sizeof(H5T_NATIVE_UCHAR)) { case 1: { uint8_t value; m_status = H5Aread(aid, H5T_NATIVE_UCHAR, &value); handleError(m_status, "H5Aread"); attr << QLatin1String("=") << QString::number(value); break; } case 2: { uint16_t value; m_status = H5Aread(aid, H5T_NATIVE_UCHAR, &value); handleError(m_status, "H5Aread"); attr << QLatin1String("=") << QString::number(value); break; } case 4: { uint32_t value; m_status = H5Aread(aid, H5T_NATIVE_UCHAR, &value); handleError(m_status, "H5Aread"); attr << QLatin1String("=") << QString::number(value); break; } case 8: { uint64_t value; m_status = H5Aread(aid, H5T_NATIVE_UCHAR, &value); handleError(m_status, "H5Aread"); attr << QLatin1String("=") << QString::number(value); break; } default: DEBUG("unknown size " << sizeof(H5T_NATIVE_UCHAR) << " of H5T_NATIVE_UCHAR"); return QStringList(QString()); } } else if (H5Tequal(atype, H5T_STD_I16LE) || H5Tequal(atype, H5T_STD_I16BE) || H5Tequal(atype, H5T_NATIVE_SHORT)) { short value; m_status = H5Aread(aid, H5T_NATIVE_SHORT, &value); handleError(m_status, "H5Aread"); attr << QLatin1String("=") << QString::number(value); } else if (H5Tequal(atype, H5T_STD_U16LE) || H5Tequal(atype, H5T_STD_U16BE) || H5Tequal(atype, H5T_NATIVE_USHORT)) { unsigned short value; m_status = H5Aread(aid, H5T_NATIVE_USHORT, &value); handleError(m_status, "H5Aread"); attr << QLatin1String("=") << QString::number(value); } else if (H5Tequal(atype, H5T_STD_I32LE) || H5Tequal(atype, H5T_STD_I32BE) || H5Tequal(atype, H5T_NATIVE_INT)) { int value; m_status = H5Aread(aid, H5T_NATIVE_INT, &value); handleError(m_status, "H5Aread"); attr << QLatin1String("=") << QString::number(value); } else if (H5Tequal(atype, H5T_STD_U32LE) || H5Tequal(atype, H5T_STD_U32BE) || H5Tequal(atype, H5T_NATIVE_UINT)) { unsigned int value; m_status = H5Aread(aid, H5T_NATIVE_UINT, &value); handleError(m_status, "H5Aread"); attr << QLatin1String("=") << QString::number(value); } else if (H5Tequal(atype, H5T_NATIVE_LONG)) { long value; m_status = H5Aread(aid, H5T_NATIVE_LONG, &value); handleError(m_status, "H5Aread"); attr << QLatin1String("=") << QString::number(value); } else if (H5Tequal(atype, H5T_NATIVE_ULONG)) { unsigned long value; m_status = H5Aread(aid, H5T_NATIVE_ULONG, &value); handleError(m_status, "H5Aread"); attr << QLatin1String("=") << QString::number(value); } else if (H5Tequal(atype, H5T_STD_I64LE) || H5Tequal(atype, H5T_STD_I64BE) || H5Tequal(atype, H5T_NATIVE_LLONG)) { long long value; m_status = H5Aread(aid, H5T_NATIVE_LLONG, &value); handleError(m_status, "H5Aread"); attr << QLatin1String("=") << QString::number(value); } else if (H5Tequal(atype, H5T_STD_U64LE) || H5Tequal(atype, H5T_STD_U64BE) || H5Tequal(atype, H5T_NATIVE_ULLONG)) { unsigned long long value; m_status = H5Aread(aid, H5T_NATIVE_ULLONG, &value); handleError(m_status, "H5Aread"); attr << QLatin1String("=") << QString::number(value); } else attr<<" (unknown integer)"; } else if (aclass == H5T_FLOAT) { if (H5Tequal(atype, H5T_IEEE_F32LE) || H5Tequal(atype, H5T_IEEE_F32BE)) { float value; m_status = H5Aread(aid, H5T_NATIVE_FLOAT, &value); handleError(m_status, "H5Aread"); attr << QLatin1String("=") << QString::number(value); } else if (H5Tequal(atype, H5T_IEEE_F64LE) || H5Tequal(atype, H5T_IEEE_F64BE)) { double value; m_status = H5Aread(aid, H5T_NATIVE_DOUBLE, &value); handleError(m_status, "H5Aread"); attr << QLatin1String("=") << QString::number(value); } else if (H5Tequal(atype, H5T_NATIVE_LDOUBLE)) { long double value; m_status = H5Aread(aid, H5T_NATIVE_LDOUBLE, &value); handleError(m_status, "H5Aread"); attr << QLatin1String("=") << QString::number((double)value); } else attr<<" (unknown float)"; } m_status = H5Tclose(atype); handleError(m_status, "H5Tclose"); m_status = H5Sclose(aspace); handleError(m_status, "H5Sclose"); return attr; } QStringList HDF5FilterPrivate::scanHDF5Attrs(hid_t oid) { QStringList attrList; int numAttr = H5Aget_num_attrs(oid); handleError(numAttr, "H5Aget_num_attrs"); DEBUG("number of attr = " << numAttr); for (int i = 0; i < numAttr; ++i) { hid_t aid = H5Aopen_idx(oid, i); handleError((int)aid, "H5Aopen_idx"); attrList << readHDF5Attr(aid); if (i < numAttr-1) attrList << QLatin1String(", "); m_status = H5Aclose(aid); handleError(m_status, "H5Aclose"); } return attrList; } QStringList HDF5FilterPrivate::readHDF5DataType(hid_t tid) { H5T_class_t typeClass = H5Tget_class(tid); handleError((int)typeClass, "H5Tget_class"); QStringList typeProps; QString typeString = translateHDF5Class(typeClass); if (typeClass == H5T_INTEGER || typeClass == H5T_FLOAT) typeString = translateHDF5Type(tid); typeProps<setIcon(0, QIcon::fromTheme("accessories-calculator")); dataTypeItem->setFlags(Qt::ItemIsEnabled); parentItem->addChild(dataTypeItem); } void HDF5FilterPrivate::scanHDF5DataSet(hid_t did, char *dataSetName, QTreeWidgetItem* parentItem) { QString attr = scanHDF5Attrs(did).join(QString()); char link[MAXNAMELENGTH]; m_status = H5Iget_name(did, link, MAXNAMELENGTH); handleError(m_status, "H5Iget_name"); QStringList dataSetProps; hsize_t size = H5Dget_storage_size(did); handleError((int)size, "H5Dget_storage_size"); hid_t datatype = H5Dget_type(did); handleError((int)datatype, "H5Dget_type"); size_t typeSize = H5Tget_size(datatype); handleError((int)typeSize, "H5Dget_size"); dataSetProps << readHDF5DataType(datatype); hid_t dataspace = H5Dget_space(did); int rank = H5Sget_simple_extent_ndims(dataspace); handleError(rank, "H5Sget_simple_extent_ndims"); unsigned int rows = 1, cols = 1, regs = 1; if (rank == 1) { hsize_t dims_out[1]; m_status = H5Sget_simple_extent_dims(dataspace, dims_out, nullptr); handleError(m_status, "H5Sget_simple_extent_dims"); rows = dims_out[0]; dataSetProps << QLatin1String(", ") << QString::number(rows) << QLatin1String(" (") << QString::number(size/typeSize) << QLatin1String(")"); } else if (rank == 2) { hsize_t dims_out[2]; m_status = H5Sget_simple_extent_dims(dataspace, dims_out, nullptr); handleError(m_status, "H5Sget_simple_extent_dims"); rows = dims_out[0]; cols = dims_out[1]; dataSetProps << QLatin1String(", ") << QString::number(rows) << QLatin1String("x") << QString::number(cols) << QLatin1String(" (") << QString::number(size/typeSize) << QLatin1String(")"); } else if (rank == 3) { hsize_t dims_out[3]; m_status = H5Sget_simple_extent_dims(dataspace, dims_out, nullptr); handleError(m_status, "H5Sget_simple_extent_dims"); rows = dims_out[0]; cols = dims_out[1]; regs = dims_out[2]; dataSetProps << QLatin1String(", ") << QString::number(rows) << QLatin1String("x") << QString::number(cols) << QLatin1String("x") << QString::number(regs) << QLatin1String(" (") << QString::number(size/typeSize) << QLatin1String(")"); } else dataSetProps << QLatin1String(", ") << i18n("rank %1 not supported yet", rank); hid_t pid = H5Dget_create_plist(did); handleError((int)pid, "H5Dget_create_plist"); dataSetProps << ", " << readHDF5PropertyList(pid).join(QString()); QTreeWidgetItem* dataSetItem = new QTreeWidgetItem(QStringList()<setIcon(0, QIcon::fromTheme("x-office-spreadsheet")); for (int i = 0; i < dataSetItem->columnCount(); ++i) { if (rows > 0 && cols > 0 && regs > 0) { dataSetItem->setBackground(i, QColor(192,255,192)); dataSetItem->setForeground(i, Qt::black); dataSetItem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable); } else dataSetItem->setFlags(Qt::NoItemFlags); } parentItem->addChild(dataSetItem); } void HDF5FilterPrivate::scanHDF5Link(hid_t gid, char *linkName, QTreeWidgetItem* parentItem) { char target[MAXNAMELENGTH]; m_status = H5Gget_linkval(gid, linkName, MAXNAMELENGTH, target) ; handleError(m_status, "H5Gget_linkval"); QTreeWidgetItem* linkItem = new QTreeWidgetItem(QStringList() << QString(linkName) << i18n("symbolic link") << i18n("link to %1", QFile::decodeName(target))); linkItem->setIcon(0, QIcon::fromTheme("emblem-symbolic-link")); linkItem->setFlags(Qt::ItemIsEnabled); parentItem->addChild(linkItem); } void HDF5FilterPrivate::scanHDF5Group(hid_t gid, char *groupName, QTreeWidgetItem* parentItem) { DEBUG("HDF5FilterPrivate::scanHDF5Group()"); //check for hard link H5G_stat_t statbuf; m_status = H5Gget_objinfo(gid, ".", true, &statbuf); handleError(m_status, "H5Gget_objinfo"); if (statbuf.nlink > 1) { if (m_multiLinkList.contains(statbuf.objno[0])) { QTreeWidgetItem* objectItem = new QTreeWidgetItem(QStringList()<setIcon(0, QIcon::fromTheme("link")); objectItem->setFlags(Qt::ItemIsEnabled); parentItem->addChild(objectItem); return; } else { m_multiLinkList.append(statbuf.objno[0]); DEBUG(" group multiple links: "<setIcon(0, QIcon::fromTheme("folder")); groupItem->setFlags(Qt::ItemIsEnabled); parentItem->addChild(groupItem); hsize_t numObj; m_status = H5Gget_num_objs(gid, &numObj); handleError(m_status, "H5Gget_num_objs"); for (unsigned int i = 0; i < numObj; ++i) { char memberName[MAXNAMELENGTH]; m_status = H5Gget_objname_by_idx(gid, (hsize_t)i, memberName, (size_t)MAXNAMELENGTH ); handleError(m_status, "H5Gget_objname_by_idx"); int otype = H5Gget_objtype_by_idx(gid, (size_t)i ); handleError(otype, "H5Gget_objtype_by_idx"); switch (otype) { case H5G_LINK: { scanHDF5Link(gid, memberName, groupItem); break; } case H5G_GROUP: { hid_t grpid = H5Gopen(gid, memberName, H5P_DEFAULT); handleError((int)grpid, "H5Gopen"); scanHDF5Group(grpid, memberName, groupItem); m_status = H5Gclose(grpid); handleError(m_status, "H5Gclose"); break; } case H5G_DATASET: { hid_t dsid = H5Dopen(gid, memberName, H5P_DEFAULT); handleError((int)dsid, "H5Dopen"); scanHDF5DataSet(dsid, memberName, groupItem); m_status = H5Dclose(dsid); handleError(m_status, "H5Dclose"); break; } case H5G_TYPE: { hid_t tid = H5Topen(gid, memberName, H5P_DEFAULT); handleError((int)tid, "H5Topen"); scanHDF5DataType(tid, memberName, groupItem); m_status = H5Tclose(tid); handleError(m_status, "H5Tclose"); break; } default: QTreeWidgetItem* objectItem = new QTreeWidgetItem(QStringList() << QString(memberName) << i18n("unknown")); objectItem->setFlags(Qt::ItemIsEnabled); groupItem->addChild(objectItem); break; } } } #endif /*! parses the content of the file \c fileName and fill the tree using rootItem. */ void HDF5FilterPrivate::parse(const QString& fileName, QTreeWidgetItem* rootItem) { DEBUG("HDF5FilterPrivate::parse()"); #ifdef HAVE_HDF5 QByteArray bafileName = fileName.toLatin1(); DEBUG("fileName = " << bafileName.data()); // check file type first htri_t isHdf5 = H5Fis_hdf5(bafileName.data()); if (isHdf5 == 0) { DEBUG(bafileName.data() << " is not a HDF5 file! Giving up."); return; } if (isHdf5 < 0) { DEBUG("H5Fis_hdf5() failed on " << bafileName.data() << "! Giving up."); return; } // open file hid_t file = H5Fopen(bafileName.data(), H5F_ACC_RDONLY, H5P_DEFAULT); handleError((int)file, "H5Fopen", fileName); if (file < 0) { DEBUG("Opening file " << bafileName.data() << " failed! Giving up."); return; } char rootName[] = "/"; hid_t group = H5Gopen(file, rootName, H5P_DEFAULT); handleError((int)group, "H5Gopen", rootName); // multiLinkList.clear(); crashes scanHDF5Group(group, rootName, rootItem); m_status = H5Gclose(group); handleError(m_status, "H5Gclose", QString()); m_status = H5Fclose(file); handleError(m_status, "H5Fclose", QString()); #else DEBUG("HDF5 not available"); Q_UNUSED(fileName) Q_UNUSED(rootItem) #endif } /*! reads the content of the date set in the file \c fileName to a string (for preview) or to the data source. */ QVector HDF5FilterPrivate::readCurrentDataSet(const QString& fileName, AbstractDataSource* dataSource, bool &ok, AbstractFileFilter::ImportMode mode, int lines) { DEBUG("HDF5Filter::readCurrentDataSet()"); QVector dataStrings; if (currentDataSetName.isEmpty()) { //return QString("No data set selected").replace(' ',QChar::Nbsp); ok = false; return dataStrings << (QStringList() << i18n("No data set selected")); } DEBUG(" current data set = " << currentDataSetName.toStdString()); #ifdef HAVE_HDF5 QByteArray bafileName = fileName.toLatin1(); hid_t file = H5Fopen(bafileName.data(), H5F_ACC_RDONLY, H5P_DEFAULT); handleError((int)file, "H5Fopen", fileName); QByteArray badataSet = currentDataSetName.toLatin1(); hid_t dataset = H5Dopen2(file, badataSet.data(), H5P_DEFAULT); handleError((int)file, "H5Dopen2", currentDataSetName); // Get datatype and dataspace hid_t dtype = H5Dget_type(dataset); handleError((int)dtype, "H5Dget_type"); H5T_class_t dclass = H5Tget_class(dtype); handleError((int)dclass, "H5Dget_class"); size_t typeSize = H5Tget_size(dtype); handleError((int)(typeSize-1), "H5Dget_size"); hid_t dataspace = H5Dget_space(dataset); handleError((int)dataspace, "H5Dget_space"); int rank = H5Sget_simple_extent_ndims(dataspace); handleError(rank, "H5Dget_simple_extent_ndims"); DEBUG(" rank = " << rank); int columnOffset = 0; // offset to import data int actualRows = 0, actualCols = 0; // rows and cols to read // dataContainer is used to store the data read from the dataSource // it contains the pointers of all columns // initially there is one pointer set to nullptr // check for dataContainer[0] != nullptr to decide if dataSource can be used QVector dataContainer(1, nullptr); // rank= 0: single value, 1: vector, 2: matrix, 3: 3D data, ... switch (rank) { case 0: { // single value actualCols = 1; switch (dclass) { case H5T_STRING: { char* data = (char *) malloc(typeSize * sizeof(char)); hid_t memtype = H5Tcopy(H5T_C_S1); handleError((int)memtype, "H5Tcopy"); m_status = H5Tset_size(memtype, typeSize); handleError(m_status, "H5Tset_size"); m_status = H5Dread(dataset, memtype, H5S_ALL, H5S_ALL, H5P_DEFAULT, data); handleError(m_status, "H5Tread"); dataStrings << (QStringList() << data); free(data); break; } case H5T_INTEGER: case H5T_FLOAT: case H5T_TIME: case H5T_BITFIELD: case H5T_OPAQUE: case H5T_COMPOUND: case H5T_REFERENCE: case H5T_ENUM: case H5T_VLEN: case H5T_ARRAY: case H5T_NO_CLASS: case H5T_NCLASSES: { ok = false; dataStrings << (QStringList() << i18n("rank 0 not implemented yet for type %1", translateHDF5Class(dclass))); QDEBUG(dataStrings); } default: break; } break; } case 1: { // vector hsize_t size, maxSize; m_status = H5Sget_simple_extent_dims(dataspace, &size, &maxSize); handleError(m_status, "H5Sget_simple_extent_dims"); int rows = size; if (endRow == -1) endRow = rows; if (lines == -1) lines = endRow; actualRows = endRow - startRow + 1; actualCols = 1; #ifndef NDEBUG H5T_order_t order = H5Tget_order(dtype); handleError((int)order, "H5Sget_order"); #endif QDEBUG(translateHDF5Class(dclass) << '(' << typeSize << ')' << translateHDF5Order(order) << ", rows:" << rows << " max:" << maxSize); //TODO: support other modes QVector columnModes; columnModes.resize(actualCols); // use current data set name (without path) for column name QStringList vectorNames = {currentDataSetName.mid(currentDataSetName.lastIndexOf("/") + 1)}; QDEBUG(" vector names = " << vectorNames) if (dataSource) columnOffset = dataSource->prepareImport(dataContainer, mode, actualRows, actualCols, vectorNames, columnModes); QStringList dataString; // data saved in a list switch (dclass) { case H5T_STRING: { DEBUG("rank 1 H5T_STRING"); hid_t memtype = H5Tcopy(H5T_C_S1); handleError((int)memtype, "H5Tcopy"); char** data = (char **) malloc(rows * sizeof (char *)); if (H5Tis_variable_str(dtype)) { m_status = H5Tset_size(memtype, H5T_VARIABLE); handleError((int)memtype, "H5Tset_size"); m_status = H5Dread(dataset, memtype, H5S_ALL, H5S_ALL, H5P_DEFAULT, data); handleError(m_status, "H5Dread"); } else { data[0] = (char *) malloc(rows * typeSize * sizeof (char)); for (int i = 1; i < rows; ++i) data[i] = data[0] + i * typeSize; m_status = H5Tset_size(memtype, typeSize); handleError((int)memtype, "H5Tset_size"); m_status = H5Dread(dataset, memtype, H5S_ALL, H5S_ALL, H5P_DEFAULT, data[0]); handleError(m_status, "H5Dread"); } for (int i = startRow-1; i < qMin(endRow, lines + startRow - 1); ++i) dataString << data[i]; free(data); break; } case H5T_INTEGER: { if (H5Tequal(dtype, H5T_STD_I8LE)) dataString = readHDF5Data1D(dataset, H5T_STD_I8LE, rows, lines, dataContainer[0]); else if (H5Tequal(dtype, H5T_STD_I8BE)) dataString = readHDF5Data1D(dataset, H5T_STD_I8BE, rows, lines, dataContainer[0]); else if (H5Tequal(dtype, H5T_NATIVE_CHAR)) { switch (sizeof(H5T_NATIVE_CHAR)) { case 1: dataString = readHDF5Data1D(dataset, H5T_NATIVE_CHAR, rows, lines, dataContainer[0]); break; case 2: dataString = readHDF5Data1D(dataset, H5T_NATIVE_CHAR, rows, lines, dataContainer[0]); break; case 4: dataString = readHDF5Data1D(dataset, H5T_NATIVE_CHAR, rows, lines, dataContainer[0]); break; case 8: dataString = readHDF5Data1D(dataset, H5T_NATIVE_CHAR, rows, lines, dataContainer[0]); break; } } else if (H5Tequal(dtype, H5T_STD_U8LE)) dataString = readHDF5Data1D(dataset, H5T_STD_U8LE, rows, lines, dataContainer[0]); else if (H5Tequal(dtype, H5T_STD_U8BE)) dataString = readHDF5Data1D(dataset, H5T_STD_U8BE, rows, lines, dataContainer[0]); else if (H5Tequal(dtype, H5T_NATIVE_UCHAR)) { switch (sizeof(H5T_NATIVE_UCHAR)) { case 1: dataString = readHDF5Data1D(dataset, H5T_NATIVE_UCHAR, rows, lines, dataContainer[0]); break; case 2: dataString = readHDF5Data1D(dataset, H5T_NATIVE_UCHAR, rows, lines, dataContainer[0]); break; case 4: dataString = readHDF5Data1D(dataset, H5T_NATIVE_UCHAR, rows, lines, dataContainer[0]); break; case 8: dataString = readHDF5Data1D(dataset, H5T_NATIVE_UCHAR, rows, lines, dataContainer[0]); break; } } else if (H5Tequal(dtype, H5T_STD_I16LE) || H5Tequal(dtype, H5T_STD_I16BE) || H5Tequal(dtype, H5T_NATIVE_SHORT)) dataString = readHDF5Data1D(dataset, H5T_NATIVE_SHORT, rows, lines, dataContainer[0]); else if (H5Tequal(dtype, H5T_STD_U16LE) || H5Tequal(dtype, H5T_STD_U16BE) || H5Tequal(dtype, H5T_NATIVE_USHORT)) dataString = readHDF5Data1D(dataset, H5T_NATIVE_USHORT, rows, lines, dataContainer[0]); else if (H5Tequal(dtype, H5T_STD_I32LE) || H5Tequal(dtype, H5T_STD_I32BE) || H5Tequal(dtype, H5T_NATIVE_INT)) dataString = readHDF5Data1D(dataset, H5T_NATIVE_INT, rows, lines, dataContainer[0]); else if (H5Tequal(dtype, H5T_STD_U32LE) || H5Tequal(dtype, H5T_STD_U32BE) || H5Tequal(dtype, H5T_NATIVE_UINT)) dataString = readHDF5Data1D(dataset, H5T_NATIVE_UINT, rows, lines, dataContainer[0]); else if (H5Tequal(dtype, H5T_NATIVE_LONG)) dataString = readHDF5Data1D(dataset, H5T_NATIVE_LONG, rows, lines, dataContainer[0]); else if (H5Tequal(dtype, H5T_NATIVE_ULONG)) dataString = readHDF5Data1D(dataset, H5T_NATIVE_ULONG, rows, lines, dataContainer[0]); else if (H5Tequal(dtype, H5T_STD_I64LE) || H5Tequal(dtype, H5T_STD_I64BE) || H5Tequal(dtype, H5T_NATIVE_LLONG)) dataString = readHDF5Data1D(dataset, H5T_NATIVE_LLONG, rows, lines, dataContainer[0]); else if (H5Tequal(dtype, H5T_STD_U64LE) || H5Tequal(dtype, H5T_STD_U64BE) || H5Tequal(dtype, H5T_NATIVE_ULLONG)) dataString = readHDF5Data1D(dataset, H5T_NATIVE_ULLONG, rows, lines, dataContainer[0]); else { ok = false; dataString = (QStringList() << i18n("unsupported integer type for rank 1")); QDEBUG(dataString); } break; } case H5T_FLOAT: { if (H5Tequal(dtype, H5T_IEEE_F32LE) || H5Tequal(dtype, H5T_IEEE_F32BE)) dataString = readHDF5Data1D(dataset, H5T_NATIVE_FLOAT, rows, lines, dataContainer[0]); else if (H5Tequal(dtype, H5T_IEEE_F64LE) || H5Tequal(dtype, H5T_IEEE_F64BE)) dataString = readHDF5Data1D(dataset, H5T_NATIVE_DOUBLE, rows, lines, dataContainer[0]); else if (H5Tequal(dtype, H5T_NATIVE_LDOUBLE)) dataString = readHDF5Data1D(dataset, H5T_NATIVE_LDOUBLE, rows, lines, dataContainer[0]); else { ok = false; dataString = (QStringList() << i18n("unsupported float type for rank 1")); QDEBUG(dataString); } break; } case H5T_COMPOUND: { int members = H5Tget_nmembers(dtype); handleError(members, "H5Tget_nmembers"); if (dataSource) { // re-create data pointer dataContainer.clear(); dataSource->prepareImport(dataContainer, mode, actualRows, members, vectorNames, columnModes); } else dataStrings << readHDF5Compound(dtype); dataString = readHDF5CompoundData1D(dataset, dtype, rows, lines, dataContainer); break; } case H5T_TIME: case H5T_BITFIELD: case H5T_OPAQUE: case H5T_REFERENCE: case H5T_ENUM: case H5T_VLEN: case H5T_ARRAY: case H5T_NO_CLASS: case H5T_NCLASSES: { ok = false; dataString = (QStringList() << i18n("rank 1 not implemented yet for type %1", translateHDF5Class(dclass))); QDEBUG(dataString); } default: break; } if (!dataSource) { // preview QDEBUG("dataString =" << dataString); DEBUG(" data string size = " << dataString.size()); DEBUG(" rows = " << rows << ", lines = " << lines << ", actual rows = " << actualRows); for (int i = 0; i < qMin(actualRows, lines); ++i) dataStrings << (QStringList() << dataString[i]); } break; } case 2: { // matrix hsize_t dims_out[2]; m_status = H5Sget_simple_extent_dims(dataspace, dims_out, nullptr); handleError(m_status, "H5Sget_simple_extent_dims"); int rows = dims_out[0]; int cols = dims_out[1]; if (endRow == -1) endRow = rows; if (lines == -1) lines = endRow; if (endColumn == -1) endColumn = cols; actualRows = endRow-startRow+1; actualCols = endColumn-startColumn+1; #ifndef NDEBUG H5T_order_t order = H5Tget_order(dtype); handleError((int)order, "H5Tget_order"); #endif QDEBUG(translateHDF5Class(dclass) << '(' << typeSize << ')' << translateHDF5Order(order) << "," << rows << "x" << cols); DEBUG("startRow/endRow" << startRow << endRow); DEBUG("startColumn/endColumn" << startColumn << endColumn); DEBUG("actual rows/cols" << actualRows << actualCols); DEBUG("lines" << lines); //TODO: support other modes QVector columnModes; columnModes.resize(actualCols); // use current data set name (without path) append by "_" and column number for column names QStringList vectorNames; QString colName = currentDataSetName.mid(currentDataSetName.lastIndexOf("/") + 1); for (int i = 0; i < actualCols; i++) vectorNames << colName + QLatin1String("_") + QString::number(i + 1); QDEBUG(" vector names = " << vectorNames) if (dataSource) columnOffset = dataSource->prepareImport(dataContainer, mode, actualRows, actualCols, vectorNames, columnModes); // read data switch (dclass) { case H5T_INTEGER: { if (H5Tequal(dtype, H5T_STD_I8LE)) dataStrings << readHDF5Data2D(dataset, H5T_STD_I8LE, rows, cols, lines, dataContainer); else if (H5Tequal(dtype, H5T_STD_I8BE)) dataStrings << readHDF5Data2D(dataset, H5T_STD_I8BE, rows, cols, lines, dataContainer); else if (H5Tequal(dtype, H5T_NATIVE_CHAR)) { switch (sizeof(H5T_NATIVE_CHAR)) { case 1: dataStrings << readHDF5Data2D(dataset, H5T_NATIVE_CHAR, rows, cols, lines, dataContainer); break; case 2: dataStrings << readHDF5Data2D(dataset, H5T_NATIVE_CHAR, rows, cols, lines, dataContainer); break; case 4: dataStrings << readHDF5Data2D(dataset, H5T_NATIVE_CHAR, rows, cols, lines, dataContainer); break; case 8: dataStrings << readHDF5Data2D(dataset, H5T_NATIVE_CHAR, rows, cols, lines, dataContainer); break; } } else if (H5Tequal(dtype, H5T_STD_U8LE)) dataStrings << readHDF5Data2D(dataset, H5T_STD_U8LE, rows, cols, lines, dataContainer); else if (H5Tequal(dtype, H5T_STD_U8BE)) dataStrings << readHDF5Data2D(dataset, H5T_STD_U8BE, rows, cols, lines, dataContainer); else if (H5Tequal(dtype, H5T_NATIVE_UCHAR)) { switch (sizeof(H5T_NATIVE_UCHAR)) { case 1: dataStrings << readHDF5Data2D(dataset, H5T_NATIVE_UCHAR, rows, cols, lines, dataContainer); break; case 2: dataStrings << readHDF5Data2D(dataset, H5T_NATIVE_UCHAR, rows, cols, lines, dataContainer); break; case 4: dataStrings << readHDF5Data2D(dataset, H5T_NATIVE_UCHAR, rows, cols, lines, dataContainer); break; case 8: dataStrings << readHDF5Data2D(dataset, H5T_NATIVE_UCHAR, rows, cols, lines, dataContainer); break; } } else if (H5Tequal(dtype, H5T_STD_I16LE) || H5Tequal(dtype, H5T_STD_I16BE) || H5Tequal(dtype, H5T_NATIVE_SHORT)) dataStrings << readHDF5Data2D(dataset, H5T_NATIVE_SHORT, rows, cols, lines, dataContainer); else if (H5Tequal(dtype, H5T_STD_U16LE) || H5Tequal(dtype, H5T_STD_U16BE) || H5Tequal(dtype, H5T_NATIVE_USHORT)) dataStrings << readHDF5Data2D(dataset, H5T_NATIVE_USHORT, rows, cols, lines, dataContainer); else if (H5Tequal(dtype, H5T_STD_I32LE) || H5Tequal(dtype, H5T_STD_I32BE) || H5Tequal(dtype, H5T_NATIVE_INT)) dataStrings << readHDF5Data2D(dataset, H5T_NATIVE_INT, rows, cols, lines, dataContainer); else if (H5Tequal(dtype, H5T_STD_U32LE) || H5Tequal(dtype, H5T_STD_U32BE) || H5Tequal(dtype, H5T_NATIVE_UINT)) dataStrings << readHDF5Data2D(dataset, H5T_NATIVE_UINT, rows, cols, lines, dataContainer); else if (H5Tequal(dtype, H5T_NATIVE_LONG)) dataStrings << readHDF5Data2D(dataset, H5T_NATIVE_LONG, rows, cols, lines, dataContainer); else if (H5Tequal(dtype, H5T_NATIVE_ULONG)) dataStrings << readHDF5Data2D(dataset, H5T_NATIVE_ULONG, rows, cols, lines, dataContainer); else if (H5Tequal(dtype, H5T_STD_I64LE) || H5Tequal(dtype, H5T_STD_I64BE) || H5Tequal(dtype, H5T_NATIVE_LLONG)) dataStrings << readHDF5Data2D(dataset, H5T_NATIVE_LLONG, rows, cols, lines, dataContainer); else if (H5Tequal(dtype, H5T_STD_U64LE) || H5Tequal(dtype, H5T_STD_U64BE) || H5Tequal(dtype, H5T_NATIVE_ULLONG)) dataStrings << readHDF5Data2D(dataset, H5T_NATIVE_ULLONG, rows, cols, lines, dataContainer); else { ok = false; dataStrings << (QStringList() << i18n("unsupported integer type for rank 2")); QDEBUG(dataStrings); } break; } case H5T_FLOAT: { if (H5Tequal(dtype, H5T_IEEE_F32LE) || H5Tequal(dtype, H5T_IEEE_F32BE)) dataStrings << readHDF5Data2D(dataset, H5T_NATIVE_FLOAT, rows, cols, lines, dataContainer); else if (H5Tequal(dtype, H5T_IEEE_F64LE) || H5Tequal(dtype, H5T_IEEE_F64BE)) dataStrings << readHDF5Data2D(dataset, H5T_NATIVE_DOUBLE, rows, cols, lines, dataContainer); else if (H5Tequal(dtype, H5T_NATIVE_LDOUBLE)) dataStrings << readHDF5Data2D(dataset, H5T_NATIVE_LDOUBLE, rows, cols, lines, dataContainer); else { ok = false; dataStrings << (QStringList() << i18n("unsupported float type for rank 2")); QDEBUG(dataStrings); } break; } case H5T_COMPOUND: { dataStrings << readHDF5Compound(dtype); QDEBUG(dataStrings); dataStrings << readHDF5CompoundData2D(dataset,dtype,rows,cols,lines); break; } case H5T_STRING: { // TODO: implement this ok = false; dataStrings << (QStringList() << i18n("rank 2 not implemented yet for type %1, size = %2", translateHDF5Class(dclass), typeSize)); QDEBUG(dataStrings); break; } case H5T_TIME: case H5T_BITFIELD: case H5T_OPAQUE: case H5T_REFERENCE: case H5T_ENUM: case H5T_VLEN: case H5T_ARRAY: case H5T_NO_CLASS: case H5T_NCLASSES: { ok = false; dataStrings << (QStringList() << i18n("rank 2 not implemented yet for type %1", translateHDF5Class(dclass))); QDEBUG(dataStrings); } default: break; } break; } default: { // 3D or more data ok = false; dataStrings << (QStringList() << i18n("rank %1 not implemented yet for type %2", rank, translateHDF5Class(dclass))); QDEBUG(dataStrings); } } m_status = H5Sclose(dataspace); handleError(m_status, "H5Sclose"); m_status = H5Tclose(dtype); handleError(m_status, "H5Tclose"); m_status = H5Dclose(dataset); handleError(m_status, "H5Dclose"); m_status = H5Fclose(file); handleError(m_status, "H5Fclose"); if (!dataSource) return dataStrings; dataSource->finalizeImport(columnOffset, 1, actualCols, QString(), mode); #else Q_UNUSED(fileName) Q_UNUSED(dataSource) Q_UNUSED(mode) Q_UNUSED(lines) #endif return dataStrings; } /*! reads the content of the file \c fileName to the data source \c dataSource. Uses the settings defined in the data source. */ void HDF5FilterPrivate::readDataFromFile(const QString& fileName, AbstractDataSource* dataSource, AbstractFileFilter::ImportMode mode) { DEBUG("HDF5Filter::readDataFromFile()"); if (currentDataSetName.isEmpty()) { DEBUG("WARNING: No data set selected"); return; } bool ok = true; readCurrentDataSet(fileName, dataSource, ok, mode); } /*! writes the content of \c dataSource to the file \c fileName. */ void HDF5FilterPrivate::write(const QString & fileName, AbstractDataSource* dataSource) { Q_UNUSED(fileName); Q_UNUSED(dataSource); //TODO: writing HDF5 not implemented yet } //############################################################################## //################## Serialization/Deserialization ########################### //############################################################################## /*! Saves as XML. */ void HDF5Filter::save(QXmlStreamWriter* writer) const { writer->writeStartElement("hdfFilter"); writer->writeEndElement(); } /*! Loads from XML. */ bool HDF5Filter::load(XmlStreamReader* reader) { Q_UNUSED(reader); // KLocalizedString attributeWarning = ki18n("Attribute '%1' missing or empty, default value is used"); // QXmlStreamAttributes attribs = reader->attributes(); return true; } diff --git a/src/backend/nsl/nsl_corr.c b/src/backend/nsl/nsl_corr.c index bf806fed3..8a99e6e0d 100644 --- a/src/backend/nsl/nsl_corr.c +++ b/src/backend/nsl/nsl_corr.c @@ -1,200 +1,204 @@ /*************************************************************************** File : nsl_corr.c Project : LabPlot Description : NSL discrete correlation functions -------------------------------------------------------------------- Copyright : (C) 2018 by Stefan Gerlach (stefan.gerlach@uni.kn) ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301 USA * * * ***************************************************************************/ #include "nsl_corr.h" #include "nsl_common.h" #include #include #ifdef HAVE_FFTW3 #include #endif const char* nsl_corr_type_name[] = {i18n("linear (zero-padded)"), i18n("circular")}; const char* nsl_corr_norm_name[] = {i18n("none"), i18n("biased"), i18n("unbiased"), i18n("coeff")}; int nsl_corr_correlation(double s[], size_t n, double r[], size_t m, nsl_corr_type_type type, nsl_corr_norm_type normalize, double out[]) { return nsl_corr_fft_type(s, n, r, m, type, normalize, out); } int nsl_corr_fft_type(double s[], size_t n, double r[], size_t m, nsl_corr_type_type type, nsl_corr_norm_type normalize, double out[]) { size_t i, size, N = GSL_MAX(n, m), maxlag = N - 1; if (type == nsl_corr_type_linear) size = maxlag + N; else // circular size = N; size_t oldsize = size; #ifdef HAVE_FFTW3 // already zero-pad here for FFT method and FFTW r2c size = 2*(size/2+1); #endif // zero-padded arrays double *stmp = (double*)malloc(size*sizeof(double)); if (stmp == NULL) { printf("nsl_corr_fft_type(): ERROR allocating memory for 'stmp'!\n"); return -1; } double *rtmp = (double*)malloc(size*sizeof(double)); if (rtmp == NULL) { free(stmp); printf("nsl_corr_fft_type(): ERROR allocating memory for 'rtmp'!\n"); return -1; } if (type == nsl_corr_type_linear) { for (i = 0; i < maxlag; i++) stmp[i] = 0.; for (i = 0; i < n; i++) stmp[i+maxlag] = s[i]; for (i = n+maxlag; i < size; i++) stmp[i] = 0; for (i = 0; i < m; i++) rtmp[i] = r[i]; for (i = m; i < size; i++) rtmp[i] = 0; } else { // circular for (i = 0; i < n; i++) stmp[i] = s[i]; for (i = n; i < N; i++) stmp[i] = 0.; for (i = 0; i < m; i++) rtmp[i] = r[i]; for (i = m; i < N; i++) rtmp[i] = 0.; } int status; #ifdef HAVE_FFTW3 // already wraps output status = nsl_corr_fft_FFTW(stmp, rtmp, oldsize, out); #else // GSL status = nsl_corr_fft_GSL(stmp, rtmp, size, out); #endif free(stmp); free(rtmp); /* normalization */ switch (normalize) { case nsl_corr_norm_none: break; case nsl_corr_norm_biased: for (i = 0; i < oldsize; i++) out[i] = out[i]/N; break; case nsl_corr_norm_unbiased: for (i = 0; i < oldsize; i++) { size_t norm = i < oldsize/2 ? i+1 : oldsize - i; out[i] = out[i]/norm; } break; case nsl_corr_norm_coeff: { double snorm = cblas_dnrm2((int)n, s, 1); double rnorm = cblas_dnrm2((int)m, r, 1); for (i = 0; i < oldsize; i++) out[i] = out[i]/snorm/rnorm; break; } } // reverse array for circular type if (type == nsl_corr_type_circular) { for (i = 0; i < N/2; i++) { double tmp = out[i]; out[i] = out[N - i - 1]; out[N -i - 1] = tmp; } } return status; } #ifdef HAVE_FFTW3 int nsl_corr_fft_FFTW(double s[], double r[], size_t n, double out[]) { size_t i; + + if (n == 0) + return -1; + const size_t size = 2*(n/2+1); double* in = (double*)malloc(size*sizeof(double)); fftw_plan rpf = fftw_plan_dft_r2c_1d(n, in, (fftw_complex*)in, FFTW_ESTIMATE); fftw_execute_dft_r2c(rpf, s, (fftw_complex*)s); fftw_execute_dft_r2c(rpf, r, (fftw_complex*)r); fftw_destroy_plan(rpf); // multiply for (i = 0; i < size; i += 2) { double re = s[i]*r[i] + s[i+1]*r[i+1]; double im = s[i+1]*r[i] - s[i]*r[i+1]; s[i] = re; s[i+1] = im; } // back transform double* o = (double*)malloc(size*sizeof(double)); fftw_plan rpb = fftw_plan_dft_c2r_1d(n, (fftw_complex*)o, o, FFTW_ESTIMATE); fftw_execute_dft_c2r(rpb, (fftw_complex*)s, s); fftw_destroy_plan(rpb); for (i = 0; i < n; i++) out[i] = s[i]/n; return 0; } #endif int nsl_corr_fft_GSL(double s[], double r[], size_t n, double out[]) { gsl_fft_real_workspace *work = gsl_fft_real_workspace_alloc(n); gsl_fft_real_wavetable *real = gsl_fft_real_wavetable_alloc(n); /* FFT s and r */ gsl_fft_real_transform(s, 1, n, real, work); gsl_fft_real_transform(r, 1, n, real, work); gsl_fft_real_wavetable_free(real); size_t i; /* calculate halfcomplex product */ out[0] = s[0]*r[0]; for (i = 1; i < n; i++) { if (i%2) { /* Re */ out[i] = s[i]*r[i]; if (i < n-1) /* when n is even last value is real */ out[i] += s[i+1]*r[i+1]; } else /* Im */ out[i] = s[i]*r[i-1] - s[i-1]*r[i]; } /* back transform */ gsl_fft_halfcomplex_wavetable *hc = gsl_fft_halfcomplex_wavetable_alloc(n); gsl_fft_halfcomplex_inverse(out, 1, n, hc, work); gsl_fft_halfcomplex_wavetable_free(hc); gsl_fft_real_workspace_free(work); return 0; } diff --git a/src/kdefrontend/spreadsheet/DropValuesDialog.cpp b/src/kdefrontend/spreadsheet/DropValuesDialog.cpp index cdc7cf1bf..67d015df4 100644 --- a/src/kdefrontend/spreadsheet/DropValuesDialog.cpp +++ b/src/kdefrontend/spreadsheet/DropValuesDialog.cpp @@ -1,347 +1,348 @@ /*************************************************************************** File : DropValuesDialog.cpp Project : LabPlot Description : Dialog for droping and masking values in columns -------------------------------------------------------------------- Copyright : (C) 2015 by Alexander Semke (alexander.semke@web.de) ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301 USA * * * ***************************************************************************/ #include "DropValuesDialog.h" #include "backend/core/column/Column.h" #include "backend/lib/macros.h" #include "backend/spreadsheet/Spreadsheet.h" #include #include #include #include #include /*! \class DropValuesDialog \brief Dialog for generating values from a mathematical function. \ingroup kdefrontend */ DropValuesDialog::DropValuesDialog(Spreadsheet* s, bool mask, QWidget* parent) : QDialog(parent), m_spreadsheet(s), m_mask(mask) { setWindowTitle(i18nc("@title:window", "Drop Values")); ui.setupUi(this); setAttribute(Qt::WA_DeleteOnClose); ui.cbOperator->addItem(i18n("Equal to")); ui.cbOperator->addItem(i18n("Between (Including End Points)")); ui.cbOperator->addItem(i18n("Between (Excluding End Points)")); ui.cbOperator->addItem(i18n("Greater than")); ui.cbOperator->addItem(i18n("Greater than or Equal to")); ui.cbOperator->addItem(i18n("Lesser than")); ui.cbOperator->addItem(i18n("Lesser than or Equal to")); ui.leValue1->setValidator( new QDoubleValidator(ui.leValue1) ); ui.leValue2->setValidator( new QDoubleValidator(ui.leValue2) ); QDialogButtonBox* btnBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); ui.horizontalLayout->addWidget(btnBox); m_okButton = btnBox->button(QDialogButtonBox::Ok); connect(btnBox->button(QDialogButtonBox::Cancel), &QPushButton::clicked, this, &DropValuesDialog::close); if (m_mask) { m_okButton->setText(i18n("&Mask")); m_okButton->setToolTip(i18n("Mask values in the specified region")); ui.lMode->setText(i18n("Mask values")); setWindowTitle(i18nc("@title:window", "Mask Values")); } else { m_okButton->setText(i18n("&Drop")); m_okButton->setToolTip(i18n("Drop values in the specified region")); } connect(ui.cbOperator, static_cast(&QComboBox::currentIndexChanged), this, &DropValuesDialog::operatorChanged ); connect(m_okButton, &QPushButton::clicked, this, &DropValuesDialog::okClicked); connect(btnBox, &QDialogButtonBox::accepted, this, &DropValuesDialog::accept); connect(btnBox, &QDialogButtonBox::rejected, this, &DropValuesDialog::reject); resize( QSize(400,0).expandedTo(minimumSize()) ); operatorChanged(0); } void DropValuesDialog::setColumns(QVector columns) { m_columns = columns; } void DropValuesDialog::operatorChanged(int index) const { bool value2 = (index == 1) || (index == 2); ui.lMin->setVisible(value2); ui.lMax->setVisible(value2); ui.lAnd->setVisible(value2); ui.leValue2->setVisible(value2); } void DropValuesDialog::okClicked() const { if (m_mask) maskValues(); else dropValues(); } //TODO: m_column->setMasked() is slow, we need direct access to the masked-container -> redesign class MaskValuesTask : public QRunnable { public: MaskValuesTask(Column* col, int op, double value1, double value2) { m_column = col; m_operator = op; m_value1 = value1; m_value2 = value2; } void run() override { m_column->setSuppressDataChangedSignal(true); bool changed = false; auto* data = static_cast* >(m_column->data()); //equal to //TODO: use an enum if (m_operator == 0) { for (int i = 0; i < data->size(); ++i) { if (data->at(i) == m_value1) { m_column->setMasked(i, true); changed = true; } } } //between (including end points) else if (m_operator == 1) { for (int i = 0; i < data->size(); ++i) { if (data->at(i) >= m_value1 && data->at(i) <= m_value2) { m_column->setMasked(i, true); changed = true; } } } //between (excluding end points) else if (m_operator == 2) { for (int i = 0; i < data->size(); ++i) { if (data->at(i) > m_value1 && data->at(i) < m_value2) { m_column->setMasked(i, true); changed = true; } } } //greater than else if (m_operator == 3) { for (int i = 0; i < data->size(); ++i) { if (data->at(i) > m_value1) { m_column->setMasked(i, true); changed = true; } } } //greater than or equal to else if (m_operator == 4) { for (int i = 0; i < data->size(); ++i) { if (data->at(i) >= m_value1) { m_column->setMasked(i, true); changed = true; } } } //lesser than else if (m_operator == 5) { for (int i = 0; i < data->size(); ++i) { if (data->at(i) < m_value1) { m_column->setMasked(i, true); changed = true; } } } //lesser than or equal to else if (m_operator == 6) { for (int i = 0; i < data->size(); ++i) { if (data->at(i) <= m_value1) { m_column->setMasked(i, true); changed = true; } } } m_column->setSuppressDataChangedSignal(false); if (changed) m_column->setChanged(); } private: Column* m_column; int m_operator; double m_value1; double m_value2; }; class DropValuesTask : public QRunnable { public: DropValuesTask(Column* col, int op, double value1, double value2) { m_column = col; m_operator = op; m_value1 = value1; m_value2 = value2; } void run() override { bool changed = false; auto* data = static_cast* >(m_column->data()); QVector new_data(*data); //equal to if (m_operator == 0) { for (auto& d : new_data) { if (d == m_value1) { d = NAN; changed = true; } } } //between (including end points) else if (m_operator == 1) { for (auto& d : new_data) { if (d >= m_value1 && d <= m_value2) { d = NAN; changed = true; } } } //between (excluding end points) else if (m_operator == 2) { for (auto& d : new_data) { if (d > m_value1 && d < m_value2) { d = NAN; changed = true; } } } //greater than else if (m_operator == 3) { for (auto& d : new_data) { if (d > m_value1) { d = NAN; changed = true; } } } //greater than or equal to else if (m_operator == 4) { for (auto& d : new_data) { if (d >= m_value1) { d = NAN; changed = true; } } } //less than else if (m_operator == 5) { for (auto& d : new_data) { if (d < m_value1) { d = NAN; changed = true; } } } //less than or equal to else if (m_operator == 6) { for (auto& d : new_data) { if (d <= m_value1) { d = NAN; changed = true; } } } if (changed) m_column->replaceValues(0, new_data); } private: Column* m_column; int m_operator; double m_value1; double m_value2; }; void DropValuesDialog::maskValues() const { Q_ASSERT(m_spreadsheet); WAIT_CURSOR; m_spreadsheet->beginMacro(i18n("%1: mask values", m_spreadsheet->name())); const int op = ui.cbOperator->currentIndex(); const double value1 = ui.leValue1->text().toDouble(); const double value2 = ui.leValue2->text().toDouble(); for (Column* col: m_columns) { auto* task = new MaskValuesTask(col, op, value1, value2); task->run(); //TODO: writing to the undo-stack in Column::setMasked() is not tread-safe -> redesign // QThreadPool::globalInstance()->start(task); + delete task; } //wait until all columns were processed // QThreadPool::globalInstance()->waitForDone(); m_spreadsheet->endMacro(); RESET_CURSOR; } void DropValuesDialog::dropValues() const { Q_ASSERT(m_spreadsheet); WAIT_CURSOR; m_spreadsheet->beginMacro(i18n("%1: drop values", m_spreadsheet->name())); const int op = ui.cbOperator->currentIndex(); const double value1 = ui.leValue1->text().toDouble(); const double value2 = ui.leValue2->text().toDouble(); for (Column* col: m_columns) { auto* task = new DropValuesTask(col, op, value1, value2); QThreadPool::globalInstance()->start(task); } //wait until all columns were processed QThreadPool::globalInstance()->waitForDone(); m_spreadsheet->endMacro(); RESET_CURSOR; } diff --git a/src/kdefrontend/widgets/ThemesWidget.cpp b/src/kdefrontend/widgets/ThemesWidget.cpp index e8b5b56a8..5c70f860c 100644 --- a/src/kdefrontend/widgets/ThemesWidget.cpp +++ b/src/kdefrontend/widgets/ThemesWidget.cpp @@ -1,144 +1,146 @@ /*************************************************************************** File : ThemesWidget.cpp Project : LabPlot Description : widget for selecting themes -------------------------------------------------------------------- Copyright : (C) 2016 Prakriti Bhardwaj (p_bhardwaj14@informatik.uni-kl.de) Copyright : (C) 2016 Alexander Semke (alexander.semke@web.de) ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301 USA * * * ***************************************************************************/ #include "ThemesWidget.h" #include "kdefrontend/ThemeHandler.h" #include #include #include #include #include #include #include #include #include // #include /*! \class ThemesWidget \brief Widget for showing theme previews and for selecting a theme. \ingroup kdefrontend */ ThemesWidget::ThemesWidget(QWidget* parent) : QListView(parent) { setSelectionMode(QAbstractItemView::SingleSelection); setWordWrap(true); setViewMode(QListWidget::IconMode); setResizeMode(QListWidget::Fixed); setDragDropMode(QListView::NoDragDrop); //make the icon 3x3cm big and show two of them in the height int size = 3.0/2.54 * QApplication::desktop()->physicalDpiX(); setIconSize(QSize(size, size)); setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); //show preview pixmaps auto* mContentItemModel = new QStandardItemModel(this); QStringList themeList = ThemeHandler::themes(); QStringList themeImgPathList = QStandardPaths::locateAll(QStandardPaths::DataLocation, "themes/screenshots/", QStandardPaths::LocateDirectory); - if (themeImgPathList.isEmpty()) + if (themeImgPathList.isEmpty()) { + delete mContentItemModel; return; + } const QString& themeImgPath = themeImgPathList.first(); QString tempPath; for (int i = 0; i < themeList.size(); ++i) { auto* listItem = new QStandardItem(); tempPath = themeImgPath + themeList.at(i) + ".png"; if (!QFile::exists(tempPath)) tempPath = themeImgPath + "Unavailable.png"; listItem->setIcon(QIcon(QPixmap(tempPath))); listItem->setText(themeList.at(i)); mContentItemModel->appendRow(listItem); } //create and add the icon for "None" QPixmap pm(size, size); QPen pen(Qt::SolidPattern, 1); const QColor& color = (palette().color(QPalette::Base).lightness() < 128) ? Qt::white : Qt::black; pen.setColor(color); QPainter pa; pm.fill(Qt::transparent); pa.begin(&pm); pa.setPen(pen); pa.drawRect(2, 2, size - 4, size - 4); pa.end(); auto* listItem = new QStandardItem(); listItem->setIcon(pm); listItem->setText(i18n("None")); mContentItemModel->appendRow(listItem); //adding download themes option //TODO: activate this later // QStandardItem* listItem = new QStandardItem(); // listItem->setIcon(QIcon::fromTheme("get-hot-new-stuff")); // listItem->setText("Download Themes"); // listItem->setData("file_download_theme", Qt::UserRole); // mContentItemModel->appendRow(listItem); QListView::setModel(mContentItemModel); //resize the widget to show three items QFont font; QFontMetrics fm(font); QSize widgetSize(size + qApp->style()->pixelMetric(QStyle::PM_ScrollBarExtent), 3*(size + fm.height() + spacing()) + fm.height()); setMinimumSize(widgetSize); setMaximumSize(widgetSize); //SLOTS connect(this, &ThemesWidget::clicked, this, &ThemesWidget::applyClicked); } void ThemesWidget::applyClicked(const QModelIndex& index) { const QString& themeName = index.data(Qt::DisplayRole).toString(); //TODO: activate this later // if (themeName == "file_download_theme") // this->downloadThemes(); // else if (index.row() == model()->rowCount()-1) emit themeSelected(QString()); //item with the string "None" was selected -> no theme else emit themeSelected(themeName); } //TODO: activate this later // void ThemesWidget::downloadThemes() { // KNS3::DownloadDialog dialog("labplot2_themes.knsrc", this); // dialog.exec(); // foreach (const KNS3::Entry& e, dialog.changedEntries()) { // kDebug() << "Changed Entry: " << e.name(); // } // }