From 16d924bf6ce2d4d2646bedc14a803e17f83e5fe8 Mon Sep 17 00:00:00 2001
From: Mark Watkins <jedimark@users.sourceforge.net>
Date: Sat, 12 Oct 2013 17:40:45 +1000
Subject: [PATCH] Implement support for SessionBar in QWebView areas

---
 sleepyhead/daily.cpp      | 167 +++++++++++++++++++++++++-------------
 sleepyhead/daily.h        |  24 ++++++
 sleepyhead/daily.ui       |  49 +----------
 sleepyhead/sessionbar.cpp |  32 +++++++-
 sleepyhead/sessionbar.h   |  16 ++--
 sleepyhead/sleepyhead.pro |   2 +-
 6 files changed, 179 insertions(+), 111 deletions(-)

diff --git a/sleepyhead/daily.cpp b/sleepyhead/daily.cpp
index 0cbb2264..c811f6dd 100644
--- a/sleepyhead/daily.cpp
+++ b/sleepyhead/daily.cpp
@@ -17,6 +17,7 @@
 #include <QSpacerItem>
 #include <QWebFrame>
 #include <QLabel>
+#include <QtUiTools/QUiLoader>
 
 #include <cmath>
 //#include <QPrinter>
@@ -65,22 +66,25 @@ Daily::Daily(QWidget *parent,gGraphView * shared)
     layout->setMargin(0);
     layout->setContentsMargins(0,0,0,0);
 
-    sessbar=new SessionBar(this);
+//    const bool sessbar_under_graphs=false;
+//    if (sessbar_under_graphs) {
+//        ui->sessionBarLayout->addWidget(sessbar,1);
+//    } else {
+//        QLabel *label=new QLabel("The session bar could go here instead??",this);
+//        label->setAlignment(Qt::AlignCenter);
+//        ui->sessionBarLayout->addWidget(label,1);
+//        ui->splitter->insertWidget(2,sessbar);
+//        sessbar->setMaximumHeight(sessbar->height());
+//        sessbar->setMinimumHeight(sessbar->height());
+//    }
 
-    const bool sessbar_under_graphs=false;
-    if (sessbar_under_graphs) {
-        ui->sessionBarLayout->addWidget(sessbar,1);
-    } else {
-        QLabel *label=new QLabel("The session bar could go here instead??",this);
-        label->setAlignment(Qt::AlignCenter);
-        ui->sessionBarLayout->addWidget(label,1);
-        ui->splitter->insertWidget(2,sessbar);
-        sessbar->setMaximumHeight(sessbar->height());
-        sessbar->setMinimumHeight(sessbar->height());
-    }
-    sessbar->setMouseTracking(true);
 
-    connect(sessbar, SIGNAL(toggledSession(Session*)), this, SLOT(doToggleSession(Session*)));
+    webView=new MyWebView(this);
+
+    QWebSettings::globalSettings()->setAttribute(QWebSettings::PluginsEnabled, true);
+
+    ui->tabWidget->insertTab(0,webView,QIcon(),"Details");
+
     ui->graphMainArea->setLayout(layout);
     //ui->graphMainArea->setLayout(layout);
 
@@ -325,11 +329,11 @@ Daily::Daily(QWidget *parent,gGraphView * shared)
 
     ui->calendar->setFirstDayOfWeek(dow);
 
-    ui->tabWidget->setCurrentWidget(ui->details);
+    ui->tabWidget->setCurrentWidget(webView);
 
-    ui->webView->settings()->setFontSize(QWebSettings::DefaultFontSize,QApplication::font().pointSize());
-    ui->webView->page()->setLinkDelegationPolicy(QWebPage::DelegateAllLinks);
-    connect(ui->webView,SIGNAL(linkClicked(QUrl)),this,SLOT(Link_clicked(QUrl)));
+    webView->settings()->setFontSize(QWebSettings::DefaultFontSize,QApplication::font().pointSize());
+    webView->page()->setLinkDelegationPolicy(QWebPage::DelegateAllLinks);
+    connect(webView,SIGNAL(linkClicked(QUrl)),this,SLOT(Link_clicked(QUrl)));
 
     int ews=PROFILE.general->eventWindowSize();
     ui->evViewSlider->setValue(ews);
