diff --git a/Jamulus.pro b/Jamulus.pro index b0df1a78..2165d5f5 100755 --- a/Jamulus.pro +++ b/Jamulus.pro @@ -158,7 +158,6 @@ HEADERS += src/audiomixerboard.h \ src/connectdlg.h \ src/global.h \ src/clientdlg.h \ - src/historygraph.h \ src/serverdlg.h \ src/multicolorled.h \ src/multicolorledbar.h \ @@ -169,13 +168,15 @@ HEADERS += src/audiomixerboard.h \ src/settings.h \ src/socket.h \ src/soundbase.h \ - src/svghistorygraph.h \ src/testbench.h \ src/util.h \ src/analyzerconsole.h \ src/recorder/jamrecorder.h \ src/recorder/creaperproject.h \ - src/recorder/cwavestream.h + src/recorder/cwavestream.h \ + src/historygraph.h \ + src/jpeghistorygraph.h \ + src/svghistorygraph.h HEADERS_OPUS = libs/opus/include/opus.h \ libs/opus/include/opus_multistream.h \ @@ -268,12 +269,14 @@ SOURCES += src/audiomixerboard.cpp \ src/settings.cpp \ src/socket.cpp \ src/soundbase.cpp \ - src/svghistorygraph.cpp \ src/util.cpp \ src/analyzerconsole.cpp \ src/recorder/jamrecorder.cpp \ src/recorder/creaperproject.cpp \ - src/recorder/cwavestream.cpp + src/recorder/cwavestream.cpp \ + src/historygraph.cpp \ + src/jpeghistorygraph.cpp \ + src/svghistorygraph.cpp SOURCES_OPUS = libs/opus/src/opus.c \ libs/opus/src/opus_decoder.c \ diff --git a/src/historygraph.cpp b/src/historygraph.cpp new file mode 100644 index 00000000..ae4c7031 --- /dev/null +++ b/src/historygraph.cpp @@ -0,0 +1,256 @@ +#include "historygraph.h" + +AHistoryGraph::AHistoryGraph() : + sFileName ( "" ), + bDoHistory ( false ), + vHistoryDataFifo ( NUM_ITEMS_HISTORY ), + iNumTicksX ( 0 ), // number of days in history + + BackgroundColor ( "white" ), // background + FrameColor ( "black" ), // frame + GridColor ( "gray" ), // grid + TextColor ( "black" ), // text + MarkerNewColor ( "darkCyan" ), // marker for new connection + MarkerNewLocalColor ( "blue" ), // marker for new local connection + MarkerStopColor ( "red" ), // marker for server stop + + canvasRectX ( 0 ), + canvasRectY ( 0 ), + canvasRectWidth ( 640 ), + canvasRectHeight ( 450 ), + + iGridFrameOffset ( 10 ), + iGridWidthWeekend ( 3 ), // should be an odd value + iXAxisTextHeight ( 22 ), + gridFrameX ( canvasRectX + iGridFrameOffset ), + gridFrameY ( canvasRectY + iGridFrameOffset ), + gridFrameWidth ( canvasRectWidth - 2 * iGridFrameOffset ), + gridFrameHeight ( canvasRectHeight - 2 * iGridFrameOffset - iXAxisTextHeight ), + gridFrameRight ( gridFrameX + gridFrameWidth - 1 ), + gridFrameBottom ( gridFrameY + gridFrameHeight - 1 ), + + axisFontFamily ( "Arial" ), + axisFontWeight ( "100" ), + axisFontSize ( 12 ), + + iYAxisStart ( 0 ), + iYAxisEnd ( 24 ), + iNumTicksY ( 5 ), + + iTextOffsetToGrid ( 3 ), + iTextOffsetX ( 18 ), + + iMarkerSizeNewCon ( 11 ), + iMarkerSizeServSt ( 8 ) +{ +} + +void AHistoryGraph::Start ( const QString& sNewFileName ) +{ + QTextStream& tsConsoleStream = *( ( new ConsoleWriterFactory() )->get() ); + tsConsoleStream << QString("AHistoryGraph::Start ( %1 )").arg(sNewFileName) << endl; // on console + if ( !sNewFileName.isEmpty() ) + { + // save file name + sFileName = sNewFileName; + + // set enable flag + bDoHistory = true; + + // enable timer (update once a day) + TimerDailyUpdate.start ( 3600000 * 24 ); + + // initial update (empty graph) + Update(); + } +} + +void AHistoryGraph::Add ( const QDateTime& newDateTime, const EHistoryItemType curType ) +{ + if ( bDoHistory ) + { + // create and add new element in FIFO + SHistoryData curHistoryData; + curHistoryData.DateTime = newDateTime; + curHistoryData.Type = curType; + + vHistoryDataFifo.Add ( curHistoryData ); + } +} + +void AHistoryGraph::Add ( const QDateTime& newDateTime, const QHostAddress ClientInetAddr ) +{ + if ( bDoHistory ) + { + // add element to history, distinguish between a local connection + // and a remote connection + if ( ( ClientInetAddr == QHostAddress ( "127.0.0.1" ) ) || + ( ClientInetAddr.toString().left ( 7 ).compare ( "192.168" ) == 0 ) ) + { + // local connection + Add ( newDateTime, HIT_LOCAL_CONNECTION ); + } + else + { + // remote connection + Add ( newDateTime, HIT_REMOTE_CONNECTION ); + } + } +} + +void AHistoryGraph::Update ( ) +{ + if ( bDoHistory ) + { + int i; + + // store current date for reference + curDate = QDate::currentDate(); + + // get oldest date in history + QDate oldestDate = curDate.addDays ( 1 ); // one day in the future + const int iNumItemsForHistory = vHistoryDataFifo.Size(); + for ( i = 0; i < iNumItemsForHistory; i++ ) + { + // only use valid dates + if ( vHistoryDataFifo[i].DateTime.date().isValid() ) + { + if ( vHistoryDataFifo[i].DateTime.date() < oldestDate ) + { + oldestDate = vHistoryDataFifo[i].DateTime.date(); + } + } + } + const int iNumDaysInHistory = -curDate.daysTo ( oldestDate ) + 1; + + // draw frame of the graph + DrawFrame ( iNumDaysInHistory ); + + // add markers + for ( i = 0; i < iNumItemsForHistory; i++ ) + { + // only use valid dates + if ( vHistoryDataFifo[i].DateTime.date().isValid() ) + { + AddMarker ( vHistoryDataFifo[i] ); + } + } + + // save graph as picture in file + Save ( sFileName ); + } +} + +void AHistoryGraph::DrawFrame ( const int iNewNumTicksX ) +{ + int i; + + // store number of x-axis ticks (number of days we want to draw + // the history for + iNumTicksX = iNewNumTicksX; + + + // Create actual plot region (grid frame) ---------------------------------- + rect( gridFrameX, gridFrameY, gridFrameWidth, gridFrameHeight ); + + // calculate step for x-axis ticks so that we get the desired number of + // ticks -> 5 ticks + +// TODO the following equation does not work as expected but results are acceptable + + // we want to have "floor ( iNumTicksX / 5 )" which is the same as + // "iNumTicksX / 5" since "iNumTicksX" is an integer variable + const int iXAxisTickStep = iNumTicksX / 5 + 1; + + // grid (ticks) for x-axis + dayXSpace = static_cast ( gridFrameWidth ) / ( iNumTicksX + 1 ); + for ( i = 0; i < static_cast(iNumTicksX); i++ ) + { + int iBottomExtraTickLen = 0; + const int iCurX = gridFrameX + static_cast ( dayXSpace * ( i + 1 ) ); + const QDate curXAxisDate = curDate.addDays ( i - iNumTicksX + 1 ); + + // text (print only every "iXAxisTickStep" tick) + if ( !( i % iXAxisTickStep ) ) + { + text( iCurX - iTextOffsetX, gridFrameBottom + iXAxisTextHeight + iTextOffsetToGrid, curXAxisDate.toString ( "dd.MM." ) ); + + iBottomExtraTickLen = 5; + } + + // regular grid + line( iCurX, 1 + gridFrameY, iCurX, gridFrameBottom + iBottomExtraTickLen ); + + // different grid width for weekends (overwrite regular grid) + if ( ( curXAxisDate.dayOfWeek() == 6 ) || // check for Saturday + ( curXAxisDate.dayOfWeek() == 7 ) ) // check for Sunday + { + const int iGridWidthWeekendHalf = iGridWidthWeekend / 2; + + line( iCurX, 1 + gridFrameY + iGridWidthWeekendHalf, iCurX, gridFrameBottom - iGridWidthWeekendHalf, iGridWidthWeekend ); + } + } + + // grid (ticks) for y-axis, draw iNumTicksY - 2 grid lines and + // iNumTicksY - 1 text labels (the lowest grid line is the grid frame) + iYSpace = gridFrameHeight / ( iNumTicksY - 1 ); + for ( i = 0; i < ( static_cast(iNumTicksY) - 1 ); i++ ) + { + const int iCurY = gridFrameY + iYSpace * ( i + 1 ); + + // text + text( gridFrameX + iTextOffsetToGrid, + iCurY - iTextOffsetToGrid, + QString ( "%1:00" ).arg ( ( iYAxisEnd - iYAxisStart ) / ( iNumTicksY - 1 ) * ( ( iNumTicksY - 2 ) - i ) ) ); + + // grid (do not overwrite frame) + if ( i < ( static_cast(iNumTicksY) - 2 ) ) + { + line( gridFrameX, iCurY, gridFrameRight, iCurY ); + } + } +} + +void AHistoryGraph::AddMarker ( const SHistoryData& curHistoryData ) +{ + // calculate x-axis offset (difference of days compared to + // current date) + const int iXAxisOffs = + curDate.daysTo ( curHistoryData.DateTime.date() ); + + // check range, if out of range, do not plot anything + if ( -iXAxisOffs > ( static_cast(iNumTicksX) - 1 ) ) + { + return; + } + + // calculate y-axis offset (consider hours and minutes) + const double dYAxisOffs = 24 - curHistoryData.DateTime.time().hour() - + static_cast ( curHistoryData.DateTime.time().minute() ) / 60; + + // calculate the actual point in the graph (in pixels) + int curPointX = gridFrameX + static_cast ( dayXSpace * ( iNumTicksX + iXAxisOffs ) ); + int curPointY = gridFrameY + static_cast ( static_cast ( + gridFrameHeight ) / ( iYAxisEnd - iYAxisStart ) * dYAxisOffs ); + QString curPointColour = MarkerNewColor; + int curPointSize = iMarkerSizeNewCon; + + // we use different markers for new connection and server stop items + switch ( curHistoryData.Type ) + { + case HIT_SERVER_STOP: + curPointColour = MarkerStopColor; + curPointSize = iMarkerSizeServSt; + break; + + case HIT_LOCAL_CONNECTION: + curPointColour = MarkerNewLocalColor; + break; + + case HIT_REMOTE_CONNECTION: + curPointColour = MarkerNewColor; + break; + } + + point( curPointX, curPointY, curPointSize, curPointColour ); +} diff --git a/src/historygraph.h b/src/historygraph.h old mode 100755 new mode 100644 index cf8e5caf..49f45568 --- a/src/historygraph.h +++ b/src/historygraph.h @@ -1,8 +1,6 @@ #ifndef HISTORYGRAPH_H #define HISTORYGRAPH_H -#include -#include #include #include #include @@ -15,11 +13,9 @@ // number of history items to store #define NUM_ITEMS_HISTORY 600 -/* Classes ********************************************************************/ -class CHistoryGraph : public QObject +/* Interface ********************************************************************/ +class AHistoryGraph { - Q_OBJECT - public: enum EHistoryItemType { @@ -28,11 +24,13 @@ public: HIT_SERVER_STOP }; - CHistoryGraph(); + AHistoryGraph(); + ~AHistoryGraph() { } + void Start ( const QString& sNewFileName ); void Add ( const QDateTime& newDateTime, const EHistoryItemType curType ); void Add ( const QDateTime& newDateTime, const QHostAddress ClientInetAddr ); - void Update(); + virtual void Update ( ); protected: struct SHistoryData @@ -42,49 +40,61 @@ protected: }; void DrawFrame ( const int iNewNumTicksX ); void AddMarker ( const SHistoryData& curHistoryData ); - void Save ( const QString sFileName ); + virtual void Save ( const QString sFileName ) = 0; + virtual void rect ( const unsigned int x, const unsigned int y, const unsigned int width, const unsigned int height ) = 0; + virtual void text ( const unsigned int x, const unsigned int y, const QString& value ) = 0; + virtual void line ( const unsigned int x1, const unsigned int y1, const unsigned int x2, const unsigned int y2, const unsigned int strokeWidth = 1 ) = 0; + virtual void point ( const unsigned int x, const unsigned int y, const unsigned int size, const QString& colour ) = 0; + + // Constructor sets these QString sFileName; - bool bDoHistory; CFIFO vHistoryDataFifo; + unsigned int iNumTicksX; // Class global, not sure why - QRect PlotCanvasRect; + QString BackgroundColor; + QString FrameColor; + QString GridColor; + QString TextColor; + QString MarkerNewColor; + QString MarkerNewLocalColor; + QString MarkerStopColor; - int iNumTicksX; - int iYAxisStart; - int iYAxisEnd; - int iNumTicksY; - int iGridFrameOffset; - int iGridWidthWeekend; - int iTextOffsetToGrid; - int iXAxisTextHeight; - int iMarkerSizeNewCon; - int iMarkerSizeServSt; + const unsigned int canvasRectX; + const unsigned int canvasRectY; + const unsigned int canvasRectWidth; + const unsigned int canvasRectHeight; - QFont AxisFont; - int iTextOffsetX; + const unsigned int iGridFrameOffset; + const unsigned int iGridWidthWeekend; + const unsigned int iXAxisTextHeight; + const unsigned int gridFrameX; + const unsigned int gridFrameY; + const unsigned int gridFrameWidth; + const unsigned int gridFrameHeight; + const unsigned int gridFrameRight; + const unsigned int gridFrameBottom; - QColor PlotBackgroundColor; - QColor PlotFrameColor; - QColor PlotGridColor; - QColor PlotTextColor; - QColor PlotMarkerNewColor; - QColor PlotMarkerNewLocalColor; - QColor PlotMarkerStopColor; + const QString axisFontFamily; + const QString axisFontWeight; + const unsigned int axisFontSize; - QImage PlotPixmap; + const unsigned int iYAxisStart; + const unsigned int iYAxisEnd; + const unsigned int iNumTicksY; - double dXSpace; - int iYSpace; + const unsigned int iTextOffsetToGrid; + const unsigned int iTextOffsetX; - QDate curDate; - QRect PlotGridFrame; - QTimer TimerDailyUpdate; + const unsigned int iMarkerSizeNewCon; + const unsigned int iMarkerSizeServSt; -public slots: - void OnTimerDailyUpdate() { Update(); } + // others + double dayXSpace; + unsigned int iYSpace; + QDate curDate; + QTimer TimerDailyUpdate; }; - #endif // HISTORYGRAPH_H diff --git a/src/jpeghistorygraph.cpp b/src/jpeghistorygraph.cpp new file mode 100644 index 00000000..41b1391f --- /dev/null +++ b/src/jpeghistorygraph.cpp @@ -0,0 +1,96 @@ +#include "jpeghistorygraph.h" + +CJpegHistoryGraph::CJpegHistoryGraph() : + AHistoryGraph(), + PlotPixmap ( 1, 1, QImage::Format_RGB32 ), + iAxisFontWeight ( -1 ) +{ + // scale pixmap to correct size + PlotPixmap = PlotPixmap.scaled ( canvasRectWidth, canvasRectHeight ); + + // axisFontWeight is a string matching the CSS2 font-weight definition + // Thin = 0, // 100 + // ExtraLight = 12, // 200 + // Light = 25, // 300 + // Normal = 50, // 400 + // Medium = 57, // 500 + // DemiBold = 63, // 600 + // Bold = 75, // 700 + // ExtraBold = 81, // 800 + // Black = 87 // 900 + bool ok; + int weight = axisFontWeight.toInt( &ok ); + if (!ok) + { + if (!QString("normal").compare(axisFontWeight, Qt::CaseSensitivity::CaseInsensitive)) { iAxisFontWeight = 50; } + else if (!QString("bold").compare(axisFontWeight, Qt::CaseSensitivity::CaseInsensitive)) { weight = 75; } + } + else + { + if (weight <= 100) { iAxisFontWeight = 0; } + else if (weight <= 200) { iAxisFontWeight = 12; } + else if (weight <= 300) { iAxisFontWeight = 25; } + else if (weight <= 400) { iAxisFontWeight = 50; } + else if (weight <= 500) { iAxisFontWeight = 57; } + else if (weight <= 600) { iAxisFontWeight = 63; } + else if (weight <= 700) { iAxisFontWeight = 75; } + else if (weight <= 800) { iAxisFontWeight = 81; } + else if (weight <= 900) { iAxisFontWeight = 87; } + } + // if all else fails, it's left at -1 + + QTextStream& tsConsoleStream = *( ( new ConsoleWriterFactory() )->get() ); + tsConsoleStream << "CJpegHistoryGraph" << endl; // on console + + // Connections ------------------------------------------------------------- + QObject::connect ( &TimerDailyUpdate, SIGNAL ( timeout() ), + this, SLOT ( OnTimerDailyUpdate() ) ); +} + +// Override Update to create the fresh SVG stream each time +void CJpegHistoryGraph::Update() +{ + if ( bDoHistory ) + { + // create JPEG image + PlotPixmap.fill ( BackgroundColor ); // fill background + + AHistoryGraph::Update(); + } +} + +void CJpegHistoryGraph::Save ( const QString sFileName ) +{ + // save plot as a file + PlotPixmap.save ( sFileName, "JPG", 90 ); +} + +void CJpegHistoryGraph::rect ( const unsigned int x, const unsigned int y, const unsigned int width, const unsigned int height ) +{ + QPainter PlotPainter ( &PlotPixmap ); + PlotPainter.setPen ( FrameColor ); + PlotPainter.drawRect ( x, y, width, height ); +} + +void CJpegHistoryGraph::text ( const unsigned int x, const unsigned int y, const QString& value ) +{ + QPainter PlotPainter ( &PlotPixmap ); + PlotPainter.setPen ( TextColor ); + // QFont(const QString &family, int pointSize = -1, int weight = -1, bool italic = false); + PlotPainter.setFont ( QFont( axisFontFamily, static_cast(axisFontSize), iAxisFontWeight ) ); + PlotPainter.drawText ( QPoint ( x, y ), value ); +} + +void CJpegHistoryGraph::line ( const unsigned int x1, const unsigned int y1, const unsigned int x2, const unsigned int y2, const unsigned int strokeWidth ) +{ + QPainter PlotPainter ( &PlotPixmap ); + PlotPainter.setPen ( QPen ( QBrush ( QColor ( GridColor ) ), strokeWidth ) ); + PlotPainter.drawLine ( x1, y1, x2, y2 ); +} + +void CJpegHistoryGraph::point ( const unsigned int x, const unsigned int y, const unsigned int size, const QString& colour ) +{ + QPainter PlotPainter ( &PlotPixmap ); + PlotPainter.setPen ( QPen ( QBrush( QColor ( colour ) ), size ) ); + PlotPainter.drawPoint ( x, y ); +} diff --git a/src/jpeghistorygraph.h b/src/jpeghistorygraph.h new file mode 100755 index 00000000..f4dd3c88 --- /dev/null +++ b/src/jpeghistorygraph.h @@ -0,0 +1,34 @@ +#ifndef JPEGHISTORYGRAPH_H +#define JPEGHISTORYGRAPH_H + +#include "historygraph.h" + +#include +#include + +/* Classes ********************************************************************/ +class CJpegHistoryGraph : public QObject, virtual public AHistoryGraph +{ + Q_OBJECT + +public: + CJpegHistoryGraph(); + virtual void Update ( ); + +protected: + virtual void Save ( const QString sFileName ); + + virtual void rect ( const unsigned int x, const unsigned int y, const unsigned int width, const unsigned int height ); + virtual void text ( const unsigned int x, const unsigned int y, const QString& value ); + virtual void line ( const unsigned int x1, const unsigned int y1, const unsigned int x2, const unsigned int y2, const unsigned int strokeWidth = 1 ); + virtual void point ( const unsigned int x, const unsigned int y, const unsigned int size, const QString& colour ); + +private: + QImage PlotPixmap; + int iAxisFontWeight; + +public slots: + void OnTimerDailyUpdate() { Update(); } +}; + +#endif // JPEGHISTORYGRAPH_H diff --git a/src/serverlogging.cpp b/src/serverlogging.cpp index 0567cebe..389127d7 100755 --- a/src/serverlogging.cpp +++ b/src/serverlogging.cpp @@ -24,293 +24,6 @@ #include "serverlogging.h" - -/* Implementation *************************************************************/ -CHistoryGraph::CHistoryGraph() : - sFileName ( "" ), - bDoHistory ( false ), - vHistoryDataFifo ( NUM_ITEMS_HISTORY ), - PlotCanvasRect ( 0, 0, 600, 450 ), // defines total size of graph - iNumTicksX ( 0 ), // just an initialization value, will be overwritten - iYAxisStart ( 0 ), - iYAxisEnd ( 24 ), - iNumTicksY ( 5 ), - iGridFrameOffset ( 10 ), - iGridWidthWeekend ( 3 ), // should be an odd value - iTextOffsetToGrid ( 3 ), - iXAxisTextHeight ( 22 ), - iMarkerSizeNewCon ( 11 ), - iMarkerSizeServSt ( 8 ), - AxisFont ( "Arial", 12 ), - iTextOffsetX ( 18 ), - PlotBackgroundColor ( Qt::white ), // background - PlotFrameColor ( Qt::black ), // frame - PlotGridColor ( Qt::gray ), // grid - PlotTextColor ( Qt::black ), // text - PlotMarkerNewColor ( Qt::darkCyan ), // marker for new connection - PlotMarkerNewLocalColor ( Qt::blue ), // marker for new local connection - PlotMarkerStopColor ( Qt::red ), // marker for server stop - PlotPixmap ( 1, 1, QImage::Format_RGB32 ) -{ - // generate plot grid frame rectangle - PlotGridFrame.setRect ( PlotCanvasRect.x() + iGridFrameOffset, - PlotCanvasRect.y() + iGridFrameOffset, - PlotCanvasRect.width() - 2 * iGridFrameOffset, - PlotCanvasRect.height() - 2 * iGridFrameOffset - iXAxisTextHeight ); - - // scale pixmap to correct size - PlotPixmap = PlotPixmap.scaled ( - PlotCanvasRect.width(), PlotCanvasRect.height() ); - - - // Connections ------------------------------------------------------------- - QObject::connect ( &TimerDailyUpdate, SIGNAL ( timeout() ), - this, SLOT ( OnTimerDailyUpdate() ) ); -} - -void CHistoryGraph::Start ( const QString& sNewFileName ) -{ - if ( !sNewFileName.isEmpty() ) - { - // save file name - sFileName = sNewFileName; - - // set enable flag - bDoHistory = true; - - // enable timer (update once a day) - TimerDailyUpdate.start ( 3600000 * 24 ); - - // initial update (empty graph) - Update(); - } -} - -void CHistoryGraph::DrawFrame ( const int iNewNumTicksX ) -{ - int i; - - // store number of x-axis ticks (number of days we want to draw - // the history for - iNumTicksX = iNewNumTicksX; - - // clear base pixmap for new plotting - PlotPixmap.fill ( PlotBackgroundColor.rgb() ); // fill background - - // create painter - QPainter PlotPainter ( &PlotPixmap ); - - - // Create actual plot region (grid frame) ---------------------------------- - PlotPainter.setPen ( PlotFrameColor ); - PlotPainter.drawRect ( PlotGridFrame ); - - // calculate step for x-axis ticks so that we get the desired number of - // ticks -> 5 ticks - -// TODO the following equation does not work as expected but results are acceptable - - // we want to have "floor ( iNumTicksX / 5 )" which is the same as - // "iNumTicksX / 5" since "iNumTicksX" is an integer variable - const int iXAxisTickStep = iNumTicksX / 5 + 1; - - // grid (ticks) for x-axis - dXSpace = static_cast ( PlotGridFrame.width() ) / ( iNumTicksX + 1 ); - for ( i = 0; i < iNumTicksX; i++ ) - { - int iBottomExtraTickLen = 0; - const int iCurX = PlotGridFrame.x() + static_cast ( dXSpace * ( i + 1 ) ); - const QDate curXAxisDate = curDate.addDays ( i - iNumTicksX + 1 ); - - // text (print only every "iXAxisTickStep" tick) - if ( !( i % iXAxisTickStep ) ) - { - PlotPainter.setPen ( PlotTextColor ); - PlotPainter.setFont ( AxisFont ); - PlotPainter.drawText ( - QPoint ( iCurX - iTextOffsetX, - PlotGridFrame.bottom() + iXAxisTextHeight + iTextOffsetToGrid ), - curXAxisDate.toString ( "dd.MM." ) ); - - iBottomExtraTickLen = 5; - } - - // regular grid - PlotPainter.setPen ( PlotGridColor ); - PlotPainter.drawLine ( iCurX, 1 + PlotGridFrame.y(), - iCurX, PlotGridFrame.bottom() + iBottomExtraTickLen ); - - // different grid width for weekends (overwrite regular grid) - if ( ( curXAxisDate.dayOfWeek() == 6 ) || // check for Saturday - ( curXAxisDate.dayOfWeek() == 7 ) ) // check for Sunday - { - const int iGridWidthWeekendHalf = iGridWidthWeekend / 2; - - PlotPainter.setPen ( QPen ( PlotGridColor, iGridWidthWeekend ) ); - PlotPainter.drawLine ( iCurX, 1 + PlotGridFrame.y() + iGridWidthWeekendHalf, - iCurX, PlotGridFrame.bottom() - iGridWidthWeekendHalf ); - } - } - - // grid (ticks) for y-axis, draw iNumTicksY - 2 grid lines and - // iNumTicksY - 1 text labels (the lowest grid line is the grid frame) - iYSpace = PlotGridFrame.height() / ( iNumTicksY - 1 ); - for ( i = 0; i < ( iNumTicksY - 1 ); i++ ) - { - const int iCurY = PlotGridFrame.y() + iYSpace * ( i + 1 ); - - // text - PlotPainter.setPen ( PlotTextColor ); - PlotPainter.setFont ( AxisFont ); - PlotPainter.drawText ( QPoint ( - PlotGridFrame.x() + iTextOffsetToGrid, - iCurY - iTextOffsetToGrid ), - QString ( "%1:00" ).arg ( - ( iYAxisEnd - iYAxisStart ) / ( iNumTicksY - 1 ) * - ( ( iNumTicksY - 2 ) - i ) ) ); - - // grid (do not overwrite frame) - if ( i < ( iNumTicksY - 2 ) ) - { - PlotPainter.setPen ( PlotGridColor ); - PlotPainter.drawLine ( PlotGridFrame.x(), iCurY, - PlotGridFrame.right(), iCurY ); - } - } -} - -void CHistoryGraph::AddMarker ( const SHistoryData& curHistoryData ) -{ - // calculate x-axis offset (difference of days compared to - // current date) - const int iXAxisOffs = - curDate.daysTo ( curHistoryData.DateTime.date() ); - - // check range, if out of range, do not plot anything - if ( -iXAxisOffs > ( iNumTicksX - 1 ) ) - { - return; - } - - // calculate y-axis offset (consider hours and minutes) - const double dYAxisOffs = 24 - curHistoryData.DateTime.time().hour() - - static_cast ( curHistoryData.DateTime.time().minute() ) / 60; - - // calculate the actual point in the graph (in pixels) - const QPoint curPoint ( - PlotGridFrame.x() + static_cast ( dXSpace * ( iNumTicksX + iXAxisOffs ) ), - PlotGridFrame.y() + static_cast ( static_cast ( - PlotGridFrame.height() ) / ( iYAxisEnd - iYAxisStart ) * dYAxisOffs ) ); - - // create painter for plot - QPainter PlotPainter ( &PlotPixmap ); - - // we use different markers for new connection and server stop items - switch ( curHistoryData.Type ) - { - case HIT_SERVER_STOP: - PlotPainter.setPen ( QPen ( QBrush ( PlotMarkerStopColor ), - iMarkerSizeServSt ) ); - break; - - case HIT_LOCAL_CONNECTION: - PlotPainter.setPen ( QPen ( QBrush ( PlotMarkerNewLocalColor ), - iMarkerSizeNewCon ) ); - break; - - case HIT_REMOTE_CONNECTION: - PlotPainter.setPen ( QPen ( QBrush ( PlotMarkerNewColor ), - iMarkerSizeNewCon ) ); - break; - } - PlotPainter.drawPoint ( curPoint ); -} - -void CHistoryGraph::Save ( const QString sFileName ) -{ - // save plot as a file - PlotPixmap.save ( sFileName, "JPG", 90 ); -} - -void CHistoryGraph::Add ( const QDateTime& newDateTime, - const QHostAddress ClientInetAddr ) -{ - if ( bDoHistory ) - { - // add element to history, distinguish between a local connection - // and a remote connection - if ( ( ClientInetAddr == QHostAddress ( "127.0.0.1" ) ) || - ( ClientInetAddr.toString().left ( 7 ).compare ( "192.168" ) == 0 ) ) - { - // local connection - Add ( newDateTime, CHistoryGraph::HIT_LOCAL_CONNECTION ); - } - else - { - // remote connection - Add ( newDateTime, CHistoryGraph::HIT_REMOTE_CONNECTION ); - } - } -} - -void CHistoryGraph::Add ( const QDateTime& newDateTime, - const EHistoryItemType curType ) -{ - if ( bDoHistory ) - { - // create and add new element in FIFO - SHistoryData curHistoryData; - curHistoryData.DateTime = newDateTime; - curHistoryData.Type = curType; - - vHistoryDataFifo.Add ( curHistoryData ); - } -} - -void CHistoryGraph::Update() -{ - if ( bDoHistory ) - { - int i; - - // store current date for reference - curDate = QDate::currentDate(); - - // get oldest date in history - QDate oldestDate = curDate.addDays ( 1 ); // one day in the future - const int iNumItemsForHistory = vHistoryDataFifo.Size(); - for ( i = 0; i < iNumItemsForHistory; i++ ) - { - // only use valid dates - if ( vHistoryDataFifo[i].DateTime.date().isValid() ) - { - if ( vHistoryDataFifo[i].DateTime.date() < oldestDate ) - { - oldestDate = vHistoryDataFifo[i].DateTime.date(); - } - } - } - const int iNumDaysInHistory = -curDate.daysTo ( oldestDate ) + 1; - - // draw frame of the graph - DrawFrame ( iNumDaysInHistory ); - - // add markers - for ( i = 0; i < iNumItemsForHistory; i++ ) - { - // only use valid dates - if ( vHistoryDataFifo[i].DateTime.date().isValid() ) - { - AddMarker ( vHistoryDataFifo[i] ); - } - } - - // save graph as picture in file - Save ( sFileName ); - } -} - - // Server logging -------------------------------------------------------------- CServerLogging::~CServerLogging() { @@ -339,7 +52,7 @@ void CServerLogging::EnableHistory ( const QString& strHistoryFileName ) } else { - HistoryGraph.Start ( strHistoryFileName ); + JpegHistoryGraph.Start ( strHistoryFileName ); } } @@ -354,7 +67,7 @@ void CServerLogging::AddNewConnection ( const QHostAddress& ClientInetAddr ) *this << strLogStr; // in log file // add element to history - HistoryGraph.Add ( QDateTime::currentDateTime(), ClientInetAddr ); + JpegHistoryGraph.Add ( QDateTime::currentDateTime(), ClientInetAddr ); SvgHistoryGraph.Add ( QDateTime::currentDateTime(), ClientInetAddr ); } @@ -368,10 +81,10 @@ void CServerLogging::AddServerStopped() *this << strLogStr; // in log file // add element to history and update on server stop - HistoryGraph.Add ( QDateTime::currentDateTime(), CHistoryGraph::HIT_SERVER_STOP ); - SvgHistoryGraph.Add ( QDateTime::currentDateTime(), CHistoryGraph::HIT_SERVER_STOP ); + JpegHistoryGraph.Add ( QDateTime::currentDateTime(), CJpegHistoryGraph::HIT_SERVER_STOP ); + SvgHistoryGraph.Add ( QDateTime::currentDateTime(), CJpegHistoryGraph::HIT_SERVER_STOP ); - HistoryGraph.Update(); + JpegHistoryGraph.Update(); SvgHistoryGraph.Update(); } @@ -425,8 +138,8 @@ void CServerLogging::ParseLogFile ( const QString& strFileName ) if ( strAddress.isEmpty() ) { // server stop - HistoryGraph.Add ( curDateTime, CHistoryGraph::HIT_SERVER_STOP ); - SvgHistoryGraph.Add ( curDateTime, CHistoryGraph::HIT_SERVER_STOP ); + JpegHistoryGraph.Add ( curDateTime, CJpegHistoryGraph::HIT_SERVER_STOP ); + SvgHistoryGraph.Add ( curDateTime, CJpegHistoryGraph::HIT_SERVER_STOP ); } else { @@ -436,7 +149,7 @@ void CServerLogging::ParseLogFile ( const QString& strFileName ) if ( curAddress.setAddress ( strlistCurLine.at ( 2 ).trimmed() ) ) { // new client connection - HistoryGraph.Add ( curDateTime, curAddress ); + JpegHistoryGraph.Add ( curDateTime, curAddress ); SvgHistoryGraph.Add ( curDateTime, curAddress ); } } @@ -444,7 +157,7 @@ void CServerLogging::ParseLogFile ( const QString& strFileName ) } } - HistoryGraph.Update(); + JpegHistoryGraph.Update(); SvgHistoryGraph.Update(); } diff --git a/src/serverlogging.h b/src/serverlogging.h index 4fcb6d5b..649bbdd5 100755 --- a/src/serverlogging.h +++ b/src/serverlogging.h @@ -33,7 +33,7 @@ #include "global.h" #include "util.h" -#include "historygraph.h" +#include "jpeghistorygraph.h" #include "svghistorygraph.h" /* Classes ********************************************************************/ @@ -46,7 +46,6 @@ public: void Start ( const QString& strLoggingFileName ); void EnableHistory ( const QString& strHistoryFileName ); - void EnableSVGHistory ( const QString& strHistoryFileName ); void AddNewConnection ( const QHostAddress& ClientInetAddr ); void AddServerStopped(); void ParseLogFile ( const QString& strFileName ); @@ -55,10 +54,10 @@ protected: void operator<< ( const QString& sNewStr ); QString CurTimeDatetoLogString(); - CHistoryGraph HistoryGraph; - CSvgHistoryGraph SvgHistoryGraph; - bool bDoLogging; - QFile File; + CJpegHistoryGraph JpegHistoryGraph; + CSvgHistoryGraph SvgHistoryGraph; + bool bDoLogging; + QFile File; }; #endif // SERVERLOGGING_H diff --git a/src/svghistorygraph.cpp b/src/svghistorygraph.cpp index 77d0dbc6..d5287320 100755 --- a/src/svghistorygraph.cpp +++ b/src/svghistorygraph.cpp @@ -1,210 +1,51 @@ #include "svghistorygraph.h" CSvgHistoryGraph::CSvgHistoryGraph() : - sFileName ( "" ), - bDoHistory ( false ), - vHistoryDataFifo ( NUM_ITEMS_HISTORY ), - plotCanvasRectX ( 0 ), - plotCanvasRectY ( 0 ), - plotCanvasRectWidth ( 600 ), - plotCanvasRectHeight ( 450 ), - numDays ( 0 ), - iYAxisStart ( 0 ), - iYAxisEnd ( 24 ), - iNumTicksY ( 5 ), - iGridFrameOffset ( 10 ), - iGridWidthWeekend ( 3 ), // should be an odd value - iTextOffsetToGrid ( 3 ), - iXAxisTextHeight ( 22 ), - iMarkerSizeNewCon ( 11 ), - iMarkerSizeServSt ( 8 ), - axisFontFamily ( "sans-serif" ), - axisFontWeight ( "60" ), - axisFontSize ( 10 ), - iTextOffsetX ( 18 ), - plotGridFrameX ( plotCanvasRectX + iGridFrameOffset ), - plotGridFrameY ( plotCanvasRectY + iGridFrameOffset ), - plotGridFrameWidth ( plotCanvasRectWidth - 2 * iGridFrameOffset ), - plotGridFrameHeight ( plotCanvasRectHeight - 2 * iGridFrameOffset - iXAxisTextHeight ), - plotGridFrameRight ( plotGridFrameX + plotGridFrameWidth ), - plotGridFrameBottom ( plotGridFrameY + plotGridFrameHeight ), - PlotBackgroundColor ( "white" ), // background - PlotFrameColor ( "black" ), // frame - PlotGridColor ( "gray" ), // grid - PlotTextColor ( "black" ), // text - PlotMarkerNewColor ( "darkCyan" ), // marker for new connection - PlotMarkerNewLocalColor ( "blue" ), // marker for new local connection - PlotMarkerStopColor ( "red" ) // marker for server stop + AHistoryGraph(), + svgImage( "" ), + svgStreamWriter( &svgImage ) { - // set SVG veiwBox to correct size to ensure correct scaling svgRootAttributes.append("viewBox", QString("%1, %2, %3, %4") - .arg(plotCanvasRectX) - .arg(plotCanvasRectY) - .arg(plotCanvasRectWidth) - .arg(plotCanvasRectHeight) + .arg(canvasRectX) + .arg(canvasRectY) + .arg(canvasRectWidth) + .arg(canvasRectHeight) ); svgRootAttributes.append("xmlns", "http://www.w3.org/2000/svg"); svgRootAttributes.append("xmlns:xlink", "http://www.w3.org/1999/xlink"); - // generate plot grid frame rectangle - gridFrameAttributes.append("stroke", QString("%1").arg(PlotFrameColor)); - gridFrameAttributes.append("stroke-width", QString("%1").arg(1)); - gridFrameAttributes.append("style", QString("fill: none;")); - - textAttributes.append("stroke", QString("%1").arg(PlotTextColor)); - textAttributes.append("font-family", axisFontFamily); - textAttributes.append("font-weight", axisFontWeight); - textAttributes.append("font-size", QString("%1").arg(axisFontSize)); - - gridAttributes.append("stroke", QString("%1").arg(PlotGridColor)); - gridAttributes.append("stroke-width", QString("%1").arg(1)); - - gridWeekendAttributes.append("stroke", QString("%1").arg(PlotGridColor)); - gridWeekendAttributes.append("stroke-width", QString("%1").arg(iGridWidthWeekend)); + QTextStream& tsConsoleStream = *( ( new ConsoleWriterFactory() )->get() ); + tsConsoleStream << "CSvgHistoryGraph" << endl; // on console // Connections ------------------------------------------------------------- QObject::connect ( &TimerDailyUpdate, SIGNAL ( timeout() ), this, SLOT ( OnTimerDailyUpdate() ) ); - } -void CSvgHistoryGraph::Start ( const QString& sNewFileName ) +// Override Update to create the fresh SVG stream each time +void CSvgHistoryGraph::Update() { - if ( !sNewFileName.isEmpty() ) + if ( bDoHistory ) { - // save file name - sFileName = sNewFileName; + // create SVG document + svgImage = ""; - // set enable flag - bDoHistory = true; + svgStreamWriter.setAutoFormatting(true); + svgStreamWriter.writeStartDocument(); + svgStreamWriter.writeStartElement("svg"); + svgStreamWriter.writeAttributes(svgRootAttributes); - // enable timer (update once a day) - TimerDailyUpdate.start ( 3600000 * 24 ); - - // initial update (empty graph) - Update(); + AHistoryGraph::Update(); } } -void CSvgHistoryGraph::DrawFrame( QXmlStreamWriter &svgStreamWriter, const unsigned int _numDays ) +void CSvgHistoryGraph::Save ( const QString sFileName ) { - unsigned int i; + svgStreamWriter.writeEndDocument(); - // store number of x-axis ticks (number of days we want to draw - // the history for - numDays = _numDays; - - // Create actual plot region (grid frame) ---------------------------------- - rect(svgStreamWriter, plotGridFrameX, plotGridFrameY, plotGridFrameWidth, plotGridFrameHeight, gridFrameAttributes); - - // calculate step for x-axis ticks so that we get the desired number of - // ticks -> 5 ticks - -// TODO the following equation does not work as expected but results are acceptable - - // we want to have "floor ( numDays / 5 )" which is the same as - // "numDays / 5" since "numDays" is an integer variable - const unsigned int iXAxisTickStep = numDays / 5 + 1; - - // grid (ticks) for x-axis - dayXSpace = static_cast ( plotCanvasRectWidth / ( numDays + 1 ) ); - for ( i = 0; i < numDays; i++ ) - { - unsigned int iBottomExtraTickLen = 0; - const unsigned int iCurX = plotGridFrameX + static_cast ( dayXSpace * ( i + 1 ) ); - const QDate curXAxisDate = curDate.addDays ( static_cast(1 + i - numDays) ); - - // text (print only every "iXAxisTickStep" tick) - if ( !( i % iXAxisTickStep ) ) - { - text(svgStreamWriter, static_cast(std::max(0, static_cast(iCurX - iTextOffsetX))), plotGridFrameBottom + iXAxisTextHeight + iTextOffsetToGrid, curXAxisDate.toString ( "dd.MM." ), textAttributes); - - iBottomExtraTickLen = 5; - } - - // regular grid - line(svgStreamWriter, iCurX, 1 + plotGridFrameY, iCurX, plotGridFrameBottom + iBottomExtraTickLen, gridAttributes); - - // different grid width for weekends (overwrite regular grid) - if ( ( curXAxisDate.dayOfWeek() == 6 ) || // check for Saturday - ( curXAxisDate.dayOfWeek() == 7 ) ) // check for Sunday - { - const unsigned int iGridWidthWeekendHalf = iGridWidthWeekend / 2; - - line(svgStreamWriter, iCurX, 1 + plotGridFrameY + iGridWidthWeekendHalf, iCurX, plotGridFrameBottom - iGridWidthWeekendHalf, gridWeekendAttributes); - } - } - - // grid (ticks) for y-axis, draw iNumTicksY - 2 grid lines and - // iNumTicksY - 1 text labels (the lowest grid line is the grid frame) - iYSpace = plotGridFrameHeight / ( iNumTicksY - 1 ); - for ( i = 0; i < ( iNumTicksY - 1 ); i++ ) - { - const unsigned int iCurY = plotGridFrameY + iYSpace * ( i + 1 ); - - // text - text(svgStreamWriter, plotGridFrameX + iTextOffsetToGrid, iCurY - iTextOffsetToGrid, - QString ( "%1:00" ).arg ( ( iYAxisEnd - iYAxisStart ) / ( iNumTicksY - 1 ) * ( ( iNumTicksY - 2 ) - i ) ), - textAttributes ); - - // grid (do not overwrite frame) - if ( i < ( iNumTicksY - 2 ) ) - { - line(svgStreamWriter, plotGridFrameX, iCurY, plotGridFrameRight, iCurY, gridAttributes); - } - } -} - -void CSvgHistoryGraph::AddMarker ( QXmlStreamWriter &svgStreamWriter, const SHistoryData& curHistoryData ) -{ - // calculate x-axis offset (difference of days compared to - // current date) - const int iXAxisOffs = curDate.daysTo ( curHistoryData.DateTime.date() ); - - // check range, if out of range, do not plot anything - if ( -iXAxisOffs > static_cast( numDays - 1 ) ) - { - return; - } - - // calculate y-axis offset (consider hours and minutes) - const double dYAxisOffs = 24 - curHistoryData.DateTime.time().hour() - - static_cast ( curHistoryData.DateTime.time().minute() ) / 60; - - // calculate the actual point in the graph (in pixels) - unsigned int curPointX = plotGridFrameX + ( dayXSpace * static_cast( numDays + iXAxisOffs ) ); - unsigned int curPointY = plotGridFrameY + static_cast ( static_cast ( - plotGridFrameHeight ) / ( iYAxisEnd - iYAxisStart ) * dYAxisOffs ); - - // we use different markers for new connection and server stop items - QXmlStreamAttributes curPointAttibutes; - curPointAttibutes.append("stroke", "0"); - unsigned int wh = 0; - switch ( curHistoryData.Type ) - { - case CHistoryGraph::EHistoryItemType::HIT_SERVER_STOP: - curPointAttibutes.append("fill", PlotMarkerStopColor); - wh = iMarkerSizeServSt; - break; - - case CHistoryGraph::EHistoryItemType::HIT_LOCAL_CONNECTION: - curPointAttibutes.append("fill", PlotMarkerNewLocalColor); - wh = iMarkerSizeNewCon; - break; - - case CHistoryGraph::EHistoryItemType::HIT_REMOTE_CONNECTION: - curPointAttibutes.append("fill", PlotMarkerNewColor); - wh = iMarkerSizeNewCon; - break; - } - rect(svgStreamWriter, curPointX, curPointY, wh, wh, curPointAttibutes); -} - -void CSvgHistoryGraph::Save ( const QString sFileName, const QString& svgImage ) -{ QFile outf (sFileName); if (!outf.open(QFile::WriteOnly)) { throw std::runtime_error( (sFileName + " could not be written. Aborting.").toStdString() ); @@ -214,128 +55,50 @@ void CSvgHistoryGraph::Save ( const QString sFileName, const QString& svgImage ) out << svgImage << endl; } -void CSvgHistoryGraph::Add ( const QDateTime& newDateTime, - const QHostAddress ClientInetAddr ) -{ - if ( bDoHistory ) - { - // add element to history, distinguish between a local connection - // and a remote connection - if ( ( ClientInetAddr == QHostAddress ( "127.0.0.1" ) ) || - ( ClientInetAddr.toString().left ( 7 ).compare ( "192.168" ) == 0 ) ) - { - // local connection - Add ( newDateTime, CHistoryGraph::HIT_LOCAL_CONNECTION ); - } - else - { - // remote connection - Add ( newDateTime, CHistoryGraph::HIT_REMOTE_CONNECTION ); - } - } -} - -void CSvgHistoryGraph::Add ( const QDateTime& newDateTime, - const CHistoryGraph::EHistoryItemType curType ) -{ - if ( bDoHistory ) - { - // create and add new element in FIFO - SHistoryData curHistoryData; - curHistoryData.DateTime = newDateTime; - curHistoryData.Type = curType; - - vHistoryDataFifo.Add ( curHistoryData ); - } -} - -void CSvgHistoryGraph::Update() -{ - if ( bDoHistory ) - { - - int i; - - // store current date for reference - curDate = QDate::currentDate(); - - // get oldest date in history - QDate oldestDate = curDate.addDays ( 1 ); // one day in the future - const int iNumItemsForHistory = vHistoryDataFifo.Size(); - for ( i = 0; i < iNumItemsForHistory; i++ ) - { - // only use valid dates - if ( vHistoryDataFifo[i].DateTime.date().isValid() ) - { - if ( vHistoryDataFifo[i].DateTime.date() < oldestDate ) - { - oldestDate = vHistoryDataFifo[i].DateTime.date(); - } - } - } - - const unsigned int iNumDaysInHistory = static_cast( -curDate.daysTo ( oldestDate ) + 1 ); - - // create SVG document - QString svgImage; - QXmlStreamWriter svgStreamWriter( &svgImage ); - svgStreamWriter.setAutoFormatting(true); - svgStreamWriter.writeStartDocument(); - svgStreamWriter.writeStartElement("svg"); - svgStreamWriter.writeAttributes(svgRootAttributes); - - // draw frame of the graph - DrawFrame ( svgStreamWriter, iNumDaysInHistory ); - - // add markers - for ( i = 0; i < iNumItemsForHistory; i++ ) - { - // only use valid dates - if ( vHistoryDataFifo[i].DateTime.date().isValid() ) - { - AddMarker ( svgStreamWriter, vHistoryDataFifo[i] ); - } - } - - svgStreamWriter.writeEndDocument(); - - // save graph as picture in file - Save ( sFileName, svgImage ); - } -} - -void CSvgHistoryGraph::rect ( QXmlStreamWriter &svgStreamWriter, const unsigned int x, const unsigned int y, const unsigned width, const unsigned height, const QXmlStreamAttributes &attrs ) +void CSvgHistoryGraph::rect ( const unsigned int x, const unsigned int y, const unsigned int width, const unsigned int height ) { svgStreamWriter.writeEmptyElement("rect"); svgStreamWriter.writeAttribute("x", QString("%1").arg(x)); svgStreamWriter.writeAttribute("y", QString("%1").arg(y)); svgStreamWriter.writeAttribute("width", QString("%1").arg(width)); svgStreamWriter.writeAttribute("height", QString("%1").arg(height)); - if (attrs.size() > 0) { - svgStreamWriter.writeAttributes(attrs); - } + svgStreamWriter.writeAttribute("stroke", FrameColor); + svgStreamWriter.writeAttribute("stroke-width", QString("1")); + svgStreamWriter.writeAttribute("style", QString("fill: none;")); } -void CSvgHistoryGraph::line ( QXmlStreamWriter &svgStreamWriter, const unsigned int x1, const unsigned int y1, const unsigned int x2, const unsigned int y2, const QXmlStreamAttributes &attrs ) +void CSvgHistoryGraph::text ( const unsigned int x, const unsigned int y, const QString& value ) +{ + svgStreamWriter.writeStartElement("text"); + svgStreamWriter.writeAttribute("x", QString("%1").arg(x)); + svgStreamWriter.writeAttribute("y", QString("%1").arg(y)); + svgStreamWriter.writeAttribute("stroke", TextColor); + svgStreamWriter.writeAttribute("font-family", axisFontFamily); + svgStreamWriter.writeAttribute("font-weight", axisFontWeight); + svgStreamWriter.writeAttribute("font-size", QString("%1").arg(axisFontSize)); + + svgStreamWriter.writeCharacters( value ); + svgStreamWriter.writeEndElement(); +} + +void CSvgHistoryGraph::line ( const unsigned int x1, const unsigned int y1, const unsigned int x2, const unsigned int y2, const unsigned int strokeWidth ) { svgStreamWriter.writeEmptyElement("line"); svgStreamWriter.writeAttribute("x1", QString("%1").arg(x1)); svgStreamWriter.writeAttribute("y1", QString("%1").arg(y1)); svgStreamWriter.writeAttribute("x2", QString("%1").arg(x2)); svgStreamWriter.writeAttribute("y2", QString("%1").arg(y2)); - if (attrs.size() > 0) { - svgStreamWriter.writeAttributes(attrs); - } + svgStreamWriter.writeAttribute("stroke", GridColor); + svgStreamWriter.writeAttribute("stroke-width", QString("%1").arg(strokeWidth)); } -void CSvgHistoryGraph::text ( QXmlStreamWriter &svgStreamWriter, const unsigned int x, const unsigned int y, const QString &value, const QXmlStreamAttributes &attrs ) +void CSvgHistoryGraph::point ( const unsigned int x, const unsigned int y, const unsigned int size, const QString& colour ) { - svgStreamWriter.writeStartElement("text"); + svgStreamWriter.writeEmptyElement("rect"); svgStreamWriter.writeAttribute("x", QString("%1").arg(x)); svgStreamWriter.writeAttribute("y", QString("%1").arg(y)); - if (attrs.size() > 0) { - svgStreamWriter.writeAttributes(attrs); - } - svgStreamWriter.writeCharacters( value ); - svgStreamWriter.writeEndElement(); + svgStreamWriter.writeAttribute("width", QString("%1").arg(size)); + svgStreamWriter.writeAttribute("height", QString("%1").arg(size)); + svgStreamWriter.writeAttribute("stroke-opacity", "0"); + svgStreamWriter.writeAttribute("fill", colour); } diff --git a/src/svghistorygraph.h b/src/svghistorygraph.h index 7124e440..86ce4f83 100755 --- a/src/svghistorygraph.h +++ b/src/svghistorygraph.h @@ -2,6 +2,7 @@ #define SVGHISTORYGRAPH_H #include "historygraph.h" + #include #include @@ -12,86 +13,29 @@ #endif /* Classes ********************************************************************/ -class CSvgHistoryGraph : public QObject +class CSvgHistoryGraph : public QObject, virtual public AHistoryGraph { Q_OBJECT public: CSvgHistoryGraph(); - void Start ( const QString& sNewFileName ); - void Add ( const QDateTime& newDateTime, const CHistoryGraph::EHistoryItemType curType ); - void Add ( const QDateTime& newDateTime, const QHostAddress ClientInetAddr ); - void Update(); + virtual void Update(); + +protected: + virtual void Save ( const QString sFileName ); + + virtual void rect ( const unsigned int x, const unsigned int y, const unsigned int width, const unsigned int height ); + virtual void text ( const unsigned int x, const unsigned int y, const QString& value ); + virtual void line ( const unsigned int x1, const unsigned int y1, const unsigned int x2, const unsigned int y2, const unsigned int strokeWidth = 1 ); + virtual void point ( const unsigned int x, const unsigned int y, const unsigned int size, const QString& colour ); private: - struct SHistoryData - { - QDateTime DateTime; - CHistoryGraph::EHistoryItemType Type; - }; - void DrawFrame ( QXmlStreamWriter &svgStreamWriter, const unsigned int numDays ); - void AddMarker ( QXmlStreamWriter &svgStreamWriter, const SHistoryData& curHistoryData ); - void Save ( const QString sFileName, const QString& svgImage ); - - void rect ( QXmlStreamWriter &svgStreamWriter, const unsigned int x, const unsigned int y, const unsigned width, const unsigned height, const QXmlStreamAttributes &attrs = QXmlStreamAttributes() ); - void line ( QXmlStreamWriter &svgStreamWriter, const unsigned int x1, const unsigned int y1, const unsigned int x2, const unsigned int y2, const QXmlStreamAttributes &attrs = QXmlStreamAttributes() ); - void text ( QXmlStreamWriter &svgStreamWriter, const unsigned int x, const unsigned int y, const QString &value, const QXmlStreamAttributes &attrs = QXmlStreamAttributes() ); - - QString sFileName; - - bool bDoHistory; - CFIFO vHistoryDataFifo; - - const unsigned int plotCanvasRectX; - const unsigned int plotCanvasRectY; - const unsigned int plotCanvasRectWidth; - const unsigned int plotCanvasRectHeight; - - unsigned int numDays; - - const unsigned int iYAxisStart; - const unsigned int iYAxisEnd; - const unsigned int iNumTicksY; - const unsigned int iGridFrameOffset; - const unsigned int iGridWidthWeekend; - const unsigned int iTextOffsetToGrid; - const unsigned int iXAxisTextHeight; - const unsigned int iMarkerSizeNewCon; - const unsigned int iMarkerSizeServSt; - const QString axisFontFamily; - const QString axisFontWeight; - const unsigned int axisFontSize; - const unsigned int iTextOffsetX; - - const unsigned int plotGridFrameX; - const unsigned int plotGridFrameY; - const unsigned int plotGridFrameWidth; - const unsigned int plotGridFrameHeight; - const unsigned int plotGridFrameRight; - const unsigned int plotGridFrameBottom; - - QString PlotBackgroundColor; - QString PlotFrameColor; - QString PlotGridColor; - QString PlotTextColor; - QString PlotMarkerNewColor; - QString PlotMarkerNewLocalColor; - QString PlotMarkerStopColor; - - double dayXSpace; - unsigned int iYSpace; - - QDate curDate; QXmlStreamAttributes svgRootAttributes; - QXmlStreamAttributes gridFrameAttributes; - QXmlStreamAttributes textAttributes; - QXmlStreamAttributes gridAttributes; - QXmlStreamAttributes gridWeekendAttributes; - QTimer TimerDailyUpdate; + QString svgImage; + QXmlStreamWriter svgStreamWriter; public slots: void OnTimerDailyUpdate() { Update(); } - }; #endif // SVGHISTORYGRAPH_H