diff --git a/Graphs/gFlagsLine.h b/Graphs/gFlagsLine.h index 4511adba..740a698d 100644 --- a/Graphs/gFlagsLine.h +++ b/Graphs/gFlagsLine.h @@ -11,18 +11,37 @@ class gFlagsGroup; +/*! \class gFlagsLine + \brief One single line of event flags in the Event Flags chart + */ class gFlagsLine:public Layer { friend class gFlagsGroup; public: + /*! \brief Constructs an individual gFlagsLine object + \param code The Channel the data is sourced from + \param col The colour to draw this flag + \param label The label to show to the left of the Flags line. + \param always_visible Whether to always show this line, even if empty + \param Type of Flag, either FT_Bar, or FT_Span + */ gFlagsLine(ChannelID code,QColor col=Qt::black,QString label="",bool always_visible=false,FlagType flt=FT_Bar); virtual ~gFlagsLine(); + //! \brief Drawing code to add the flags and span markers to the Vertex buffers. virtual void paint(gGraph & w,int left, int top, int width, int height); + + //! \brief Returns true if should always show this flag, even if it's empty bool isAlwaysVisible() { return m_always_visible; } + //! \brief Set this to true to make a flag line always visible void setAlwaysVisible(bool b) { m_always_visible=b; } + + //! \brief Returns the label for this individual Event Flags line QString label() { return m_label; } + + //! \brief Sets the label for this individual Event Flags line void setLabel(QString s) { m_label=s; } + void setTotalLines(int i) { total_lines=i; } void setLineNum(int i) { line_num=i; } protected: @@ -35,19 +54,36 @@ class gFlagsLine:public Layer int m_lx, m_ly; }; +/*! \class gFlagsGroup + \brief Contains multiple gFlagsLine entries for the Events Flag graph + */ class gFlagsGroup:public LayerGroup { public: gFlagsGroup(); virtual ~gFlagsGroup(); + //! Draw filled rectangles behind Event Flag's, and an outlines around them all, Calls the individual paint for each gFlagLine virtual void paint(gGraph & w,int left, int top, int width, int height); + + //! Returns the first time represented by all gFlagLine layers, in milliseconds since epoch virtual qint64 Minx(); + //! Returns the last time represented by all gFlagLine layers, in milliseconds since epoch. virtual qint64 Maxx(); + + //! Checks if each flag has data, and adds valid gFlagLines to the visible layers list virtual void SetDay(Day *); + + //! Returns true if none of the gFlagLine objects contain any data for this day virtual bool isEmpty() { return m_empty; } + + //! Returns the count of visible flag line entries int count() { return lvisible.size(); } + + //! Returns the height in pixels of each bar int barHeight() { return m_barh; } + + //! Returns a list of Visible gFlagsLine layers to draw QVector & visibleLayers() { return lvisible; } protected: diff --git a/Graphs/gFooBar.h b/Graphs/gFooBar.h index ffca9f07..55eaae98 100644 --- a/Graphs/gFooBar.h +++ b/Graphs/gFooBar.h @@ -9,6 +9,9 @@ #include "gGraphView.h" +/*! \class gShadowArea + \brief Displays a Shadow for all graph areas not highlighted (used in Event Flags) + */ class gShadowArea:public Layer { public: @@ -22,6 +25,10 @@ class gShadowArea:public Layer GLShortBuffer *lines; }; +/*! \class gFooBar + \brief Was a kind of scrollbar thingy that used to be used for representing the overall graph areas. + Currently Unused and empty. + */ class gFooBar:public Layer { public: diff --git a/Graphs/gGraphView.h b/Graphs/gGraphView.h index 35ab5d6f..4a9056de 100644 --- a/Graphs/gGraphView.h +++ b/Graphs/gGraphView.h @@ -253,7 +253,7 @@ public: //! \brief Draw all this layers custom GLBuffers (ie. the actual OpenGL Vertices) virtual void drawGLBuf(float linesize); - //! \note not sure why I needed the reference counting stuff. + //! \brief not sure why I needed the reference counting stuff. short m_refcount; void addref() { m_refcount++; } bool unref() { m_refcount--; if (m_refcount<=0) return true; return false; } @@ -439,7 +439,7 @@ public: //! \brief Set the height element. (relative to the total of all heights) void setHeight(float height) { m_height=height; } - // Can't remember what these are for.. + //! \brief Can't remember what these are for.. int minHeight() { return m_min_height; } void setMinHeight(int height) { m_min_height=height; } @@ -449,9 +449,10 @@ public: //! \brief Set whether or not to render the vertical graph title void showTitle(bool b); - //! \brief Returns printScaleX, used for DPI scaling + //! \brief Returns printScaleX, used for DPI scaling in report printing float printScaleX(); - //! \brief Returns printScaleY, used for DPI scaling.. + + //! \brief Returns printScaleY, used for DPI scaling in report printing float printScaleY(); //! \brief Returns true if none of the included layers have data attached @@ -460,6 +461,7 @@ public: //! \brief Add Layer l to graph object, allowing you to specify position, margin sizes, order, movability status and offsets void AddLayer(Layer * l,LayerPosition position=LayerCenter, short pixelsX=0, short pixelsY=0, short order=0, bool movable=false, short x=0, short y=0); + void qglColor(QColor col); //! \brief Queues text for gGraphView object to draw it. diff --git a/Graphs/gLineChart.h b/Graphs/gLineChart.h index 5696b0c3..cdda2b60 100644 --- a/Graphs/gLineChart.h +++ b/Graphs/gLineChart.h @@ -13,21 +13,41 @@ #include "gGraphView.h" //#include "graphlayer.h" +/*! \class AHIChart + \brief Another graph calculating the AHI/hour, this one looks at all the sessions for a day. Currently Unused. + */ class AHIChart:public Layer { public: + //! \brief Constructs an AHIChart object, with QColor col for the line plots. AHIChart(const QColor col=QColor("black")); ~AHIChart(); + + //! \brief Draws the precalculated data to the Vertex buffers virtual void paint(gGraph & w,int left, int top, int width, int height); + + //! \brief AHI/hr Calculations are done for this day here. + //! This also uses the sliding window method virtual void SetDay(Day *d); + + //! \brief Returns the minimum AHI/hr value caculated virtual EventDataType Miny() { return m_miny; } + + //! \brief Returns the maximum AHI/hr value caculated virtual EventDataType Maxy() { return m_maxy; } + + //! \brief Returns true if no data was available virtual bool isEmpty() { return m_data.size()==0; } protected: + //! \brief Contains the plot data (Y-axis) generated for this day QVector m_data; + + //! \brief Contains the time codes (X-axis) generated for this day QVector m_time; - EventDataType m_miny,m_maxy; + + EventDataType m_miny; + EventDataType m_maxy; QColor m_color; GLShortBuffer * lines; }; @@ -57,7 +77,7 @@ class gLineChart:public Layer bool GetSquarePlot() { return m_square_plot; } //! \brief Set this if you want this layer to draw it's empty data message - //! \note They don't show anymore due to the changes in gGraphView. Should modify isEmpty if this still gets to live + //! They don't show anymore due to the changes in gGraphView. Should modify isEmpty if this still gets to live void ReportEmpty(bool b) { m_report_empty=b; } //! \brief Returns whether or not to show the empty text message diff --git a/Graphs/gLineOverlay.h b/Graphs/gLineOverlay.h index 11e29495..af168d90 100644 --- a/Graphs/gLineOverlay.h +++ b/Graphs/gLineOverlay.h @@ -9,16 +9,27 @@ #include "gGraphView.h" +/*! \class gLineOverlayBar + \brief Shows a flag line, a dot, or a span over the top of a 2D line chart. + */ class gLineOverlayBar:public Layer { public: + //! \brief Constructs a gLineOverlayBar object of type code, setting the flag/span color, the label to show when zoomed + //! in, and the display method requested, of either FT_Bar, FT_Span, or FT_Dot gLineOverlayBar(ChannelID code,QColor col,QString _label="",FlagType _flt=FT_Bar); virtual ~gLineOverlayBar(); + //! \brief The drawing code that fills the OpenGL vertex GLBuffers virtual void paint(gGraph & w,int left, int top, int width, int height); + virtual EventDataType Miny() { return 0; } virtual EventDataType Maxy() { return 0; } + + //! \brief Returns true if no Channel data available for this code virtual bool isEmpty() { return true; } + + //! \brief returns a count of all flags drawn during render. (for gLineOverlaySummary) int count() { return m_count; } protected: QColor m_flag_color; @@ -29,6 +40,9 @@ class gLineOverlayBar:public Layer GLShortBuffer *points,*quads, *lines; }; +/*! \class gLineOverlaySummary + \brief A container class to hold a group of gLineOverlayBar's, and shows the "Section AHI" over the Flow Rate waveform. + */ class gLineOverlaySummary:public Layer { public: @@ -38,7 +52,11 @@ class gLineOverlaySummary:public Layer virtual void paint(gGraph & w,int left, int top, int width, int height); virtual EventDataType Miny() { return 0; } virtual EventDataType Maxy() { return 0; } + + //! \brief Returns true if no Channel data available for this code virtual bool isEmpty() { return true; } + + //! \brief Adds a gLineOverlayBar to this list gLineOverlayBar *add(gLineOverlayBar *bar) { m_overlays.push_back(bar); return bar; } protected: QVector m_overlays; diff --git a/Graphs/gSessionTime.cpp b/Graphs/gSessionTime.cpp deleted file mode 100644 index 92c3d1b8..00000000 --- a/Graphs/gSessionTime.cpp +++ /dev/null @@ -1,167 +0,0 @@ -/* - gSessionTime Implementation - Copyright (c)2011 Mark Watkins - License: GPL -*/ - -#include -#include -#include "gSessionTime.h" - -gTimeYAxis::gTimeYAxis(QColor col) - :gYAxis("",col) -{ -} -gTimeYAxis::~gTimeYAxis() -{ -} -const QString gTimeYAxis::Format(double v) -{ - static QString t; - int i=v; - if (i<0) i=24+i; - - - t.sprintf("%02i:00",i); - return t; -}; - - -gSessionTime::gSessionTime(ChannelID code,QColor col,Qt::Orientation o) -:Layer(code),m_orientation(o) -{ - color.clear(); - color.push_back(col); - - Xaxis=new gXAxis(); -} -gSessionTime::~gSessionTime() -{ - delete Xaxis; -} - -void gSessionTime::paint(gGraph & w,int left, int top, int width, int height) -{ - Q_UNUSED(w); - Q_UNUSED(left); - Q_UNUSED(top); - Q_UNUSED(width); - Q_UNUSED(height); - - if (!m_visible) return; - /*if (!data) return; - if (!data->IsReady()) return; - - int start_px=w.GetLeftMargin(); - int start_py=w.GetBottomMargin(); - int width=scrx-(w.GetLeftMargin()+w.GetRightMargin()); - int height=scry-(w.GetTopMargin()+w.GetBottomMargin()); - - double maxx=w.max_x; - double minx=w.min_x; - double xx=maxx - minx; - - int days=ceil(xx); - - float barwidth=float(width-days)/float(days); - qint64 dy; - //double sd; - double px1,py1;//,py2,px2; - QColor & col1=color[0]; - QColor col2("light grey"); - QString str; - bool draw_xticks_instead=false; - bool antialias=(*profile)["UseAntiAliasing"].toBool(); - - QDateTime d; - QTime t; - double start,total;//end, - float textX,textY; - map datedrawn; - - int idx=-1; - for (int i=0;inp[0];i++) { - QPointD & rp=data->point[0][i]; - if (int(rp.x()) < int(minx)) continue; - if (int(rp.x()) > int(maxx+.5)) break; - if (idx<0) idx=i; - d=QDateTime::fromTime_t(rp.x()*86400.0); - t=d.time(); - start=t.hour()+(t.minute()/60.0)+(t.second()/3600.0); - //d=QDateTime::fromTime_t(rp.y()*86400.0); - //t=d.time(); - //end=t.hour()+(t.minute()/60.0)+(t.second()/3600.0); - - total=(rp.y()-rp.x())*24; - - dy=int(rp.x())-int(minx); // day number. - if (dy>=days) continue; - if (start>=12) { - // dy++; - start-=24; - } - start+=12; - - if (start+total>24) { -// total=24-start; - } - if (total<0.25) continue; // Hide sessions less than 15 minutes - - //double sd=floor(rp.x()); - px1=dy*(barwidth+1); // x position for this day - //px2=px1+barwidth; // plus bar width - py1=height/24.0*start; - double h=height/24.0*(total); - - QRect rect(start_px+px1,start_py+py1,barwidth,h); - - glBegin(GL_QUADS); - glColor4ub(col1.red(),col1.green(),col1.blue(),col1.alpha()); - glVertex2f(rect.x(), rect.y()+rect.height()); - glVertex2f(rect.x(), rect.y()); - - glColor4ub(col2.red(),col2.green(),col2.blue(),col2.alpha()); - glVertex2f(rect.x()+rect.width(),rect.y()); - glVertex2f(rect.x()+rect.width(), rect.y()+rect.height()); - glEnd(); - - glColor4ub(0,0,0,255); - glLineWidth (1); - glBegin(GL_LINE_LOOP); - glVertex2f(rect.x(), rect.y()+rect.height()+.5); - glVertex2f(rect.x(), rect.y()); - glVertex2f(rect.x()+rect.width(),rect.y()); - glVertex2f(rect.x()+rect.width(), rect.y()+rect.height()+.5); - glEnd(); - if (!draw_xticks_instead) { - if (datedrawn.find(dy)==datedrawn.end()) { - datedrawn[dy]=true; - str=FormatX(rp.y()); - - GetTextExtent(str, textX, textY); - if (!draw_xticks_instead && (textY+6SetShowMinorTicks(false); - Xaxis->Plot(w,scrx,scry); - } - - glColor3f (0.0F, 0.0F, 0.0F); - glLineWidth(1); - glBegin (GL_LINES); - glVertex2f (start_px, start_py); - glVertex2f (start_px, start_py+height+1); - glVertex2f (start_px,start_py); - glVertex2f (start_px+width, start_py); - glEnd (); */ -} diff --git a/Graphs/gSessionTime.h b/Graphs/gSessionTime.h deleted file mode 100644 index 465cb7a3..00000000 --- a/Graphs/gSessionTime.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - gSessionTime Header - Copyright (c)2011 Mark Watkins - License: GPL -*/ - -#ifndef GSESSIONTIME_H -#define GSESSIONTIME_H - -#include "gGraphView.h" -#include "gXAxis.h" -#include "gYAxis.h" - -class gTimeYAxis:public gYAxis -{ -public: - gTimeYAxis(QColor col=QColor("black")); - virtual ~gTimeYAxis(); - virtual const QString Format(double v); -}; - - -class gSessionTime:public Layer -{ - public: - gSessionTime(ChannelID="",QColor col=QColor("blue"),Qt::Orientation o=Qt::Horizontal); - virtual ~gSessionTime(); - - virtual void paint(gGraph & w,int left,int top, int width, int height); - - protected: - Qt::Orientation m_orientation; - - virtual const QString & FormatX(double v) { static QString t; QDateTime d; d=d.fromTime_t(v*86400.0); t=d.toString("MMM dd"); return t; } - //virtual const wxString & FormatX(double v) { static wxString t; wxDateTime d; d.Set(vi*86400000.0); t=d.Format(wxT("HH:mm")); return t; }; - //virtual const wxString & FormatX(double v) { static wxString t; t=wxString::Format(wxT("%.1f"),v); return t; }; - virtual const QString & FormatY(double v) { static QString t; t.sprintf("%.1f",v); return t; } - - gXAxis *Xaxis; - QVector color; -}; - -#endif // GSESSIONTIME_H diff --git a/Graphs/gStatsLine.h b/Graphs/gStatsLine.h index 152703c3..886fb66b 100644 --- a/Graphs/gStatsLine.h +++ b/Graphs/gStatsLine.h @@ -4,6 +4,9 @@ #include "SleepLib/machine.h" #include "gGraphView.h" +/*! \class gStatsLine + \brief Show a rendered stats area in place of a graph. This is currently unused + */ class gStatsLine : public Layer { public: diff --git a/Graphs/gXAxis.h b/Graphs/gXAxis.h index 27bcd46c..be68a04f 100644 --- a/Graphs/gXAxis.h +++ b/Graphs/gXAxis.h @@ -8,6 +8,8 @@ #define GXAXIS_H #include "gGraphView.h" +/*! \class gXAxis + \brief Draws the XTicker timescales underneath graphs */ class gXAxis:public Layer { public: diff --git a/Graphs/gYAxis.cpp b/Graphs/gYAxis.cpp index f31f0884..88bf9a4c 100644 --- a/Graphs/gYAxis.cpp +++ b/Graphs/gYAxis.cpp @@ -124,8 +124,8 @@ void gXGrid::paint(gGraph & w,int left,int top, int width, int height) -gYAxis::gYAxis(ChannelID code,QColor col) -:Layer(code) +gYAxis::gYAxis(QColor col) +:Layer("") { m_line_color=col; m_text_color=col; @@ -249,7 +249,7 @@ bool gYAxis::mouseMoveEvent(QMouseEvent * event) } gYAxisTime::gYAxisTime(QColor col): - gYAxis("",col) + gYAxis(col) { show_12hr=true; } diff --git a/Graphs/gYAxis.h b/Graphs/gYAxis.h index 32c90880..201a378e 100644 --- a/Graphs/gYAxis.h +++ b/Graphs/gYAxis.h @@ -9,6 +9,10 @@ #include "gGraphView.h" + +/*! \class gYSpacer + \brief A dummy vertical spacer object + */ class gYSpacer:public Layer { public: @@ -23,16 +27,29 @@ class gYSpacer:public Layer }; +/*! \class gXGrid + \brief Draws the horizintal major/minor grids over graphs + */ class gXGrid:public Layer { public: + //! \brief Constructs an gXGrid object with default settings, and col for line colour. gXGrid(QColor col=QColor("black")); virtual ~gXGrid(); + + //! \brief Draw the horizontal lines by adding the to the Vertex GLbuffers virtual void paint(gGraph & w,int left,int top, int width, int height); + //! \brief set the visibility status of Major lines void setShowMinorLines(bool b) { m_show_minor_lines=b; } + + //! \brief set the visibility status of Minor lines void setShowMajorLines(bool b) { m_show_major_lines=b; } + + //! \brief Returns the visibility status of minor lines bool showMinorLines() { return m_show_minor_lines; } + + //! \brief Returns the visibility status of Major lines bool showMajorLines() { return m_show_major_lines; } protected: bool m_show_major_lines; @@ -41,29 +58,51 @@ protected: QColor m_minor_color; }; +/*! \class gYAxis + \brief Draws the YAxis tick markers, and numeric labels + */ class gYAxis:public Layer { public: - gYAxis(ChannelID code="",QColor col=QColor("black")); + //! \brief Construct a gYAxis object, with QColor col for tickers & text + gYAxis(QColor col=QColor("black")); virtual ~gYAxis(); - virtual void paint(gGraph & w,int left,int top, int width, int height); - void SetShowMinorLines(bool b) { m_show_minor_lines=b; } - void SetShowMajorLines(bool b) { m_show_major_lines=b; } - bool ShowMinorLines() { return m_show_minor_lines; } - bool ShowMajorLines() { return m_show_major_lines; } - void SetShowMinorTicks(bool b) { m_show_minor_ticks=b; } - void SetShowMajorTicks(bool b) { m_show_major_ticks=b; } - bool ShowMinorTicks() { return m_show_minor_ticks; } - bool ShowMajorTicks() { return m_show_major_ticks; } - virtual const QString Format(EventDataType v, int dp); - static const int Margin=60; // Left margin space - void SetScale(float f) { m_yaxis_scale=f; } // Scale yaxis ticker values (only what's displayed) + //! \brief Draw the horizontal tickers display + virtual void paint(gGraph & w,int left,int top, int width, int height); + +// void SetShowMinorLines(bool b) { m_show_minor_lines=b; } +// void SetShowMajorLines(bool b) { m_show_major_lines=b; } +// bool ShowMinorLines() { return m_show_minor_lines; } +// bool ShowMajorLines() { return m_show_major_lines; } + + //! \brief Sets the visibility status of minor ticks + void SetShowMinorTicks(bool b) { m_show_minor_ticks=b; } + + //! \brief Sets the visibility status of Major ticks + void SetShowMajorTicks(bool b) { m_show_major_ticks=b; } + + //! \brief Returns the visibility status of Minor ticks + bool ShowMinorTicks() { return m_show_minor_ticks; } + + //! \brief Returns the visibility status of Major ticks + bool ShowMajorTicks() { return m_show_major_ticks; } + + //! \brief Formats the ticker value.. Override to implement other types + virtual const QString Format(EventDataType v, int dp); + + //! \brief Left Margin space in pixels + static const int Margin=60; + + //! \brief Set the scale of the Y axis values.. Values can be multiplied by this to convert formats + void SetScale(float f) { m_yaxis_scale=f; } + + //! \brief Returns the scale of the Y axis values.. Values can be multiplied by this to convert formats float Scale() { return m_yaxis_scale; } protected: - bool m_show_major_lines; - bool m_show_minor_lines; + //bool m_show_major_lines; + //bool m_show_minor_lines; bool m_show_minor_ticks; bool m_show_major_ticks; float m_yaxis_scale; @@ -75,13 +114,20 @@ class gYAxis:public Layer }; +/*! \class gYAxisTime + \brief Draws the YAxis tick markers, and labels in time format + */ class gYAxisTime:public gYAxis { public: + //! \brief Construct a gYAxisTime object, with QColor col for tickers & times gYAxisTime(QColor col=Qt::black); virtual ~gYAxisTime(); protected: + //! \brief Overrides gYAxis Format to display Time format virtual const QString Format(EventDataType v, int dp); + + //! \brief Whether to format as 12 or 24 hour times bool show_12hr; }; diff --git a/Resources.qrc b/Resources.qrc index b34fd53e..3f784c2b 100644 --- a/Resources.qrc +++ b/Resources.qrc @@ -15,7 +15,6 @@ docs/usage.html icons/oximeter.png docs/0.0.gif - docs/template_overview.sht docs/schema.xml docs/channels.xml icons/last.png diff --git a/SleepLib/day.h b/SleepLib/day.h index c79c9475..3e465fe0 100644 --- a/SleepLib/day.h +++ b/SleepLib/day.h @@ -12,6 +12,9 @@ #include "SleepLib/event.h" #include "SleepLib/session.h" +/*! \class OneTypePerDay + \brief An Exception class to catch multiple machine records per day + */ class OneTypePerDay { }; diff --git a/SleepLib/loader_plugins/cms50_loader.h b/SleepLib/loader_plugins/cms50_loader.h index 03841163..d4d6434d 100644 --- a/SleepLib/loader_plugins/cms50_loader.h +++ b/SleepLib/loader_plugins/cms50_loader.h @@ -13,6 +13,10 @@ License: GPL const QString cms50_class_name="CMS50"; const int cms50_data_version=4; + +/*! \class CMS50Loader + \brief Bulk Importer for CMS50 SPO2Review format.. Deprecated, as the Oximetry module does a better job + */ class CMS50Loader : public MachineLoader { public: diff --git a/SleepLib/loader_plugins/intellipap_loader.h b/SleepLib/loader_plugins/intellipap_loader.h index 1015162f..85604f64 100644 --- a/SleepLib/loader_plugins/intellipap_loader.h +++ b/SleepLib/loader_plugins/intellipap_loader.h @@ -22,6 +22,9 @@ const int intellipap_data_version=1; // //******************************************************************************************** +/*! \class Intellipap + \brief Intellipap customized machine object + */ class Intellipap:public CPAP { public: @@ -35,24 +38,32 @@ const int intellipap_load_buffer_size=1024*1024; const QString intellipap_class_name="Intellipap"; +/*! \class IntellipapLoader + \brief Loader for DeVilbiss Intellipap Auto data + This is only relatively recent addition and still needs more work + */ class IntellipapLoader : public MachineLoader { public: IntellipapLoader(); virtual ~IntellipapLoader(); + //! \brief Scans path for Intellipap data signature, and Loads any new data virtual int Open(QString & path,Profile *profile); + + //! \brief Returns SleepLib database version of this IntelliPap loader virtual int Version() { return intellipap_data_version; } + + //! \brief Returns the machine class name of this IntelliPap, "Intellipap" virtual const QString & ClassName() { return intellipap_class_name; } + + //! \brief Creates a machine object, indexed by serial number Machine *CreateMachine(QString serial,Profile *profile); + + //! \brief Registers this MachineLoader with the master list, so Intellipap data can load static void Register(); protected: QString last; QHash MachList; - /*int OpenMachine(Machine *m,QString path,Profile *profile); - bool ParseProperties(Machine *m,QString filename); - bool OpenSummary(Session *session,QString filename); - bool OpenEvents(Session *session,QString filename); - bool OpenWaveforms(Session *session,QString filename);*/ unsigned char * m_buffer; }; diff --git a/SleepLib/loader_plugins/prs1_loader.cpp b/SleepLib/loader_plugins/prs1_loader.cpp index 772aba52..c180d94d 100644 --- a/SleepLib/loader_plugins/prs1_loader.cpp +++ b/SleepLib/loader_plugins/prs1_loader.cpp @@ -106,6 +106,15 @@ PRS1::~PRS1() } +/*! \struct WaveHeaderList + \brief Used in PRS1 Waveform Parsing */ +struct WaveHeaderList { + quint16 interleave; + quint8 sample_format; + WaveHeaderList(quint16 i,quint8 f){ interleave=i; sample_format=f; } +}; + + PRS1Loader::PRS1Loader() { //genCRCTable(); @@ -420,19 +429,18 @@ int PRS1Loader::OpenMachine(Machine *m,QString path,Profile *profile) return cnt; } +//struct PRS1SummaryR5 { +// quint8 unknown1; +// quint8 unknown2; +// quint8 unknown3; +// quint8 pressure_min; +// quint8 pressure_max; +// quint8 unknown; -struct PRS1SummaryR5 { - quint8 unknown1; - quint8 unknown2; - quint8 unknown3; - quint8 pressure_min; - quint8 pressure_max; - quint8 unknown; - - quint32 flags; +// quint32 flags; -};// __attribute__((packed)); +//};// __attribute__((packed)); bool PRS1Loader::ParseSummary(Machine *mach, qint32 sequence, quint32 timestamp, unsigned char *data, quint16 size, char version) { @@ -1414,6 +1422,7 @@ bool PRS1Loader::OpenEvents(Session *session,QString filename) return true; } */ + bool PRS1Loader::OpenWaveforms(SessionID sid, QString filename) { Session * session=new_sessions[sid]; diff --git a/SleepLib/loader_plugins/prs1_loader.h b/SleepLib/loader_plugins/prs1_loader.h index 28a18deb..f702bee6 100644 --- a/SleepLib/loader_plugins/prs1_loader.h +++ b/SleepLib/loader_plugins/prs1_loader.h @@ -25,6 +25,9 @@ const int prs1_data_version=8; // //******************************************************************************************** +/*! \class PRS1 + \brief PRS1 customized machine object (via CPAP) + */ class PRS1:public CPAP { public: @@ -38,43 +41,67 @@ const int max_load_buffer_size=1024*1024; const QString prs1_class_name="PRS1"; +/*! \class PRS1Loader + \brief Philips Respironics System One Loader Module + */ class PRS1Loader : public MachineLoader { public: PRS1Loader(); virtual ~PRS1Loader(); + //! \brief Scans directory path for valid PRS1 signature virtual int Open(QString & path,Profile *profile); + + //! \brief Returns the database version of this loader virtual int Version() { return prs1_data_version; } + + //! \brief Return the ClassName, in this case "PRS1" virtual const QString & ClassName() { return prs1_class_name; } + + //! \brief Create a new PRS1 machine record, indexed by Serial number. Machine *CreateMachine(QString serial,Profile *profile); + //! \brief Register this Module to the list of Loaders, so it knows to search for PRS1 data. static void Register(); protected: QString last; QHash PRS1List; + + //! \brief Opens the SD folder structure for this machine, scans for data files and imports any new sessions int OpenMachine(Machine *m,QString path,Profile *profile); + + //! \brief Parses "properties.txt" file containing machine information bool ParseProperties(Machine *m,QString filename); + //bool OpenSummary(Session *session,QString filename); //bool OpenEvents(Session *session,QString filename); + + //! \brief Parse a .005 waveform file, extracting Flow Rate waveform (and Mask Pressure data if available) bool OpenWaveforms(SessionID sid, QString filename); + + //! \brief ParseWaveform chunk.. Currently unused, as the old one works fine. bool ParseWaveform(qint32 sequence, quint32 timestamp, unsigned char *data, quint16 size, quint16 duration, quint16 num_signals, quint16 interleave, quint8 sample_format); + + //! \brief Parse a data chunk from the .000 (brick) and .001 (summary) files. bool ParseSummary(Machine *mach, qint32 sequence, quint32 timestamp, unsigned char *data, quint16 size, char version); + + //! \brief Parse a single data chunk from a .002 file containing event data for a standard system one machine bool Parse002(qint32 sequence, quint32 timestamp, unsigned char *data, quint16 size); + + //! \brief Parse a single data chunk from a .002 file containing event data for a family 5 ASV machine (which has a different format) bool Parse002v5(qint32 sequence, quint32 timestamp, unsigned char *data, quint16 size); + //! \brief Open a PRS1 data file, and break into data chunks, delivering them to the correct parser. bool OpenFile(Machine *mach, QString filename); + //bool Parse002(Session *session,unsigned char *buffer,int size,qint64 timestamp,long fpos); //bool Parse002ASV(Session *session,unsigned char *buffer,int size,qint64 timestamp,long fpos); unsigned char * m_buffer; QHash extra_session; + + //! \brief PRS1 Data files can store multiple sessions, so store them in this list for later processing. QHash new_sessions; qint32 summary_duration; }; -struct WaveHeaderList { - quint16 interleave; - quint8 sample_format; - WaveHeaderList(quint16 i,quint8 f){ interleave=i; sample_format=f; } -}; - #endif // PRS1LOADER_H diff --git a/SleepLib/loader_plugins/resmed_loader.cpp b/SleepLib/loader_plugins/resmed_loader.cpp index 4a6de110..1367dbd7 100644 --- a/SleepLib/loader_plugins/resmed_loader.cpp +++ b/SleepLib/loader_plugins/resmed_loader.cpp @@ -196,6 +196,9 @@ bool EDFParser::Open(QString name) filesize=f.size(); datasize=filesize-EDFHeaderSize; if (datasize<0) return false; + + //Urk.. This needs fixing for VC++, as it doesn't have packed attribute type.. + f.read((char *)&header,EDFHeaderSize); //qDebug() << "Opening " << name; buffer=new char [datasize]; diff --git a/SleepLib/loader_plugins/resmed_loader.h b/SleepLib/loader_plugins/resmed_loader.h index cbf41212..79b59815 100644 --- a/SleepLib/loader_plugins/resmed_loader.h +++ b/SleepLib/loader_plugins/resmed_loader.h @@ -26,6 +26,10 @@ const int resmed_data_version=5; const QString resmed_class_name="ResMed"; +/*! \struct EDFHeader + \brief Represents the EDF+ header structure, used as a place holder while processing the text data. + \note More information on the EDF+ file format can be obtained from http://edfplus.info +*/ struct EDFHeader { char version[8]; char patientident[80]; @@ -36,50 +40,113 @@ struct EDFHeader { char num_data_records[8]; char dur_data_records[8]; char num_signals[4]; -};// __attribute__ ((packed)); +} +#ifndef BUILD_WITH_MSVC +__attribute__ ((packed)) +#endif +; const int EDFHeaderSize=sizeof(EDFHeader); +/*! \struct EDFSignal + \brief Contains information about a single EDF+ Signal + \note More information on the EDF+ file format can be obtained from http://edfplus.info + */ struct EDFSignal { public: + //! \brief Name of this Signal QString label; + + //! \brief Tranducer Type (source of the data, usually blank) QString transducer_type; + + //! \brief The units of measurements represented by this signal QString physical_dimension; + + //! \brief The minimum limits of the ungained data double physical_minimum; + + //! \brief The maximum limits of the ungained data double physical_maximum; + + //! \brief The minimum limits of the data with gain and offset applied double digital_minimum; + + //! \brief The maximum limits of the data with gain and offset applied double digital_maximum; + + //! \brief Raw integer data is multiplied by this value double gain; + + //! \brief This value is added to the raw data double offset; + + //! \brief Any prefiltering methods used (usually blank) QString prefiltering; + + //! \brief Number of records long nr; + + //! \brief Reserved (usually blank) QString reserved; + + //! \brief Pointer to the signals sample data qint16 * data; + + //! \brief a non-EDF extra used internally to count the signal data int pos; }; +/*! \class EDFParser + \author Mark Watkins + \brief Parse an EDF+ data file into a list of EDFSignal's + \note More information on the EDF+ file format can be obtained from http://edfplus.info + */ class EDFParser { public: - EDFParser(QString filename); + //! \brief Constructs an EDFParser object, opening the filename if one supplied + EDFParser(QString filename=""); + ~EDFParser(); + + //! \brief Open the EDF+ file, and read it's header bool Open(QString name); + //! \brief Read si bytes of 8 bit data from the EDF+ data stream QString Read(int si); + + //! \brief Read 16 bit word of data from the EDF+ data stream qint16 Read16(); + //! \brief Vector containing the list of EDFSignals contained in this edf file QVector edfsignals; + + //! \brief An by-name indexed into the EDFSignal data QHash lookup; + + //! \brief Look up signal names by SleepLib ChannelID.. A little "ResMed"ified.. :/ EDFSignal * lookupSignal(ChannelID); + //! \brief Returns the number of signals contained in this EDF file long GetNumSignals() { return num_signals; } + + //! \brief Returns the number of data records contained per signal. long GetNumDataRecords() { return num_data_records; } + + //! \brief Returns the duration represented by this EDF file (in milliseconds) qint64 GetDuration() { return dur_data_record; } + + //! \brief Returns the patientid field from the EDF header QString GetPatient() { return patientident; } + //! \brief Parse the EDF+ file into the list of EDFSignals.. Must be call Open(..) first. bool Parse(); char *buffer; + + //! \brief The EDF+ files header structure, used as a place holder while processing the text data. EDFHeader header; + QString filename; long filesize; long datasize; @@ -99,27 +166,50 @@ public: QString reserved44; }; +/*! \class ResmedLoader + \brief Importer for ResMed S9 Data + */ class ResmedLoader : public MachineLoader { public: ResmedLoader(); virtual ~ResmedLoader(); + + //! \brief Scans for S9 SD folder structure signature, and loads any new data if found virtual int Open(QString & path,Profile *profile); + //! \brief Returns the version number of this ResMed loader virtual int Version() { return resmed_data_version; } + + //! \brief Returns the Machine class name of this loader. ("ResMed") virtual const QString & ClassName() { return resmed_class_name; } + + //! \brief Converts EDFSignal data to time delta packed EventList, and adds to Session EventList * ToTimeDelta(Session *sess,EDFParser &edf, EDFSignal & es, ChannelID code, long recs,qint64 duration,EventDataType min=0,EventDataType max=0,bool square=false); + //! \brief Create Machine record, and index it by serial number Machine *CreateMachine(QString serial,Profile *profile); + //! \brief Register the ResmedLoader with the list of other machine loaders static void Register(); protected: QHash ResmedList; - bool LoadEVE(Session *sess,EDFParser &edf); - bool LoadBRP(Session *sess,EDFParser &edf); - bool LoadSAD(Session *sess,EDFParser &edf); - bool LoadPLD(Session *sess,EDFParser &edf); + //! \brief Parse the EVE Event annotation data, and save to Session * sess + //! This contains all Hypopnea, Obstructive Apnea, Central and Apnea codes + bool LoadEVE(Session *sess,EDFParser &edf); + + //! \brief Parse the BRP High Resolution data, and save to Session * sess + //! This contains Flow Rate, Mask Pressure, and Resp. Event data + bool LoadBRP(Session *sess,EDFParser &edf); + + //! \brief Parse the SAD Pulse oximetry attachment data, and save to Session * sess + //! This contains Pulse Rate and SpO2 Oxygen saturation data + bool LoadSAD(Session *sess,EDFParser &edf); + + //! \brief Parse the PRD low resolution data, and save to Session * sess + //! This contains the Pressure, Leak, Respiratory Rate, Minute Ventilation, Tidal Volume, etc.. + bool LoadPLD(Session *sess,EDFParser &edf); }; #endif // RESMED_LOADER_H diff --git a/SleepLib/loader_plugins/zeo_loader.h b/SleepLib/loader_plugins/zeo_loader.h index 02376f07..441e6e43 100644 --- a/SleepLib/loader_plugins/zeo_loader.h +++ b/SleepLib/loader_plugins/zeo_loader.h @@ -14,6 +14,9 @@ const QString zeo_class_name="CMS50"; const int zeo_data_version=1; +/*! \class ZEOLoader + \brief Unfinished stub for loading ZEO Personal Sleep Coach data +*/ class ZEOLoader : public MachineLoader { public: @@ -22,8 +25,8 @@ class ZEOLoader : public MachineLoader virtual int Open(QString & path,Profile *profile); static void Register(); - virtual int Version() { return zeo_data_version; }; - virtual const QString & ClassName() { return zeo_class_name; }; + virtual int Version() { return zeo_data_version; } + virtual const QString & ClassName() { return zeo_class_name; } Machine *CreateMachine(Profile *profile); diff --git a/SleepLib/machine.h b/SleepLib/machine.h index 974759b3..110c3eba 100644 --- a/SleepLib/machine.h +++ b/SleepLib/machine.h @@ -41,12 +41,17 @@ class SaveThread:public QThread Q_OBJECT public: SaveThread(Machine *m,QString p) { machine=m; path=p; } + + //! \brief Static millisecond sleep function.. Can be used from anywhere static void msleep(unsigned long msecs) { QThread::msleep(msecs); } + + //! \brief Start Save processing thread running virtual void run(); protected: Machine *machine; QString path; signals: + //! \brief Signal sent to update the Progress Bar void UpdateProgress(int i); }; @@ -177,6 +182,8 @@ public: protected: }; +// This should probably move somewhere else +//! \fn timezoneOffset(); //! \brief Calculate the timezone Offset in milliseconds between system timezone and UTC qint64 timezoneOffset(); diff --git a/SleepLib/machine_common.h b/SleepLib/machine_common.h index 0e21e7d9..88f53f37 100644 --- a/SleepLib/machine_common.h +++ b/SleepLib/machine_common.h @@ -21,7 +21,10 @@ typedef long SessionID; typedef float EventDataType; typedef qint16 EventStoreType; +//! \brief Exception class for out of Bounds error.. Unused. class BoundsError {}; + +//! \brief Exception class for to trap old database versions. class OldDBVersion {}; const quint32 magic=0xC73216AB; // Magic number for Sleepyhead Data Files.. Don't touch! @@ -29,16 +32,29 @@ const quint32 magic=0xC73216AB; // Magic number for Sleepyhead Data Files.. Don' //const int max_number_event_fields=10; +/*! \enum SummaryType + \brief Calculation method to select from dealing with summary information + */ enum SummaryType { ST_CNT, ST_SUM, ST_AVG, ST_WAVG, ST_90P, ST_MIN, ST_MAX, ST_CPH, ST_SPH, ST_FIRST, ST_LAST, ST_HOURS, ST_SESSIONS, ST_SETMIN, ST_SETAVG, ST_SETMAX, ST_SETWAVG, ST_SETSUM }; +/*! \enum MachineType + \brief Generalized type of a machine + */ enum MachineType { MT_UNKNOWN=0,MT_CPAP,MT_OXIMETER,MT_SLEEPSTAGE,MT_JOURNAL }; //void InitMapsWithoutAwesomeInitializerLists(); +/*! \enum CPAPMode + \brief CPAP Machines mode of operation + */ enum CPAPMode//:short { MODE_UNKNOWN=0,MODE_CPAP,MODE_APAP,MODE_BIPAP,MODE_ASV }; + +/*! \enum PRTypes + \brief Pressure Relief Types, used by CPAP machines + */ enum PRTypes//:short { PR_UNKNOWN=0,PR_NONE,PR_CFLEX,PR_CFLEXPLUS,PR_AFLEX,PR_BIFLEX,PR_EPR,PR_SMARTFLEX @@ -49,10 +65,14 @@ enum PRTypes//:short //extern map PressureReliefNames; //extern map CPAPModeNames; -// These are types supported by wxVariant class. To retain compatability, add to the end of this list only.. +/*! \enum MCDataType + \brief Data Types stored by Profile/Preferences objects, etc.. + */ + enum MCDataType { MC_bool=0, MC_int, MC_long, MC_float, MC_double, MC_string, MC_datetime }; +// This all needs replacing with actual integer codes.. There will likely be a big speedup when this happens again. const QString CPAP_IPAP="IPAP"; const QString CPAP_IPAPLo="IPAPLo"; const QString CPAP_IPAPHi="IPAPHi"; diff --git a/SleepLib/machine_loader.h b/SleepLib/machine_loader.h index 3c1be0f3..564e68c4 100644 --- a/SleepLib/machine_loader.h +++ b/SleepLib/machine_loader.h @@ -12,6 +12,9 @@ License: GPL #include "profiles.h" #include "machine.h" +/*! \class MachineLoader + \brief Base class to derive a new Machine importer from + */ class MachineLoader { public: @@ -21,8 +24,13 @@ public: //virtual Machine * CreateMachine() {}; - virtual int Open(QString &,Profile *)=0; // Scans for new content + //! \brief Override this to scan path and detect new machine data + virtual int Open(QString & path,Profile *)=0; // Scans for new content + + //! \brief Override to returns the Version number of this MachineLoader virtual int Version()=0; + + //! \brief Override to returns the class name of this MachineLoader virtual const QString & ClassName()=0; @@ -47,12 +55,14 @@ public: virtual bool SaveWaveform(Machine * m, QString & filename);*/ protected: + //! \brief Contains a list of Machine records known by this loader QList m_machlist; QString m_class; MachineType m_type; Profile * m_profile; }; +// Put in machine loader class as static?? void RegisterLoader(MachineLoader *loader); void DestroyLoaders(); QList GetLoaders(); diff --git a/SleepLib/schema.h b/SleepLib/schema.h index 4d8bf477..56d65ef1 100644 --- a/SleepLib/schema.h +++ b/SleepLib/schema.h @@ -41,7 +41,9 @@ enum ScopeType { class Channel; extern Channel EmptyChannel; -// this is really a channel definition. +/*! \class Channel + \brief Contains information about a SleepLib data Channel (aka signals) + */ class Channel { public: @@ -81,19 +83,29 @@ protected: int m_link; }; +/*! \class ChannelList + \brief A list containing a group of Channel objects, and XML storage and retrieval capability + */ class ChannelList { public: ChannelList(); virtual ~ChannelList(); + + //! \brief Loads Channel list from XML file specified by filename bool Load(QString filename); + + //! \brief Stores Channel list to XML file specified by filename bool Save(QString filename); - Channel & operator[](int i) { - if (channels.contains(i)) - return *channels[i]; + + //! \brief Looks up Channel in this List with the index idx, returns EmptyChannel if not found + Channel & operator[](int idx) { + if (channels.contains(idx)) + return *channels[idx]; else return EmptyChannel; } + //! \brief Looks up Channel from this list by name, returns Empty Channel if not found. Channel & operator[](QString name) { if (names.contains(name)) return *names[name]; @@ -101,17 +113,24 @@ public: return EmptyChannel; } + //! \brief Channel List indexed by integer ID QHash channels; + + //! \brief Channel List index by name QHash names; + + //! \brief Channel List indexed by group QHash > groups; QString m_doctype; }; extern ChannelList channel; -enum LayerType { +/*enum LayerType { UnspecifiedLayer, Waveform, Flag, Overlay, Group }; + +// ????? class Layer { public: @@ -196,7 +215,7 @@ public: Graph *addGraph(Graph *graph) { m_graphs.push_back(graph); return graph; } protected: QVectorm_graphs; -}; +}; */ void init(); diff --git a/SleepyHeadQT.pro b/SleepyHeadQT.pro index e6e99f11..38827a0d 100644 --- a/SleepyHeadQT.pro +++ b/SleepyHeadQT.pro @@ -56,12 +56,10 @@ SOURCES += main.cpp\ Graphs/gFlagsLine.cpp \ Graphs/glcommon.cpp \ Graphs/gSegmentChart.cpp \ - Graphs/gSessionTime.cpp \ qextserialport/qextserialport.cpp \ preferencesdialog.cpp \ Graphs/gGraphView.cpp \ Graphs/gStatsLine.cpp \ - report.cpp \ Graphs/gSummaryChart.cpp \ SleepLib/schema.cpp \ profileselect.cpp \ @@ -126,7 +124,6 @@ HEADERS += \ Graphs/gFlagsLine.h \ Graphs/glcommon.h \ Graphs/gSegmentChart.h\ - Graphs/gSessionTime.h \ SleepLib/loader_plugins/resmed_loader.h \ qextserialport/qextserialport_global.h \ qextserialport/qextserialport.h \ @@ -134,7 +131,6 @@ HEADERS += \ preferencesdialog.h \ Graphs/gGraphView.h \ Graphs/gStatsLine.h \ - report.h \ Graphs/gSummaryChart.h \ SleepLib/schema.h \ profileselect.h \ @@ -179,7 +175,6 @@ RESOURCES += \ OTHER_FILES += \ docs/index.html \ docs/usage.html \ - docs/template_overview.sht \ docs/schema.xml \ docs/graphs.xml \ docs/channels.xml \ diff --git a/docs/template_overview.sht b/docs/template_overview.sht deleted file mode 100644 index b6f449c5..00000000 --- a/docs/template_overview.sht +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - -

CPAP Overview

- - - - - -
- - - - - -
Name:{{profile.FirstName}} {{profile.LastName}}
Address:{{profile.Address}}
Phone:{{profile.Phone}}
Email:{{profile.EmailAddress}}
- - - - -
Gender:{{profile.Gender}}
Age:{{local.Age}} years
Height:{{profile.Height}}{{local.DistanceMeasure}}
-
-
- {{logo}} -
SleepyHead v{{pref.VersionString}} -
http://sleepyhead.sf.net -
- Reporting from {{local.start}} to {{local.end}} -
-

-{{graph.AHI}} -{{graph.Usage}} -{{graph.Leaks}} -{{graph.Pressure}} -{{graph.Settings}} -{{graph.Sessions}} -{{graph.%PB}} - - diff --git a/exportcsv.h b/exportcsv.h index c60edf85..27e353fa 100644 --- a/exportcsv.h +++ b/exportcsv.h @@ -14,6 +14,11 @@ namespace Ui { class ExportCSV; } + +/*! \class ExportCSV + \brief Dialog for exporting SleepLib data in CSV Format + This module still needs a lot of work + */ class ExportCSV : public QDialog { Q_OBJECT diff --git a/overview.cpp b/overview.cpp index ac843270..0f24bb18 100644 --- a/overview.cpp +++ b/overview.cpp @@ -20,7 +20,6 @@ #include "Graphs/gXAxis.h" #include "Graphs/gLineChart.h" #include "Graphs/gYAxis.h" -#include "Graphs/gSessionTime.h" #include "mainwindow.h" extern MainWindow * mainwin; diff --git a/preferencesdialog.h b/preferencesdialog.h index f0714c23..9d03b196 100644 --- a/preferencesdialog.h +++ b/preferencesdialog.h @@ -30,11 +30,14 @@ public: MySortFilterProxyModel(QObject *parent = 0); protected: + //! \brief Simply extends filterAcceptRow to scan children as well bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const; }; -//! \note MaksProfile in still a work in progress +/*! \struct MaskProfile + \brief This in still a work in progress, and may be used in Unintentional leaks calculations. + */ struct MaskProfile { QString name; EventDataType pflow[5][2]; @@ -53,9 +56,10 @@ public: explicit PreferencesDialog(QWidget *parent, Profile * _profile); ~PreferencesDialog(); - /*! \fn Save() - \brief Save the current preferences, called when Ok button is clicked on */ + //! \brief Save the current preferences, called when Ok button is clicked on void Save(); + + //! \brief Updates the date text of the last time updates where checked void RefreshLastChecked(); private slots: @@ -83,7 +87,9 @@ private slots: void on_maskTypeCombo_activated(int index); private: + //! \brief Populates the Graph Model view with data from the Daily, Overview & Oximetry gGraphView objects void resetGraphModel(); + Ui::PreferencesDialog *ui; Profile * profile; QHash m_new_colors; @@ -92,7 +98,6 @@ private: MySortFilterProxyModel *graphFilterModel; QStandardItemModel *graphModel; QHash general; - }; diff --git a/report.cpp b/report.cpp deleted file mode 100644 index b7ff0b7b..00000000 --- a/report.cpp +++ /dev/null @@ -1,274 +0,0 @@ -/* - Report Module Implementation - Copyright (c)2011 Mark Watkins - License: GPL -*/ - -#include "report.h" -#include "ui_report.h" -#include -#include -#include -#include -//#include -#include -#include -#include -#include -#include - -Report::Report(QWidget *parent, gGraphView * shared, Overview * overview) : - QWidget(parent), - ui(new Ui::Report), - m_overview(overview) -{ - ui->setupUi(this); - - GraphView=new gGraphView(this,shared); - setMaximumSize(graph_print_width,800); - setMinimumSize(graph_print_width,800); - GraphView->setMaximumSize(graph_print_width,graph_print_height); - GraphView->setMinimumSize(graph_print_width,graph_print_height); - - GraphView->hide(); - - // Reusing the layer data from overview screen, - // (Can't reuse the graphs objects without breaking things) - - graphs["Usage"]=UC=new gGraph(GraphView,"Usage","",graph_print_height,0); - UC->AddLayer(m_overview->uc); - - graphs["AHI"]=AHI=new gGraph(GraphView,"AHI","",graph_print_height,0); - AHI->AddLayer(m_overview->bc); - - graphs["Pressure"]=PR=new gGraph(GraphView,"Pressure","",graph_print_height,0); - PR->AddLayer(m_overview->pr); - - graphs["Leaks"]=LK=new gGraph(GraphView,"Leaks","",graph_print_height,0); - LK->AddLayer(m_overview->lk); - - graphs["%PB"]=NPB=new gGraph(GraphView,"% in PB","",graph_print_height,0); - NPB->AddLayer(m_overview->npb); - - graphs["Settings"]=SET=new gGraph(GraphView,"Settings","",graph_print_height,0); - SET->AddLayer(m_overview->set); - - graphs["Sessions"]=SES=new gGraph(GraphView,"Sessions","",graph_print_height,0); - SES->AddLayer(m_overview->ses); - - - for (QHash::iterator g=graphs.begin();g!=graphs.end();g++) { - gGraph *gr=g.value(); - gr->AddLayer(new gYAxis(),LayerLeft,gYAxis::Margin); - gXAxis *gx=new gXAxis(); - gx->setUtcFix(true); - gr->AddLayer(gx,LayerBottom,0,gXAxis::Margin); - gr->AddLayer(new gXGrid()); - } - - GraphView->hideSplitter(); - m_ready=false; -} - -Report::~Report() -{ - GraphView->trashGraphs(); - for (QHash::iterator g=graphs.begin();g!=graphs.end();g++) { - delete g.value(); - } - delete ui; -} -void Report::ReloadGraphs() -{ - - for (QHash::iterator g=graphs.begin();g!=graphs.end();g++) { - g.value()->setDay(NULL); - } - startDate=PROFILE.FirstDay(); - endDate=PROFILE.LastDay(); - for (QHash::iterator g=graphs.begin();g!=graphs.end();g++) { - g.value()->ResetBounds(); - } - m_ready=true; - -} - -QPixmap Report::Snapshot(gGraph * graph) -{ - QDateTime d1(startDate,QTime(0,0,0),Qt::UTC); - qint64 first=qint64(d1.toTime_t())*1000L; - QDateTime d2(endDate,QTime(23,59,59),Qt::UTC); - qint64 last=qint64(d2.toTime_t())*1000L; - - GraphView->trashGraphs(); - GraphView->addGraph(graph); - GraphView->ResetBounds(); - GraphView->SetXBounds(first,last); - - QPixmap pixmap=GraphView->renderPixmap(graph_print_width,graph_print_height,false); - - return pixmap; -} - -QString Report::ParseTemplate(QString input) -{ - QString output; - - QRegExp rx("\\{\\{(.*)\\}\\}"); - rx.setMinimal(true); - int lastpos=0,pos=0; - - while ((pos=rx.indexIn(input,pos))!=-1) { - output+=input.mid(lastpos,pos-lastpos); - QString block=rx.cap(1); - - QString code=block.section(".",0,0).toLower(); - QString key=block.section(".",1,-1); - QHash * pr=NULL; - if (code=="profile") { - pr=&PROFILE.p_preferences; - } else if (code=="pref") { - pr=&PREF.p_preferences; - } else if (code=="local") { - pr=&locals; - } - - QString value; - if (pr) { - if (pr->contains(key)) { - if ((*pr)[key].type()==QVariant::String){ - value=(*pr)[key].toString(); - value.replace("\n","
"); - output+=value; - } else if ((*pr)[key].type()==QVariant::Double){ - bool ok; - value=QString::number((*pr)[key].toDouble(&ok),'f',2); - if (ok) output+=value; else output+="[NaN]"; - } else if ((*pr)[key].type()==QVariant::Int){ - bool ok; - value=QString::number((*pr)[key].toInt(&ok)); - if (ok) output+=value; else output+="[NaN]"; - } else if ((*pr)[key].type()==QVariant::Date){ - value=(*pr)[key].toDate().toString(); - output+=value; - } else { - qDebug() << "Unknown key type" << (*pr)[key].typeName() << " in " << code << "." << key << "in template"; - } - } else { - qDebug() << "Key not found" << code << "." << key << "in template"; - } - } else if (code=="graph") { - if (graphs.contains(key)) { - if (!graphs[key]->isEmpty()) { - QPixmap pixmap=Snapshot(graphs[key]); - QByteArray byteArray; - QBuffer buffer(&byteArray); // use buffer to store pixmap into byteArray - buffer.open(QIODevice::WriteOnly); - pixmap.save(&buffer, "PNG"); - //output += "
\n"; - output += "
\n"; - } - - } else { - qDebug() << "Graph not found" << key << "in template"; - } - } else if (code=="logo") { - QPixmap pixmap(":/docs/sheep.png"); - QByteArray byteArray; - QBuffer buffer(&byteArray); // use buffer to store pixmap into byteArray - buffer.open(QIODevice::WriteOnly); - pixmap.save(&buffer, "PNG"); - output += ""; - - } - pos+=rx.matchedLength(); - lastpos=pos; - } - output+=input.mid(lastpos); // will just return the input if no tags are used - return output; - -} - -QString Report::GenerateReport(QString templ,QDate start, QDate end) -{ - //if (!m_ready) return; - startDate=start; - endDate=end; - - QString filename=PREF.Get("{home}/Reports"); - QDir dir(filename); - if (!dir.exists()) { - dir.mkdir(filename); - } - filename+="/"+templ+".sht"; - QFile file; - file.setFileName(filename); - - QByteArray input; - if (0) { //file.exists()) { - file.open(QIODevice::ReadOnly); - input=file.readAll(); - file.close(); - } else { - QString f2=":/docs/template_"+templ+".sht"; - file.setFileName(f2); - if (!file.exists()) return ""; - file.open(QIODevice::ReadOnly); - input=file.readAll(); - file.close(); - file.setFileName(filename); - file.open(QIODevice::WriteOnly); - file.write(input); - file.close(); - } - QString html=input; - - locals["start"]=start; - locals["end"]=end; - locals["width"]=graph_print_width-10; - - if (PROFILE.Exists("DOB") && !PROFILE["DOB"].toString().isEmpty()) { - QDate dob=PROFILE["DOB"].toDate(); - QDateTime d1(dob,QTime(0,0,0)); - QDateTime d2(QDate::currentDate(),QTime(0,0,0)); - int years=d1.daysTo(d2)/365.25; - locals["Age"]=years; - } - if (!PROFILE.Exists("UnitSystem")) { - PROFILE["UnitSystem"]="Metric"; - } - if (PROFILE.Exists("Height") && !PROFILE["Height"].toString().isEmpty()) { - if (PROFILE["UnitSystem"].toString()=="Metric") - locals["DistanceMeasure"]="cm"; - else locals["DistanceMeasure"]=" inches"; - } - //QFile file(":/docs/template_overview.sht"); - //file.open(QIODevice::ReadOnly); - //QString html=file.readAll(); - //ui->webView->setHtml(output); - return ParseTemplate(html); -} - -void Report::Print(QString html) -{ - if (html.isEmpty()) return; - ui->webView->setHtml(html); - QPrinter printer; -#ifdef Q_WS_X11 - printer.setPrinterName("Print to File (PDF)"); - printer.setOutputFormat(QPrinter::PdfFormat); -#endif - printer.setPrintRange(QPrinter::AllPages); - printer.setOrientation(QPrinter::Portrait); - //printer.setPaperSize(QPrinter::A4); - printer.setResolution(QPrinter::HighResolution); - //printer.setPageSize(); - printer.setFullPage(false); // This has nothing to do with scaling - printer.setNumCopies(1); - printer.setPageMargins(10,10,10,10,QPrinter::Millimeter); - QPrintDialog *dialog = new QPrintDialog(&printer); - //printer.setOutputFileName("printYou.pdf"); - if ( dialog->exec() == QDialog::Accepted) { - ui->webView->print(&printer); - } -} diff --git a/report.h b/report.h deleted file mode 100644 index 894eec31..00000000 --- a/report.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - Report Module Header - Copyright (c)2011 Mark Watkins - License: GPL -*/ - -#ifndef REPORT_H -#define REPORT_H - -#include -#include -#include "SleepLib/profiles.h" -#include "Graphs/gGraphView.h" -#include "overview.h" - -namespace Ui { - class Report; -} - -const int graph_print_width=1024; -const int graph_print_height=150; - -class Daily; -class Overview; -class Report : public QWidget -{ - Q_OBJECT - -public: - explicit Report(QWidget *parent, gGraphView * shared, Overview * overview); - ~Report(); - QString GenerateReport(QString templ,QDate start, QDate end); - void ReloadGraphs(); - QString ParseTemplate(QString input); - - QPixmap Snapshot(gGraph * graph); - void Print(QString html); - -private: - Ui::Report *ui; - Overview * m_overview; - gGraphView * shared; - gGraphView * GraphView; - gGraph *AHI,*UC,*PR,*LK,*NPB,*SET,*SES; - SummaryChart *bc,*uc,*pr,*lk,*npb,*set,*ses; - QHash locals; - QHash graphs; - - QDate startDate; - QDate endDate; - - bool m_ready; -}; - -#endif // REPORT_H