@@ -359,9 +363,9 @@ Daily::Daily(QWidget *parent,gGraphView * shared)
 Daily::~Daily()
 {
     GraphView->SaveSettings("Daily");
-    disconnect(sessbar, SIGNAL(toggledSession(Session*)), this, SLOT(doToggleSession(Session*)));
+//    disconnect(sessbar, SIGNAL(toggledSession(Session*)), this, SLOT(doToggleSession(Session*)));
 
-    disconnect(ui->webView,SIGNAL(linkClicked(QUrl)),this,SLOT(Link_clicked(QUrl)));
+    disconnect(webView,SIGNAL(linkClicked(QUrl)),this,SLOT(Link_clicked(QUrl)));
     // Save any last minute changes..
     if (previous_date.isValid())
         Unload(previous_date);
@@ -393,7 +397,7 @@ void Daily::Link_clicked(const QUrl &url)
         Session *sess=day->find(sid);
         if (!sess)
             return;
-        int i=ui->webView->page()->mainFrame()->scrollBarMaximum(Qt::Vertical)-ui->webView->page()->mainFrame()->scrollBarValue(Qt::Vertical);
+        int i=webView->page()->mainFrame()->scrollBarMaximum(Qt::Vertical)-webView->page()->mainFrame()->scrollBarValue(Qt::Vertical);
         sess->setEnabled(!sess->enabled());
 
         // Messy, this rewrites both summary & events.. TODO: Write just the session summary file
@@ -401,21 +405,21 @@ void Daily::Link_clicked(const QUrl &url)
 
         // Reload day
         this->LoadDate(previous_date);
-        ui->webView->page()->mainFrame()->setScrollBarValue(Qt::Vertical, ui->webView->page()->mainFrame()->scrollBarMaximum(Qt::Vertical)-i);
+        webView->page()->mainFrame()->setScrollBarValue(Qt::Vertical, webView->page()->mainFrame()->scrollBarMaximum(Qt::Vertical)-i);
         return;
     } else  if (code=="toggleoxisession") { // Enable/Disable Oximetry session
         day=PROFILE.GetDay(previous_date,MT_OXIMETER);
         Session *sess=day->find(sid);
         if (!sess)
             return;
-        int i=ui->webView->page()->mainFrame()->scrollBarMaximum(Qt::Vertical)-ui->webView->page()->mainFrame()->scrollBarValue(Qt::Vertical);
+        int i=webView->page()->mainFrame()->scrollBarMaximum(Qt::Vertical)-webView->page()->mainFrame()->scrollBarValue(Qt::Vertical);
         sess->setEnabled(!sess->enabled());
         // Messy, this rewrites both summary & events.. TODO: Write just the session summary file
         day->machine->Save();
 
         // Reload day
         this->LoadDate(previous_date);
-        ui->webView->page()->mainFrame()->setScrollBarValue(Qt::Vertical, ui->webView->page()->mainFrame()->scrollBarMaximum(Qt::Vertical)-i);
+        webView->page()->mainFrame()->setScrollBarValue(Qt::Vertical, webView->page()->mainFrame()->scrollBarMaximum(Qt::Vertical)-i);
         return;
     } else if (code=="cpap")  {
         day=PROFILE.GetDay(previous_date,MT_CPAP);
@@ -684,6 +688,44 @@ void Daily::graphtogglebutton_toggled(bool b)
     GraphView->updateScale();
     GraphView->redraw();
 }
