[tor-commits] [vidalia-plugins/master] Add bandwidth graph implementation as a plugin

chiiph at torproject.org chiiph at torproject.org
Fri Jul 20 23:46:40 UTC 2012


commit f64298fbeb7cc576f43bb00f3c0b6715dc63d385
Author: Tomás Touceda <chiiph at torproject.org>
Date:   Fri Jul 20 15:14:26 2012 -0300

    Add bandwidth graph implementation as a plugin
---
 bwgraph/bwgraph.js    |  149 +++++++++++++++
 bwgraph/bwgraph.ui    |  485 +++++++++++++++++++++++++++++++++++++++++++++++++
 bwgraph/graphframe.js |  297 ++++++++++++++++++++++++++++++
 bwgraph/info.xml      |   11 +
 4 files changed, 942 insertions(+), 0 deletions(-)

diff --git a/bwgraph/bwgraph.js b/bwgraph/bwgraph.js
new file mode 100644
index 0000000..565d6a0
--- /dev/null
+++ b/bwgraph/bwgraph.js
@@ -0,0 +1,149 @@
+importExtension("qt");
+importExtension("qt.core");
+importExtension("qt.gui");
+importExtension("qt.uitools");
+
+var bwgraph = {
+    From: "From",
+    Sent: "Sent",
+    Recv: "Recv",
+
+    SETTING_DORECV: "DoRecv",
+    SETTING_DOSEND: "DoSend",
+    SETTING_ALWAYS_ON_TOP: "AlwaysOnTop",
+    SETTING_STYLE: "GraphStyle",
+
+    start: function() {
+        vdebug("Bwhistory at start");
+        torControl["bandwidthUpdate(quint64, quint64)"].connect(this, this.saveBandwidth);
+        this.createGUI();
+        this.loadSettings();
+
+        this.recv = parseInt(this.tab.getSetting(this.Sent, 0));
+        this.sent = parseInt(this.tab.getSetting(this.Recv, 0));
+        this.from = this.tab.getSetting(this.From, "");
+
+        if(this.from.length == 0)
+            this.from = QDateTime.currentDateTime().toString();
+    },
+
+    saveBandwidth: function(recv, sent) {
+        this.recv += recv;
+        this.sent += sent;
+
+        this.tab.saveSetting(this.Recv, this.recv.toString());
+        this.tab.saveSetting(this.Sent, this.sent.toString());
+        this.tab.saveSetting(this.From, this.from);
+
+        this.lblFrom.text = this.from;
+        this.lblSent.text = (this.sent/1024/1024).toFixed(4).toString() + " <b>Mb/s</b>";
+        this.lblRecv.text = (this.recv/1024/1024).toFixed(4).toString() + " <b>Mb/s</b>";
+        this.frame.addPoints(recv/1024.0, sent/1024.0);
+    },
+
+    resetCounters: function() {
+        this.recv = 0;
+        this.sent = 0;
+        this.from = QDateTime.currentDateTime().toString();
+        this.saveBandwidth(0,0);
+    },
+
+    createGUI: function() {
+        this.tab = new VidaliaTab("Bandwidth Graph", "BandwidthGraph");
+
+        var file = new QFile(pluginPath+"/bwgraph/bwgraph.ui");
+        var loader = new QUiLoader(this.tab);
+        file.open(QIODevice.ReadOnly);
+        this.widget = loader.load(file);
+        var layout = new QVBoxLayout(this.tab);
+        vdebug(layout);
+        layout.sizeConstraint = QLayout.SetMinAndMaxSize;
+        layout.addWidget(this.widget, 100, Qt.AlignCenter);
+        this.tab.setLayout(layout);
+        file.close();
+
+        this.grpBandwidth = this.widget.children()[findWidget(this.widget, "grpBandwidth")];
+
+        var graphFrame = this.widget.children()[findWidget(this.widget, "graphFrame")];
+        var graphLayout = graphFrame.children()[findWidget(graphFrame, "graphLayout")];
+
+        this.frame = new GraphFrame();
+        graphLayout.addWidget(this.frame, 1000, Qt.AlignLeft);
+
+        this.btnHistory = this.widget.children()[findWidget(this.widget, "btnHistory")];
+        this.btnSettings = this.widget.children()[findWidget(this.widget, "btnSettings")];
+        this.btnReset = this.widget.children()[findWidget(this.widget, "btnReset")];
+
+        this.frmSettings = this.widget.children()[findWidget(this.widget, "frmSettings")];
+        this.btnSaveSettings = this.frmSettings.children()[findWidget(this.frmSettings, "btnSaveSettings")];
+        this.btnCancelSettings = this.frmSettings.children()[findWidget(this.frmSettings, "btnCancelSettings")];
+        this.cmbGraphStyle = this.frmSettings.children()[findWidget(this.frmSettings, "cmbGraphStyle")];
+        this.chkReceiveRate = this.frmSettings.children()[findWidget(this.frmSettings, "chkReceiveRate")];
+        this.chkSendRate = this.frmSettings.children()[findWidget(this.frmSettings, "chkSendRate")];
+        this.chkAlwaysOnTop = this.frmSettings.children()[findWidget(this.frmSettings, "chkAlwaysOnTop")];
+
+        this.lblFrom = this.grpBandwidth.children()[findWidget(this.grpBandwidth, "lblFrom")];
+        this.lblSent = this.grpBandwidth.children()[findWidget(this.grpBandwidth, "lblSent")];
+        this.lblRecv = this.grpBandwidth.children()[findWidget(this.grpBandwidth, "lblRecv")];
+        this.btnResetHistory = this.grpBandwidth.children()[findWidget(this.grpBandwidth, "btnResetHistory")];
+
+        this.lblFrom.text = this.from;
+        this.lblSent.text = (this.sent/1024/1024).toFixed(4).toString() + " <b>Mb/s</b>";
+        this.lblRecv.text = (this.recv/1024/1024).toFixed(4).toString() + " <b>Mb/s</b>";
+
+        this.btnResetHistory["clicked()"].connect(this, this.resetCounters);
+
+        this.btnHistory["toggled(bool)"].connect(this, this.toggleHistory);
+        this.btnSettings["toggled(bool)"].connect(this, this.toggleSettings);
+        this.toggleHistory(false);
+        this.toggleSettings(false);
+
+        this.btnReset["clicked()"].connect(this.frame, this.frame.resetGraph);
+        this.btnSaveSettings["clicked()"].connect(this, this.saveSettings);
+    },
+
+    saveSettings: function() {
+        vdebug("Bwhistory at saveSettings");
+        this.tab.saveSetting(this.SETTING_DORECV, (this.chkReceiveRate.checkState() == Qt.Checked) ? "true" : "false");
+        this.tab.saveSetting(this.SETTING_DOSEND, (this.chkSendRate.checkState() == Qt.Checked) ? "true" : "false");
+        this.tab.saveSetting(this.SETTING_STYLE, this.cmbGraphStyle.currentIndex);
+        this.tab.saveSetting(this.SETTING_ALWAYS_ON_TOP, (this.chkAlwaysOnTop.checkState() == Qt.Checked) ? "true" : "false");
+        this.frame.graphStyle = this.cmbGraphStyle.currentIndex;
+        this.frame.showRecv = (this.chkReceiveRate.checkState() == Qt.Checked);
+        this.frame.showSend = (this.chkSendRate.checkState() == Qt.Checked);
+        this.toggleSettings(false);
+    },
+
+    loadSettings: function() {
+        vdebug("Bwhistory at loadSettings");
+        var dorecv = this.tab.getSetting(this.SETTING_DORECV, "true") != "false";
+        var dosend = this.tab.getSetting(this.SETTING_DOSEND, "true") != "false";
+        this.frame.graphStyle = this.tab.getSetting(this.SETTING_STYLE, 0);
+        var alwaysontop = this.tab.getSetting(this.SETTING_ALWAYS_ON_TOP, "false") != "false";
+
+        this.chkReceiveRate.setCheckState(dorecv ? Qt.Checked : Qt.Unchecked);
+        this.chkSendRate.setCheckState(dosend ? Qt.Checked : Qt.Unchecked);
+        this.chkAlwaysOnTop.setCheckState(alwaysontop ? Qt.Checked : Qt.Unchecked);
+        this.cmbGraphStyle.currentIndex = this.frame.graphStyle;
+        this.frame.showRecv = dorecv;
+        this.frame.showSend = dosend;
+    },
+
+    buildGUI: function() {
+        vdebug("Bwhistory at buildGUI");
+        return this.tab;
+    },
+
+    toggleHistory: function(toggle) {
+      this.grpBandwidth.setVisible(toggle);
+    },
+
+    toggleSettings: function(toggle) {
+      this.frmSettings.setVisible(toggle);
+    },
+
+    stop: function() {
+        vdebug("Bwhistory at stop");
+        this.saveBandwidth(0,0);
+    },
+};
diff --git a/bwgraph/bwgraph.ui b/bwgraph/bwgraph.ui
new file mode 100644
index 0000000..967ceda
--- /dev/null
+++ b/bwgraph/bwgraph.ui
@@ -0,0 +1,485 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Form</class>
+ <widget class="QWidget" name="Form">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>548</width>
+    <height>499</height>
+   </rect>
+  </property>
+  <property name="sizePolicy">
+   <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+    <horstretch>0</horstretch>
+    <verstretch>0</verstretch>
+   </sizepolicy>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <layout class="QGridLayout" name="gridLayout_3">
+   <item row="3" column="0">
+    <widget class="QGroupBox" name="grpBandwidth">
+     <property name="title">
+      <string>Bandwidth history</string>
+     </property>
+     <layout class="QGridLayout" name="gridLayout">
+      <item row="2" column="1" colspan="2">
+       <widget class="QLabel" name="lblSent">
+        <property name="text">
+         <string>TextLabel</string>
+        </property>
+       </widget>
+      </item>
+      <item row="2" column="0">
+       <widget class="QLabel" name="lblSentLabel">
+        <property name="text">
+         <string><b>Data Sent:</b></string>
+        </property>
+        <property name="alignment">
+         <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+        </property>
+       </widget>
+      </item>
+      <item row="3" column="1" colspan="2">
+       <widget class="QLabel" name="lblRecv">
+        <property name="text">
+         <string>TextLabel</string>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="0">
+       <widget class="QLabel" name="lblFromLabel">
+        <property name="text">
+         <string><b>Since:</b></string>
+        </property>
+        <property name="alignment">
+         <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+        </property>
+       </widget>
+      </item>
+      <item row="3" column="0">
+       <widget class="QLabel" name="lblSentLabel_2">
+        <property name="text">
+         <string><b>Data Recieved:</b></string>
+        </property>
+        <property name="alignment">
+         <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+        </property>
+       </widget>
+      </item>
+      <item row="5" column="2">
+       <widget class="QPushButton" name="btnResetHistory">
+        <property name="text">
+         <string>Reset history</string>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="1" colspan="2">
+       <widget class="QLabel" name="lblFrom">
+        <property name="text">
+         <string>TextLabel</string>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="0" colspan="3">
+       <spacer name="horizontalSpacer">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeType">
+         <enum>QSizePolicy::Maximum</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>1000</width>
+          <height>0</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+      <item row="5" column="0" colspan="2">
+       <spacer name="horizontalSpacer_2">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>40</width>
+          <height>0</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item row="4" column="0">
+    <widget class="QFrame" name="frmSettings">
+     <property name="frameShape">
+      <enum>QFrame::StyledPanel</enum>
+     </property>
+     <property name="frameShadow">
+      <enum>QFrame::Raised</enum>
+     </property>
+     <layout class="QGridLayout" name="gridLayout_2">
+      <property name="sizeConstraint">
+       <enum>QLayout::SetDefaultConstraint</enum>
+      </property>
+      <property name="horizontalSpacing">
+       <number>10</number>
+      </property>
+      <property name="verticalSpacing">
+       <number>0</number>
+      </property>
+      <property name="margin">
+       <number>5</number>
+      </property>
+      <item row="0" column="0">
+       <widget class="QCheckBox" name="chkReceiveRate">
+        <property name="contextMenuPolicy">
+         <enum>Qt::NoContextMenu</enum>
+        </property>
+        <property name="toolTip">
+         <string/>
+        </property>
+        <property name="layoutDirection">
+         <enum>Qt::RightToLeft</enum>
+        </property>
+        <property name="text">
+         <string>Receive Rate</string>
+        </property>
+        <property name="checked">
+         <bool>false</bool>
+        </property>
+       </widget>
+      </item>
+      <item row="2" column="0">
+       <widget class="QCheckBox" name="chkSendRate">
+        <property name="contextMenuPolicy">
+         <enum>Qt::NoContextMenu</enum>
+        </property>
+        <property name="toolTip">
+         <string/>
+        </property>
+        <property name="layoutDirection">
+         <enum>Qt::RightToLeft</enum>
+        </property>
+        <property name="text">
+         <string>Send Rate</string>
+        </property>
+        <property name="checked">
+         <bool>false</bool>
+        </property>
+       </widget>
+      </item>
+      <item row="3" column="0">
+       <widget class="QCheckBox" name="chkAlwaysOnTop">
+        <property name="layoutDirection">
+         <enum>Qt::RightToLeft</enum>
+        </property>
+        <property name="text">
+         <string>Always on Top</string>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="1" colspan="3">
+       <widget class="QLabel" name="lblGraphStyle">
+        <property name="text">
+         <string>Style</string>
+        </property>
+        <property name="alignment">
+         <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="4">
+       <widget class="QComboBox" name="cmbGraphStyle">
+        <item>
+         <property name="text">
+          <string/>
+         </property>
+         <property name="icon">
+          <iconset resource="../../vidalia/src/vidalia/res/vidalia.qrc">
+           <normaloff>:/images/16x16/graph-line.png</normaloff>:/images/16x16/graph-line.png</iconset>
+         </property>
+        </item>
+        <item>
+         <property name="text">
+          <string/>
+         </property>
+         <property name="icon">
+          <iconset resource="../../vidalia/src/vidalia/res/vidalia.qrc">
+           <normaloff>:/images/16x16/graph-area.png</normaloff>:/images/16x16/graph-area.png</iconset>
+         </property>
+        </item>
+       </widget>
+      </item>
+      <item row="3" column="6">
+       <widget class="QPushButton" name="btnCancelSettings">
+        <property name="text">
+         <string>Cancel</string>
+        </property>
+       </widget>
+      </item>
+      <item row="2" column="6">
+       <widget class="QPushButton" name="btnSaveSettings">
+        <property name="text">
+         <string>Save</string>
+        </property>
+       </widget>
+      </item>
+      <item row="2" column="5">
+       <spacer name="horizontalSpacer_4">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>40</width>
+          <height>20</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+      <item row="2" column="1" rowspan="2" colspan="4">
+       <widget class="QFrame" name="frmOpacity">
+        <property name="frameShape">
+         <enum>QFrame::NoFrame</enum>
+        </property>
+        <property name="frameShadow">
+         <enum>QFrame::Plain</enum>
+        </property>
+        <property name="lineWidth">
+         <number>0</number>
+        </property>
+        <layout class="QGridLayout" name="gridLayout3">
+         <property name="margin">
+          <number>0</number>
+         </property>
+         <property name="spacing">
+          <number>-1</number>
+         </property>
+         <item row="0" column="0" colspan="4">
+          <widget class="QSlider" name="sldrOpacity">
+           <property name="sizePolicy">
+            <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+             <horstretch>0</horstretch>
+             <verstretch>0</verstretch>
+            </sizepolicy>
+           </property>
+           <property name="contextMenuPolicy">
+            <enum>Qt::NoContextMenu</enum>
+           </property>
+           <property name="toolTip">
+            <string>Changes the transparency of the Bandwidth Graph</string>
+           </property>
+           <property name="minimum">
+            <number>30</number>
+           </property>
+           <property name="maximum">
+            <number>100</number>
+           </property>
+           <property name="value">
+            <number>100</number>
+           </property>
+           <property name="sliderPosition">
+            <number>100</number>
+           </property>
+           <property name="tracking">
+            <bool>false</bool>
+           </property>
+           <property name="orientation">
+            <enum>Qt::Horizontal</enum>
+           </property>
+           <property name="invertedAppearance">
+            <bool>false</bool>
+           </property>
+           <property name="tickPosition">
+            <enum>QSlider::NoTicks</enum>
+           </property>
+           <property name="tickInterval">
+            <number>10</number>
+           </property>
+          </widget>
+         </item>
+         <item row="1" column="1">
+          <widget class="QLabel" name="lblPercentOpacity">
+           <property name="minimumSize">
+            <size>
+             <width>25</width>
+             <height>0</height>
+            </size>
+           </property>
+           <property name="font">
+            <font>
+             <pointsize>10</pointsize>
+            </font>
+           </property>
+           <property name="contextMenuPolicy">
+            <enum>Qt::NoContextMenu</enum>
+           </property>
+           <property name="layoutDirection">
+            <enum>Qt::RightToLeft</enum>
+           </property>
+           <property name="text">
+            <string>100</string>
+           </property>
+           <property name="alignment">
+            <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+           </property>
+          </widget>
+         </item>
+         <item row="1" column="2">
+          <widget class="QLabel" name="label">
+           <property name="font">
+            <font>
+             <pointsize>10</pointsize>
+            </font>
+           </property>
+           <property name="contextMenuPolicy">
+            <enum>Qt::NoContextMenu</enum>
+           </property>
+           <property name="text">
+            <string>% Opaque</string>
+           </property>
+          </widget>
+         </item>
+         <item row="1" column="3">
+          <spacer>
+           <property name="orientation">
+            <enum>Qt::Horizontal</enum>
+           </property>
+           <property name="sizeHint" stdset="0">
+            <size>
+             <width>40</width>
+             <height>20</height>
+            </size>
+           </property>
+          </spacer>
+         </item>
+         <item row="1" column="0">
+          <spacer name="horizontalSpacer_5">
+           <property name="orientation">
+            <enum>Qt::Horizontal</enum>
+           </property>
+           <property name="sizeHint" stdset="0">
+            <size>
+             <width>40</width>
+             <height>20</height>
+            </size>
+           </property>
+          </spacer>
+         </item>
+        </layout>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item row="1" column="0">
+    <widget class="QFrame" name="graphFrame">
+     <property name="minimumSize">
+      <size>
+       <width>128</width>
+       <height>32</height>
+      </size>
+     </property>
+     <property name="frameShape">
+      <enum>QFrame::StyledPanel</enum>
+     </property>
+     <property name="frameShadow">
+      <enum>QFrame::Raised</enum>
+     </property>
+     <layout class="QVBoxLayout" name="graphLayout">
+      <property name="margin">
+       <number>0</number>
+      </property>
+      <item>
+       <spacer name="horizontalSpacer_6">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>10000</width>
+          <height>0</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item row="2" column="0">
+    <layout class="QHBoxLayout" name="horizontalLayout">
+     <item>
+      <widget class="QPushButton" name="btnHistory">
+       <property name="text">
+        <string>Show History</string>
+       </property>
+       <property name="checkable">
+        <bool>true</bool>
+       </property>
+       <property name="flat">
+        <bool>false</bool>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QPushButton" name="btnSettings">
+       <property name="text">
+        <string>Show Settings</string>
+       </property>
+       <property name="checkable">
+        <bool>true</bool>
+       </property>
+       <property name="flat">
+        <bool>false</bool>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <spacer name="horizontalSpacer_3">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+     <item>
+      <widget class="QPushButton" name="btnReset">
+       <property name="text">
+        <string>Reset</string>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item row="1" column="1">
+    <spacer name="verticalSpacer">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>0</width>
+       <height>700</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+  </layout>
+ </widget>
+ <resources>
+  <include location="../../vidalia/src/vidalia/res/vidalia.qrc"/>
+ </resources>
+ <connections/>
+</ui>
diff --git a/bwgraph/graphframe.js b/bwgraph/graphframe.js
new file mode 100644
index 0000000..c9e8c14
--- /dev/null
+++ b/bwgraph/graphframe.js
@@ -0,0 +1,297 @@
+importExtension("qt");
+importExtension("qt.core");
+importExtension("qt.gui");
+
+HOR_SPC = 2;   /** Space between data points */
+MIN_SCALE = 10;  /** 10 kB/s is the minimum scale */
+SCROLL_STEP = 4;   /** Horizontal change on graph update */
+
+BACK_COLOR = new QColor(Qt.black);
+SCALE_COLOR = new QColor(Qt.green);
+GRID_COLOR = new QColor(Qt.darkGreen);
+RECV_COLOR = new QColor(Qt.cyan);
+SEND_COLOR = new QColor(Qt.yellow);
+
+FONT_SIZE = 11;
+
+SolidLine = 0;
+AreaGraph = 1;
+
+// TODO: support translations
+function tr(s) { return s; }
+
+function GraphFrame(parent)
+{
+  QFrame.call(this, parent);
+
+  /* Create Graph Frame related objects */
+  this.recvData = [];
+  this.sendData = [];
+  this.painter = new QPainter();
+  this.graphStyle = AreaGraph;
+
+  /* Initialize graph values */
+  this.recvData.unshift(0);
+  this.sendData.unshift(0);
+  this.maxPoints = this.getNumPoints();
+  this.maxPosition = 0;
+  this.showRecv = true;
+  this.showSend = true;
+  this.maxValue = MIN_SCALE;
+  this.scaleWidth = 0;
+  this.totalSend = 0;
+  this.totalRecv = 0;
+}
+
+GraphFrame.prototype = new QFrame();
+
+/** Gets the width of the desktop, which is the maximum number of points
+ * we can plot in the graph. */
+GraphFrame.prototype.getNumPoints = function()
+{
+  return this.size - this.scaleWidth;
+}
+
+/** Adds new data points to the graph. */
+GraphFrame.prototype.addPoints = function(recv, send)
+{
+  /* If maximum number of points plotted, remove oldest */
+  if (this.sendData.length == this.maxPoints) {
+    this.sendData.pop();
+    this.recvData.pop();
+  }
+
+  /* Update the displayed maximum */
+  if (this.maxPosition >= this.maxPoints) {
+    this.maxValue = MIN_SCALE;
+    for(send in this.sendData) {
+      if(send > this.maxValue)
+        this.maxValue = send;
+    }
+    for(recv in this.recvData) {
+      if(recv > this.maxValue)
+        this.maxValue = recv;
+    }
+    this.maxPosition = 0;
+  }
+
+  /* Add the points to their respective lists */
+  this.sendData.unshift(send);
+  this.recvData.unshift(recv);
+
+  /* Add to the total counters */
+  this.totalSend += send;
+  this.totalRecv += recv;
+
+  var maxUpdated = false;
+  /* Check for a new maximum value */
+  if (send > this.maxValue) {
+    this.maxValue = send;
+    maxUpdated = true;
+  }
+
+  if (recv > this.maxValue) {
+    this.maxValue = recv;
+    maxUpdated = true;
+  }
+
+  if (maxUpdated) {
+    this.maxPosition = 0;
+  } else {
+    this.maxPosition++;
+  }
+
+  this.update();
+}
+
+/** Clears the graph. */
+GraphFrame.prototype.resetGraph = function()
+{
+  this.recvData = [];
+  this.sendData = [];
+  this.recvData.unshift(0);
+  this.sendData.unshift(0);
+  this.maxValue = MIN_SCALE;
+  this.totalSend = 0;
+  this.totalRecv = 0;
+  this.update();
+}
+
+/** Toggles display of respective graph lines and counters. */
+GraphFrame.prototype.setShowCounters = function(showRecv, showSend)
+{
+  this.showRecv = showRecv;
+  this.showSend = showSend;
+}
+
+/** Returns a list of points on the bandwidth graph based on the supplied set
+ * of send or receive values. */
+GraphFrame.prototype.pointsFromData = function(list)
+{
+  var points = new Array();
+  var x = this.frameRect.width();
+  var y = this.frameRect.height();
+  var scale = (y - (y/10)) / this.maxValue;
+  var currValue = 0;
+
+  /* Translate all data points to points on the graph frame */
+  points.push(new QPointF(x, y));
+  for (var i = 0; i < list.length; i++) {
+    var item = list[i];
+    currValue = y - (item * scale);
+    if (x - SCROLL_STEP < this.scaleWidth) {
+      points.push(new QPointF(this.scaleWidth, currValue));
+      break;
+    }
+    points.push(new QPointF(x, currValue));
+    x -= SCROLL_STEP;
+  }
+  points.push(new QPointF(this.scaleWidth, y));
+  return points;
+}
+
+/** Returns the width in pixels of <b>label</b> using the current painter's
+ * font. */
+GraphFrame.prototype.labelWidth = function(label)
+{
+  var width = 0;
+  var fm = new QFontMetrics(this.font);
+
+  for (var i = 0; i < label.length; i++)
+    width += fm.charWidth(label, i);
+  return width;
+}
+
+GraphFrame.prototype.resizeEvent = function(ev)
+{
+  this.maxPoints = ev.size().width() - this.scaleWidth;
+  this.maxPoints /= SCROLL_STEP;
+  this.resize(this.parentWidget().size.width(), this.parentWidget().size.height());
+}
+
+GraphFrame.prototype.paintEvent = function(ev)
+{
+  this.painter.begin(this);
+
+  /** Filling */
+  this.painter.setRenderHint(QPainter.Antialiasing);
+  this.painter.setRenderHint(QPainter.TextAntialiasing);
+
+  /* Fill in the background */
+  this.painter.fillRect(this.frameRect, BACK_COLOR);
+
+  /** Paint Scale */
+  var label = new Array();
+  var width = new Array();
+  var top = this.frameRect.y();
+  var bottom = this.frameRect.height();
+  var scaleWidth = 0;
+  var pos = 0;
+  var markStep = this.maxValue * 0.25;
+  var paintStep = (bottom - (bottom/8)) / 4;
+
+  /* Compute each of the y-axis labels */
+  for (var i = 0; i < 4; i++) {
+   pos = bottom - ((i+1) * paintStep);
+   label[i] = (markStep*(i+1)).toFixed(2).toString() + "KB/s";
+   width[i] = this.labelWidth(label[i]);
+   scaleWidth = Math.max(scaleWidth, 2+width[i]);
+  }
+
+  /* Include a 5px margin between the y-axis and its labels */
+  this.scaleWidth = scaleWidth + 5;
+
+  /* Draw the y-axis labels and horizontal marks in their correctly scaled
+   * locations */
+  for (i = 0; i < 4; i++) {
+    pos = bottom - ((i+1) * paintStep);
+    this.painter.setPen(SCALE_COLOR);
+    this.painter.drawText(new QPointF(this.scaleWidth-width[i]-5, pos), String(label[i]));
+
+    this.painter.setPen(GRID_COLOR);
+    this.painter.drawLine(new QPointF(this.scaleWidth, pos),
+                          new QPointF(this.frameRect.width(), pos));
+  }
+
+  /* Draw the y-axis */
+  this.painter.drawLine(this.scaleWidth, top, this.scaleWidth, bottom);
+
+  /**********************************************
+   * Paint data *********************************/
+  var recvPoints = [];
+  var sendPoints = [];
+
+  /* Convert the bandwidth data points to graph points */
+  recvPoints = this.pointsFromData(this.recvData);
+  sendPoints = this.pointsFromData(this.sendData);
+
+  if (this.graphStyle == AreaGraph) {
+    /* Plot the bandwidth data as area graphs */
+    if (this.showRecv)
+    {
+      var oldBrush = this.painter.brush();
+      RECV_COLOR.setAlphaF(0.6);
+      this.painter.setBrush(new QBrush(RECV_COLOR));
+      this.painter.drawPolygon(new QPolygonF(recvPoints), Qt.OddEvenFill);
+      this.painter.setBrush(oldBrush);
+    }
+    if (this.showSend)
+    {
+      var oldBrush = this.painter.brush();
+      SEND_COLOR.setAlphaF(0.4);
+      this.painter.setBrush(new QBrush(SEND_COLOR));
+      this.painter.drawPolygon(new QPolygonF(sendPoints), Qt.OddEvenFill);
+      this.painter.setBrush(oldBrush);
+    }
+  }
+
+  /* Plot the bandwidth as solid lines. If the graph style is currently an
+   * area graph, we end up outlining the integrals. */
+  if (this.showRecv)
+  {
+    var oldPen = this.painter.pen();
+    this.painter.setPen(RECV_COLOR);
+    this.painter.drawPolyline(new QPolygonF(recvPoints));
+    this.painter.setPen(oldPen);
+  }
+  if (this.showSend)
+  {
+    var oldPen = this.painter.pen();
+    this.painter.setPen(SEND_COLOR);
+    this.painter.drawPolyline(new QPolygonF(sendPoints));
+    this.painter.setPen(oldPen);
+  }
+
+  /************************************************
+   * Paint totals *********************************/
+  var x = this.scaleWidth + FONT_SIZE;
+  var y = 0;
+  var rowHeight = FONT_SIZE;
+
+  /* On Mac, we don't need vertical spacing between the text rows. */
+  // TODO: see how to use this in this case since we don't have preproc
+  rowHeight += 5;
+
+  /* If total received is selected */
+  if (this.showRecv) {
+    y = rowHeight;
+    this.painter.setPen(RECV_COLOR);
+    var total = Math.floor(this.totalRecv*100) / 100;
+    var count = Math.floor(this.recvData[0]*100) / 100;
+    this.painter.drawText(new QPoint(x, y),
+        tr("Recv:") + " " + total +
+        " (" + count + "KB/s)");
+  }
+
+  /* If total sent is selected */
+  if (this.showSend) {
+    y += rowHeight;
+    this.painter.setPen(SEND_COLOR);
+    var total = Math.floor(this.totalSend*100) / 100;
+    var count = Math.floor(this.sendData[0]*100) / 100;
+    this.painter.drawText(new QPoint(x, y),
+        tr("Sent:") + " " + total +
+        " (" + count + "KB/s)");
+  }
+  this.painter.end();
+}
diff --git a/bwgraph/info.xml b/bwgraph/info.xml
new file mode 100644
index 0000000..7d54654
--- /dev/null
+++ b/bwgraph/info.xml
@@ -0,0 +1,11 @@
+<VidaliaPlugin>
+  <name>Bandwidth Graph</name>
+  <date>11/06/2012</date>
+  <author>chiiph</author>
+  <type persistent="true" gui="true" />
+  <files>
+    <file>graphframe.js</file>
+    <file>bwgraph.js</file>
+  </files>
+  <namespace>bwgraph</namespace>
+</VidaliaPlugin>





More information about the tor-commits mailing list