+
+MyWebPage::MyWebPage(QObject *parent):
+   QWebPage(parent)
+{
+   // Enable plugin support
+   settings()->setAttribute(QWebSettings::PluginsEnabled, true);
+}
+
+QObject *MyWebPage::createPlugin(const QString &classid, const QUrl &url, const QStringList & paramNames, const QStringList & paramValues)
+{
+    Q_UNUSED(paramNames)
+    Q_UNUSED(paramValues)
+   // Create the widget using QUiLoader.
+   // This means that the widgets don't need to be registered
+   // with the meta object system.
+   // On the other hand, non-gui objects can't be created this
+   // way. When we'd like to create non-visual objects in
+   // Html to use them via JavaScript, we'd use a different
+   // mechanism than this.
+    if (classid=="SessionBar") {
+        return mainwin->getDaily()->sessionBar();
+    }
+    QUiLoader loader;
+//   int i=5;
+    return loader.createWidget(classid, view());
+}
+
+MyWebView::MyWebView(QWidget *parent):
+   QWebView(parent),
+   m_page(this)
+{
+   // Set the page of our own PageView class, MyPageView,
+   // because only objects of this class will handle
+   // object-tags correctly.
+   setPage(&m_page);
+}
+
+
 void Daily::Load(QDate date)
 {
     static Day * lastcpapday=NULL;
@@ -943,8 +985,8 @@ void Daily::Load(QDate date)
             if ((hours > 0) && PROFILE.appearance->graphSnapshots()) {  // AHI Pie Chart
                 if ((oai+hi+cai+uai+rei+fli)>0) {
                     html+="<tr><td colspan=5 align=center>&nbsp;</td></tr>";
-                    html+=QString("<tr><td colspan=4 align=center><b>%1</b></td></tr>").arg(tr("Event Breakdown"));
                     html+="<tr><td colspan=5 align=center><hr/></td></tr>";
+                    html+=QString("<tr><td colspan=4 align=center><b>%1</b></td></tr>").arg(tr("Event Breakdown"));
                     GAHI->setShowTitle(false);
 
                     QPixmap pixmap=GAHI->renderPixmap(150,150,false);
@@ -996,10 +1038,10 @@ void Daily::Load(QDate date)
     else if (ST_mid==ST_PERC) midname=tr("Med");
 
     if ((cpap && !isBrick && (cpap->hours()>0)) || oxi) {
-        html+="<tr height='2'><td colspan=5>&nbsp;</td></tr>\n";
+       // html+="<tr height='2'><td colspan=5>&nbsp;</td></tr>\n";
 
-        html+=QString("<tr><td colspan=5 align=center><b>%1</b></td></tr>\n").arg(tr("Statistics"));
         html+="<tr height='2'><td colspan=5><hr></td></tr>\n";
+        html+=QString("<tr><td colspan=5 align=center><b>%1</b></td></tr>\n").arg(tr("Statistics"));
         html+=QString("<tr><td><b>%1</b></td><td><b>%2</b></td><td><b>%3</b></td><td><b>%4</b></td><td><b>%5</b></td></tr>")
                 .arg(STR_TR_Channel)
                 .arg(STR_TR_Min)
@@ -1120,9 +1162,9 @@ void Daily::Load(QDate date)
 
     }
     if (oxi && oxi->hasEnabledSessions()) {
-        html+="<tr><td colspan=5 align=center>&nbsp;</td></tr>";
-        html+=QString("<tr><td colspan=5 align=center><b>%1</b></td></tr>\n").arg(tr("Oximeter Information"));
         html+="<tr><td colspan=5 align=center><hr/></td></tr>";
+        html+=QString("<tr><td colspan=5 align=center><b>%1</b></td></tr>\n").arg(tr("Oximeter Information"));
+        html+="<tr><td colspan=5 align=center>&nbsp;</td></tr>";
         html+="<tr><td colspan=5 align=center>"+oxi->machine->properties[STR_PROP_Brand]+" "+oxi->machine->properties[STR_PROP_Model]+"</td></tr>\n";
         html+="<tr><td colspan=5 align=center>&nbsp;</td></tr>";
         html+=QString("<tr><td colspan=5 align=center>%1: %2 (%3)\%</td></tr>").arg(tr("SpO2 Desaturations")).arg(oxi->count(OXI_SPO2Drop)).arg((100.0/oxi->hours()) * (oxi->sum(OXI_SPO2Drop)/3600.0),0,'f',2);
@@ -1131,9 +1173,9 @@ void Daily::Load(QDate date)
     }
 
     if (cpap && cpap->hasEnabledSessions()) {
-        html+="<tr><td colspan=5>&nbsp;</td></tr>";
-        html+=QString("<tr><td colspan=5 align=center><b>%1</b></td></tr>").arg(tr("Machine Settings"));
         html+="<tr><td colspan=5><hr height=2></td></tr>";
+        html+=QString("<tr><td colspan=5 align=center><b>%1</b></td></tr>").arg(tr("Machine Settings"));
+        html+="<tr><td colspan=5>&nbsp;</td></tr>";
         int i=cpap->settings_max(CPAP_PresReliefType);
         int j=cpap->settings_max(CPAP_PresReliefSet);
         QString flexstr=(i>1) ? schema::channel[CPAP_PresReliefType].option(i)+" x"+QString::number(j) : STR_TR_None;
@@ -1154,9 +1196,19 @@ void Daily::Load(QDate date)
 
     if (cpap || oxi) {
         html+="<table cellpadding=0 cellspacing=0 border=0 width=100%>";
-        html+="<tr><td colspan=5 align=center>&nbsp;</td></tr>";
-        html+=QString("<tr><td colspan=4 align=center><b>"+tr("Session Information")+"</b></td></tr>");
         html+="<tr><td colspan=5><hr/></td></tr>";
+        html+=QString("<tr><td colspan=5 align=center><b>"+tr("Session Information")+"</b></td></tr>");
+        html+="<tr><td colspan=5 align=center>&nbsp;</td></tr>";
+        html+=QString("<tr><td colspan=5 align=center>"
+        "<object type=\"application/x-qt-plugin\" classid=\"SessionBar\" name=\"sessbar\" height=40 width=100%")+"></object>";
+                "<script>"
+                "sessbar.show();"
+                "</script>"
+                //                   "sessionbar.setGridVisible(true);"
+                //                   "calendar.setCurrentPage(1985, 5);"
+        "</td></tr>"
+                ;
+
         QDateTime fd,ld;
         bool corrupted_waveform=false;
         QString tooltip;
@@ -1260,7 +1312,29 @@ void Daily::Load(QDate date)
     }
     html+="</body></html>";
 
-    ui->webView->setHtml(html);
+    QColor cols[]={
+        QColor("gold"),
+        QColor("light blue"),
+        QColor("light green"),
+        QColor("purple"),
+        QColor("red"),
+    };
+    const int maxcolors=sizeof(cols)/sizeof(QColor);
+    QVector<Session *>::iterator i;
+
+    // WebView trashes it without asking.. :(
+    sessbar=new SessionBar(this);
+    sessbar->setMouseTracking(true);
+    connect(sessbar, SIGNAL(toggledSession(Session*)), this, SLOT(doToggleSession(Session*)));
+    int c=0;
+    for (i=cpap->begin();i!=cpap->end();++i) {
+        Session * s=*i;
+        sessbar->add(s, cols[c % maxcolors]);
+        c++;
+    }
+    //sessbar->update();
+
+    webView->setHtml(html);
 
     ui->JournalNotes->clear();
 
@@ -1546,25 +1620,8 @@ Session * Daily::GetJournalSession(QDate date) // Get the first journal session
 void Daily::UpdateCPAPGraphs(Day *day)
 {
     //if (!day) return;
-    QColor cols[]={
-        QColor("gold"),
-        QColor("light blue"),
-        QColor("light green"),
-        QColor("purple"),
-        QColor("red"),
-    };
-    const int maxcolors=sizeof(cols)/sizeof(QColor);
     if (day) {
         day->OpenEvents();
-        QVector<Session *>::iterator i;
-        sessbar->clear();
-        int c=0;
-        for (i=day->begin();i!=day->end();++i) {
-            Session * s=*i;
-            sessbar->add(s, cols[c % maxcolors]);
-            c++;
-        }
-        sessbar->update();
     }
     for (QList<Layer *>::iterator g=CPAPData.begin();g!=CPAPData.end();g++) {
         (*g)->SetDay(day);
@@ -1948,10 +2005,10 @@ void Daily::on_ouncesSpinBox_editingFinished()
 
 QString Daily::GetDetailsText()
 {
-    ui->webView->triggerPageAction(QWebPage::SelectAll);
-    QString text=ui->webView->page()->selectedText();
-    ui->webView->triggerPageAction(QWebPage::MoveToEndOfDocument);
-    ui->webView->triggerPageAction(QWebPage::SelectEndOfDocument);
+    webView->triggerPageAction(QWebPage::SelectAll);
+    QString text=webView->page()->selectedText();
+    webView->triggerPageAction(QWebPage::MoveToEndOfDocument);
+    webView->triggerPageAction(QWebPage::SelectEndOfDocument);
     return text;
 }
 
diff --git a/sleepyhead/daily.h b/sleepyhead/daily.h
index d8844b2e..d033a226 100644
--- a/sleepyhead/daily.h
+++ b/sleepyhead/daily.h
@@ -18,6 +18,8 @@
 #include <QtOpenGL/QGLContext>
 #include <QScrollBar>
 #include <QTableWidgetItem>
+#include <QWebView>
+#include <QWebPage>
 #include "Graphs/gSummaryChart.h"
 
 #include <SleepLib/profiles.h>
@@ -31,6 +33,25 @@ namespace Ui {
     class Daily;
 }
 
+class MyWebPage:public QWebPage
+{
+Q_OBJECT
+public:
+    MyWebPage(QObject *parent = 0);
+protected:
+    QObject *createPlugin(const QString & classid, const QUrl & url, const QStringList & paramNames, const QStringList & paramValues);
+};
+
+class MyWebView:public QWebView
+{
+   Q_OBJECT
+   private:
+      MyWebPage m_page;
+   public:
+      MyWebView(QWidget *parent = 0);
+};
+
+
 
 class MainWindow;
 
@@ -102,6 +123,7 @@ public:
         \returns gGraph * object containing this chart
         */
     gGraph * eventBreakdownPie() { return GAHI; }
+    QWidget * sessionBar() { return sessbar; }
 private slots:
 
     /*! \fn on_calendar_currentPageChanged(int year, int month);
@@ -299,6 +321,8 @@ private:
 
     SessionBar * sessbar;
 
+    MyWebView * webView;
+
     bool ZombieMeterMoved;
     bool BookmarksChanged;
 };
diff --git a/sleepyhead/daily.ui b/sleepyhead/daily.ui
index 64a2190b..43d67af9 100644
--- a/sleepyhead/daily.ui
+++ b/sleepyhead/daily.ui
@@ -271,46 +271,6 @@
        <property name="movable">
         <bool>true</bool>
        </property>
-       <widget class="QWidget" name="details">
-        <attribute name="title">
-         <string>Details</string>
-        </attribute>
-        <layout class="QHBoxLayout" name="horizontalLayout_8">
-         <property name="spacing">
-          <number>0</number>
-         </property>
-         <property name="leftMargin">
-          <number>0</number>
-         </property>
-         <property name="topMargin">
-          <number>0</number>
-         </property>
-         <property name="rightMargin">
-          <number>0</number>
-         </property>
-         <property name="bottomMargin">
-          <number>0</number>
-         </property>
-         <item>
-          <widget class="QWebView" name="webView">
-           <property name="sizePolicy">
-            <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
-             <horstretch>0</horstretch>
-             <verstretch>0</verstretch>
-            </sizepolicy>
-           </property>
-           <property name="cursor">
-            <cursorShape>IBeamCursor</cursorShape>
-           </property>
-           <property name="url">
-            <url>
-             <string>about:blank</string>
-            </url>
-           </property>
-          </widget>
-         </item>
-        </layout>
-       </widget>
        <widget class="QWidget" name="events">
         <attribute name="title">
          <string>Events</string>
@@ -838,7 +798,7 @@
            </widget>
           </item>
           <item>
-           <layout class="QHBoxLayout" name="sessionBarLayout" stretch="">
+           <layout class="QHBoxLayout" name="sessionBarLayout">
             <property name="sizeConstraint">
              <enum>QLayout::SetMaximumSize</enum>
             </property>
@@ -882,13 +842,6 @@
    </item>
   </layout>
  </widget>
- <customwidgets>
-  <customwidget>
-   <class>QWebView</class>
-   <extends>QWidget</extends>
-   <header>QtWebKitWidgets/QWebView</header>
-  </customwidget>
- </customwidgets>
  <resources>
   <include location="Resources.qrc"/>
  </resources>
diff --git a/sleepyhead/sessionbar.cpp b/sleepyhead/sessionbar.cpp
index 7eb36a50..b8c9a56b 100644
--- a/sleepyhead/sessionbar.cpp
+++ b/sleepyhead/sessionbar.cpp
@@ -7,14 +7,44 @@
 
 #include "sessionbar.h"
 
+SBSeg::SBSeg()
+{
+    session=NULL;
+    color=QColor();
+    highlight=false;
+}
+
+SBSeg::SBSeg(Session * sess, QColor col)
+{
+    session=sess;
+    color=col;
+    highlight=false;
+}
+
+//SBSeg::SBSeg(const SBSeg & a)
+//{
+//    session=(Session *)a.session;
+//    color=a.color;
+//    highlight=a.highlight;
+//}
+
 SessionBar::SessionBar(QWidget *parent) :
     QWidget(parent)
 {
     timer.setParent(this);
 }
+//SessionBar::SessionBar(const SessionBar & copy)
+//    :QWidget(this)
+//{
+//    timer.setParent(this);
+//    QList<SBSeg>::const_iterator i;
+//    for (i=copy.segments.begin();i!=copy.segments.end();++i) {
+//        segments.push_back(*i);
+//    }
+//}
+
 SessionBar::~SessionBar()
 {
-
 }
 void SessionBar::updateTimer()
 {
diff --git a/sleepyhead/sessionbar.h b/sleepyhead/sessionbar.h
index e2138f1d..b2a8741e 100644
--- a/sleepyhead/sessionbar.h
+++ b/sleepyhead/sessionbar.h
@@ -12,13 +12,13 @@ typedef qint64 SegType;
 
 class SBSeg {
 public:
-    SBSeg() { session=NULL; color=QColor(); highlight=false; }
-    SBSeg(Session * sess, QColor col) { session=sess; color=col; highlight=false; }
-    SBSeg(const SBSeg & a) { session=a.session; color=a.color; highlight=a.highlight; }
+    SBSeg();
+    SBSeg(Session * sess, QColor col);
+//    SBSeg(const SBSeg & a);
 
-    Session * session;
     QColor color;
     bool highlight;
+    Session * session;
 };
 
 
@@ -27,6 +27,9 @@ class SessionBar : public QWidget
     Q_OBJECT
 public:
     SessionBar(QWidget *parent = 0);
+//    // Q_DECLARE_METATYPE requires a copy-constructor
+  //  SessionBar(const SessionBar &);
+
     virtual ~SessionBar();
     void clear() { segments.clear(); }
     void add(Session * sess, QColor col) { if (sess) segments.push_back(SBSeg(sess,col)); }
@@ -39,11 +42,12 @@ protected:
     void paintEvent(QPaintEvent * event);
     void mouseMoveEvent(QMouseEvent *);
     void mousePressEvent(QMouseEvent *);
-
-    QList<SBSeg> segments;
     SegType min();
     SegType max();
+
+    QList<SBSeg> segments;
     QTimer timer;
 };
+//Q_DECLARE_METATYPE(SessionBar)
 
 #endif
diff --git a/sleepyhead/sleepyhead.pro b/sleepyhead/sleepyhead.pro
index 0055a482..bbbcf219 100644
--- a/sleepyhead/sleepyhead.pro
+++ b/sleepyhead/sleepyhead.pro
@@ -4,7 +4,7 @@
 #
 #-------------------------------------------------
 
-QT += core gui opengl network xml
+QT += core gui opengl network xml uitools
 
 greaterThan(QT_MAJOR_VERSION,4) {
     QT += widgets webkitwidgets