Merge pull request #845 from csoler/v0.6-GxsTransport

V0.6 gxs transport
This commit is contained in:
csoler 2017-05-27 15:22:32 +02:00 committed by GitHub
commit 753867ef36
11 changed files with 175 additions and 206 deletions

View File

@ -13,6 +13,12 @@
<file>icons/anonymous_blue_128.png</file> <file>icons/anonymous_blue_128.png</file>
<file>icons/anonymous_green_128.png</file> <file>icons/anonymous_green_128.png</file>
<file>icons/aol.png</file> <file>icons/aol.png</file>
<file>icons/transport128.png</file>
<file>icons/bandwidth128.png</file>
<file>icons/RTT128.png</file>
<file>icons/DHT128.png</file>
<file>icons/turtle128.png</file>
<file>icons/GRouter128.png</file>
<file>icons/avatar_128.png</file> <file>icons/avatar_128.png</file>
<file>icons/avatar_grey_128.png</file> <file>icons/avatar_grey_128.png</file>
<file>icons/biohazard_red.png</file> <file>icons/biohazard_red.png</file>

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

View File

@ -45,14 +45,18 @@
#include "gui/common/UIStateHelper.h" #include "gui/common/UIStateHelper.h"
#include "util/misc.h" #include "util/misc.h"
#define COL_ID 0 #define COL_PENDING_ID 0
#define COL_DESTINATION 1 #define COL_PENDING_DESTINATION 1
#define COL_NICKNAME 2 #define COL_PENDING_NICKNAME 2
#define COL_DATASTATUS 3 #define COL_PENDING_DATASTATUS 3
#define COL_DATASIZE 4 #define COL_PENDING_DATASIZE 4
#define COL_DATAHASH 5 #define COL_PENDING_DATAHASH 5
#define COL_SEND 6 #define COL_PENDING_SEND 6
#define COL_GROUP_ID 7 #define COL_PENDING_GROUP_ID 7
#define COL_GROUP_GRP_ID 0
#define COL_GROUP_NUM_MSGS 1
#define COL_GROUP_SIZE_MSGS 2
static const int PARTIAL_VIEW_SIZE = 9 ; static const int PARTIAL_VIEW_SIZE = 9 ;
static const int MAX_TUNNEL_REQUESTS_DISPLAY = 10 ; static const int MAX_TUNNEL_REQUESTS_DISPLAY = 10 ;
@ -60,6 +64,7 @@ static const int GXSTRANS_STATISTICS_DELAY_BETWEEN_GROUP_REQ = 30 ; // never req
#define GXSTRANS_GROUP_META 0x01 #define GXSTRANS_GROUP_META 0x01
#define GXSTRANS_GROUP_DATA 0x02 #define GXSTRANS_GROUP_DATA 0x02
#define GXSTRANS_GROUP_STAT 0x03
// static QColor colorScale(float f) // static QColor colorScale(float f)
// { // {
@ -201,7 +206,9 @@ void GxsTransportStatistics::updateContent()
treeWidget->clear(); treeWidget->clear();
time_t now = time(NULL) ; time_t now = time(NULL) ;
groupBox->setTitle(tr("Pending packets")+": " + QString::number(transinfo.outgoing_records.size()) ); // 1 - fill the table for pending packets
groupBox->setTitle(tr("Pending data items")+": " + QString::number(transinfo.outgoing_records.size()) );
for(uint32_t i=0;i<transinfo.outgoing_records.size();++i) for(uint32_t i=0;i<transinfo.outgoing_records.size();++i)
{ {
@ -217,21 +224,37 @@ void GxsTransportStatistics::updateContent()
if(nickname.isEmpty()) if(nickname.isEmpty())
nickname = tr("Unknown"); nickname = tr("Unknown");
item -> setData(COL_ID, Qt::DisplayRole, QString::number(rec.trans_id,16).rightJustified(8,'0')); item -> setData(COL_PENDING_ID, Qt::DisplayRole, QString::number(rec.trans_id,16).rightJustified(8,'0'));
item -> setData(COL_NICKNAME, Qt::DisplayRole, nickname ) ; item -> setData(COL_PENDING_NICKNAME, Qt::DisplayRole, nickname ) ;
item -> setData(COL_DESTINATION, Qt::DisplayRole, QString::fromStdString(rec.recipient.toStdString())); item -> setData(COL_PENDING_DESTINATION, Qt::DisplayRole, QString::fromStdString(rec.recipient.toStdString()));
item -> setData(COL_DATASTATUS, Qt::DisplayRole, getStatusString(rec.status)); item -> setData(COL_PENDING_DATASTATUS, Qt::DisplayRole, getStatusString(rec.status));
item -> setData(COL_DATASIZE, Qt::DisplayRole, misc::friendlyUnit(rec.data_size)); item -> setData(COL_PENDING_DATASIZE, Qt::DisplayRole, misc::friendlyUnit(rec.data_size));
item -> setData(COL_DATAHASH, Qt::DisplayRole, QString::fromStdString(rec.data_hash.toStdString())); item -> setData(COL_PENDING_DATAHASH, Qt::DisplayRole, QString::fromStdString(rec.data_hash.toStdString()));
item -> setData(COL_SEND, Qt::DisplayRole, QString::number(now - rec.send_TS)); item -> setData(COL_PENDING_SEND, Qt::DisplayRole, QString::number(now - rec.send_TS));
item -> setData(COL_GROUP_ID, Qt::DisplayRole, QString::fromStdString(rec.group_id.toStdString())); item -> setData(COL_PENDING_GROUP_ID, Qt::DisplayRole, QString::fromStdString(rec.group_id.toStdString()));
}
// 2 - fill the table for pending group data
groupTreeWidget->clear();
for(std::map<RsGxsGroupId,GxsGroupStatistic>::const_iterator it(mGroupStats.begin());it!=mGroupStats.end();++it)
{
const GxsGroupStatistic& stat(it->second) ;
QTreeWidgetItem *item = new QTreeWidgetItem();
groupTreeWidget->addTopLevelItem(item);
item->setData(COL_GROUP_GRP_ID, Qt::DisplayRole, QString::fromStdString(stat.mGrpId.toStdString())) ;
item->setData(COL_GROUP_NUM_MSGS, Qt::DisplayRole, QString::number(stat.mNumMsgs)) ;
item->setData(COL_GROUP_SIZE_MSGS,Qt::DisplayRole, QString::number(stat.mTotalSizeOfMsgs)) ;
} }
} }
void GxsTransportStatistics::personDetails() void GxsTransportStatistics::personDetails()
{ {
QTreeWidgetItem *item = treeWidget->currentItem(); QTreeWidgetItem *item = treeWidget->currentItem();
std::string id = item->text(COL_DESTINATION).toStdString(); std::string id = item->text(COL_PENDING_DESTINATION).toStdString();
if (id.empty()) { if (id.empty()) {
return; return;
@ -239,116 +262,18 @@ void GxsTransportStatistics::personDetails()
IdDetailsDialog *dialog = new IdDetailsDialog(RsGxsGroupId(id)); IdDetailsDialog *dialog = new IdDetailsDialog(RsGxsGroupId(id));
dialog->show(); dialog->show();
}
GxsTransportStatisticsWidget::GxsTransportStatisticsWidget(QWidget *parent)
: QWidget(parent)
{
float size = QFontMetricsF(font()).height() ;
float fact = size/14.0 ;
maxWidth = 400*fact ;
maxHeight = 0 ;
mCurrentN = PARTIAL_VIEW_SIZE/2+1 ;
}
void GxsTransportStatisticsWidget::updateContent()
{
RsGxsTrans::GxsTransStatistics transinfo ;
rsGxsTrans->getStatistics(transinfo) ;
float size = QFontMetricsF(font()).height() ;
float fact = size/14.0 ;
// What do we need to draw?
//
// Statistics about GxsTransport
// - prefered group ID
//
// Own key ids
// key service id description
//
// Data items
// Msg id Local origin Destination Time Status
//
QPixmap tmppixmap(maxWidth, maxHeight);
tmppixmap.fill(Qt::transparent);
setFixedHeight(maxHeight);
QPainter painter(&tmppixmap);
painter.initFrom(this);
painter.setPen(QColor::fromRgb(0,0,0)) ;
QFont times_f(font());//"Times") ;
QFont monospace_f("Monospace") ;
monospace_f.setStyleHint(QFont::TypeWriter) ;
monospace_f.setPointSize(font().pointSize()) ;
QFontMetricsF fm_monospace(monospace_f) ;
QFontMetricsF fm_times(times_f) ;
static const int cellx = fm_monospace.width(QString(" ")) ;
static const int celly = fm_monospace.height() ;
maxHeight = 500*fact ;
// std::cerr << "Drawing into pixmap of size " << maxWidth << "x" << maxHeight << std::endl;
// draw...
int ox=5*fact,oy=5*fact ;
painter.setFont(times_f) ;
painter.drawText(ox,oy+celly,tr("Preferred group Id")+":" + QString::fromStdString(transinfo.prefered_group_id.toStdString())) ; oy += celly*2 ;
oy += celly ;
oy += celly ;
// update the pixmap
//
pixmap = tmppixmap;
maxHeight = oy ;
}
void GxsTransportStatisticsWidget::wheelEvent(QWheelEvent *e)
{
}
QString GxsTransportStatisticsWidget::speedString(float f)
{
if(f < 1.0f)
return QString("0 B/s") ;
if(f < 1024.0f)
return QString::number((int)f)+" B/s" ;
return QString::number(f/1024.0,'f',2) + " KB/s";
}
void GxsTransportStatisticsWidget::paintEvent(QPaintEvent */*event*/)
{
QStylePainter(this).drawPixmap(0, 0, pixmap);
}
void GxsTransportStatisticsWidget::resizeEvent(QResizeEvent *event)
{
QRect TaskGraphRect = geometry();
maxWidth = TaskGraphRect.width();
maxHeight = TaskGraphRect.height() ;
QWidget::resizeEvent(event);
updateContent();
} }
void GxsTransportStatistics::loadRequest(const TokenQueue *queue, const TokenRequest &req) void GxsTransportStatistics::loadRequest(const TokenQueue *queue, const TokenRequest &req)
{ {
std::cerr << "GxsTransportStatistics::loadRequest() UserType: " << req.mUserType; std::cerr << "GxsTransportStatistics::loadRequest() UserType: " << req.mUserType << std::endl;
std::cerr << std::endl;
if (queue != mTransQueue) if (queue != mTransQueue)
{ {
std::cerr << "Wrong queue!" << std::endl;
return ;
}
/* now switch on req */ /* now switch on req */
switch(req.mUserType) switch(req.mUserType)
{ {
@ -358,12 +283,14 @@ void GxsTransportStatistics::loadRequest(const TokenQueue *queue, const TokenReq
case GXSTRANS_GROUP_DATA: loadGroupData(req.mToken); case GXSTRANS_GROUP_DATA: loadGroupData(req.mToken);
break; break;
case GXSTRANS_GROUP_STAT: loadGroupStat(req.mToken);
break;
default: default:
std::cerr << "GxsTransportStatistics::loadRequest() ERROR: INVALID TYPE"; std::cerr << "GxsTransportStatistics::loadRequest() ERROR: INVALID TYPE";
std::cerr << std::endl; std::cerr << std::endl;
break; break;
} }
}
} }
void GxsTransportStatistics::requestGroupMeta() void GxsTransportStatistics::requestGroupMeta()
@ -381,6 +308,23 @@ void GxsTransportStatistics::requestGroupMeta()
uint32_t token; uint32_t token;
mTransQueue->requestGroupInfo(token, RS_TOKREQ_ANSTYPE_SUMMARY, opts, GXSTRANS_GROUP_META); mTransQueue->requestGroupInfo(token, RS_TOKREQ_ANSTYPE_SUMMARY, opts, GXSTRANS_GROUP_META);
} }
void GxsTransportStatistics::requestGroupStat(const RsGxsGroupId &groupId)
{
mTransQueue->cancelActiveRequestTokens(GXSTRANS_GROUP_STAT);
uint32_t token;
rsGxsTrans->getTokenService()->requestGroupStatistic(token, groupId);
mTransQueue->queueRequest(token, 0, RS_TOKREQ_ANSTYPE_ACK, GXSTRANS_GROUP_STAT);
}
void GxsTransportStatistics::loadGroupStat(const uint32_t &token)
{
std::cerr << "GxsTransportStatistics::loadGroupStat." << std::endl;
GxsGroupStatistic stats;
rsGxsTrans->getGroupStatistic(token, stats);
mGroupStats[stats.mGrpId] = stats ;
}
void GxsTransportStatistics::loadGroupMeta(const uint32_t& token) void GxsTransportStatistics::loadGroupMeta(const uint32_t& token)
{ {
mStateHelper->setLoading(GXSTRANS_GROUP_META, false); mStateHelper->setLoading(GXSTRANS_GROUP_META, false);
@ -420,28 +364,27 @@ void GxsTransportStatistics::loadGroupMeta(const uint32_t& token)
// externalOtherCirclesItem->setText(0, tr("External Circles (Other)")); // externalOtherCirclesItem->setText(0, tr("External Circles (Other)"));
// ui.treeWidget_membership->addTopLevelItem(externalOtherCirclesItem); // ui.treeWidget_membership->addTopLevelItem(externalOtherCirclesItem);
std::set<RsGxsGroupId> existing_groups ;
for(vit = groupInfo.begin(); vit != groupInfo.end(); ++vit) for(vit = groupInfo.begin(); vit != groupInfo.end(); ++vit)
{ {
existing_groups.insert(vit->mGroupId) ;
/* Add Widget, and request Pages */ /* Add Widget, and request Pages */
std::cerr << "GxsTransportStatisticsWidget::loadGroupMeta() GroupId: " << vit->mGroupId << " Group: " << vit->mGroupName << std::endl; std::cerr << "GxsTransportStatisticsWidget::loadGroupMeta() GroupId: " << vit->mGroupId << " Group: " << vit->mGroupName << std::endl;
// QTreeWidgetItem *groupItem = new QTreeWidgetItem(); requestGroupStat(vit->mGroupId) ;
// groupItem->setText(CIRCLEGROUP_CIRCLE_COL_GROUPNAME, QString::fromUtf8(vit->mGroupName.c_str()));
// groupItem->setText(CIRCLEGROUP_CIRCLE_COL_GROUPID, QString::fromStdString(vit->mGroupId.toStdString()));
// if (vit->mCircleType == GXS_CIRCLE_TYPE_LOCAL)
// personalCirclesItem->addChild(groupItem);
// else
// {
// if (vit->mSubscribeFlags & GXS_SERV::GROUP_SUBSCRIBE_ADMIN)
// externalAdminCirclesItem->addChild(groupItem);
// else if (vit->mSubscribeFlags & GXS_SERV::GROUP_SUBSCRIBE_SUBSCRIBED)
// externalSubCirclesItem->addChild(groupItem);
// else
// externalOtherCirclesItem->addChild(groupItem);
// }
} }
// remove group stats for group that do not exist anymore
for(std::map<RsGxsGroupId,GxsGroupStatistic>::iterator it(mGroupStats.begin());it!=mGroupStats.end();)
if(existing_groups.find(it->first) == existing_groups.end())
it = mGroupStats.erase(it);
else
++it;
} }
void GxsTransportStatistics::loadGroupData(const uint32_t& token) void GxsTransportStatistics::loadGroupData(const uint32_t& token)
{ {
std::cerr << __PRETTY_FUNCTION__ << ": not implemented." << std::endl; std::cerr << __PRETTY_FUNCTION__ << ": not implemented." << std::endl;

View File

@ -21,6 +21,8 @@
#pragma once #pragma once
#include <map>
#include <QPoint> #include <QPoint>
#include <retroshare/rsgrouter.h> #include <retroshare/rsgrouter.h>
#include <retroshare/rstypes.h> #include <retroshare/rstypes.h>
@ -55,43 +57,49 @@ private slots:
private: private:
void loadGroupData(const uint32_t& token); void loadGroupData(const uint32_t& token);
void loadGroupMeta(const uint32_t& token); void loadGroupMeta(const uint32_t& token);
void loadGroupStat(const uint32_t& token);
void requestGroupData(); void requestGroupData();
void requestGroupMeta(); void requestGroupMeta();
void requestGroupStat(const RsGxsGroupId &groupId);
void processSettings(bool bLoad); void processSettings(bool bLoad);
bool m_bProcessSettings; bool m_bProcessSettings;
virtual void updateDisplay() ; virtual void updateDisplay() ;
GxsTransportStatisticsWidget *_tst_CW ; GxsTransportStatisticsWidget *_tst_CW ;
TokenQueue *mTransQueue ; TokenQueue *mTransQueue ;
UIStateHelper *mStateHelper; UIStateHelper *mStateHelper;
uint32_t mLastGroupReqTS ; uint32_t mLastGroupReqTS ;
// temporary storage of retrieved data, for display (useful because this is obtained from the async token system)
std::map<RsGxsGroupId,GxsGroupStatistic> mGroupStats ; // stores the list of active groups and statistics about each of them.
} ; } ;
class GxsTransportStatisticsWidget: public QWidget // class GxsTransportStatisticsWidget: public QWidget
{ // {
Q_OBJECT // Q_OBJECT
//
public: // public:
GxsTransportStatisticsWidget(QWidget *parent = NULL) ; // GxsTransportStatisticsWidget(QWidget *parent = NULL) ;
//
virtual void paintEvent(QPaintEvent *event) ; // virtual void paintEvent(QPaintEvent *event) ;
virtual void resizeEvent(QResizeEvent *event); // virtual void resizeEvent(QResizeEvent *event);
virtual void wheelEvent(QWheelEvent *event); // virtual void wheelEvent(QWheelEvent *event);
//
void updateContent() ; // void updateContent() ;
private: // private:
static QString speedString(float f) ; // static QString speedString(float f) ;
//
QPixmap pixmap ; // QPixmap pixmap ;
int maxWidth,maxHeight ; // int maxWidth,maxHeight ;
int mCurrentN ; // int mCurrentN ;
int mNumberOfKnownKeys ; // int mNumberOfKnownKeys ;
int mMinWheelZoneX ; // int mMinWheelZoneX ;
int mMinWheelZoneY ; // int mMinWheelZoneY ;
int mMaxWheelZoneX ; // int mMaxWheelZoneX ;
int mMaxWheelZoneY ; // int mMaxWheelZoneY ;
}; // };

View File

@ -15,31 +15,36 @@
</property> </property>
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout">
<item row="1" column="0"> <item row="1" column="0">
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Gxs Transport Groups:</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QSplitter" name="splitter"> <widget class="QSplitter" name="splitter">
<property name="orientation"> <property name="orientation">
<enum>Qt::Vertical</enum> <enum>Qt::Vertical</enum>
</property> </property>
<widget class="QScrollArea" name="_router_F"> <widget class="QTreeWidget" name="groupTreeWidget">
<property name="frameShape"> <column>
<enum>QFrame::NoFrame</enum> <property name="text">
<string>Group ID</string>
</property> </property>
<property name="horizontalScrollBarPolicy"> </column>
<enum>Qt::ScrollBarAlwaysOff</enum> <column>
<property name="text">
<string>Number of messages</string>
</property> </property>
<property name="widgetResizable"> </column>
<bool>true</bool> <column>
</property> <property name="text">
<widget class="QWidget" name="scrollAreaWidgetContents"> <string>Total size of messages</string>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1432</width>
<height>305</height>
</rect>
</property> </property>
</column>
</widget> </widget>
</widget> </widget>
</item>
</layout>
</widget> </widget>
</item> </item>
<item row="0" column="0"> <item row="0" column="0">

View File

@ -34,6 +34,8 @@
#include "retroshare/rspeers.h" #include "retroshare/rspeers.h"
#include <retroshare/rsplugin.h> #include <retroshare/rsplugin.h>
#include <gui/settings/rsharesettings.h>
#include <gui/statistics/TurtleRouterStatistics.h> #include <gui/statistics/TurtleRouterStatistics.h>
#include <gui/statistics/GlobalRouterStatistics.h> #include <gui/statistics/GlobalRouterStatistics.h>
#include <gui/statistics/GxsTransportStatistics.h> #include <gui/statistics/GxsTransportStatistics.h>
@ -49,12 +51,14 @@
#include "gui/statistics/RttStatistics.h" #include "gui/statistics/RttStatistics.h"
#endif #endif
#define IMAGE_DHT ":/images/dht32.png" #define IMAGE_DHT ":/icons/DHT128.png"
#define IMAGE_TURTLE ":images/turtle.png" #define IMAGE_TURTLE ":/icons/turtle128.png"
#define IMAGE_BWGRAPH ":/images/ksysguard.png" #define IMAGE_BWGRAPH ":/icons/bandwidth128.png"
#define IMAGE_GLOBALROUTER ":/images/network32.png" #define IMAGE_GLOBALROUTER ":/icons/GRouter128.png"
#define IMAGE_BANDWIDTH ":images/office-chart-area-stacked.png" #define IMAGE_GXSTRANSPORT ":/icons/transport128.png"
#define IMAGE_RTT ":images/office-chart-line.png" #define IMAGE_RTT ":/icons/RTT128.png"
//#define IMAGE_BANDWIDTH ":images/office-chart-area-stacked.png"
/********************************************** STATIC WINDOW *************************************/ /********************************************** STATIC WINDOW *************************************/
StatisticsWindow * StatisticsWindow::mInstance = NULL; StatisticsWindow * StatisticsWindow::mInstance = NULL;
@ -95,6 +99,9 @@ StatisticsWindow::StatisticsWindow(QWidget *parent) :
connect(ui->stackPages, SIGNAL(currentChanged(int)), this, SLOT(setNewPage(int))); connect(ui->stackPages, SIGNAL(currentChanged(int)), this, SLOT(setNewPage(int)));
ui->stackPages->setCurrentIndex(0); ui->stackPages->setCurrentIndex(0);
int toolSize = Settings->getToolButtonSize();
ui->toolBar->setToolButtonStyle(Settings->getToolButtonStyle());
ui->toolBar->setIconSize(QSize(toolSize,toolSize));
} }
StatisticsWindow::~StatisticsWindow() StatisticsWindow::~StatisticsWindow()
@ -126,7 +133,7 @@ void StatisticsWindow::initStackedPage()
QAction *action; QAction *action;
ui->stackPages->add(bwdlg = new BwCtrlWindow(ui->stackPages), ui->stackPages->add(bwdlg = new BwCtrlWindow(ui->stackPages),
action = createPageAction(QIcon(IMAGE_BANDWIDTH), tr("Bandwidth"), grp)); action = createPageAction(QIcon(IMAGE_BWGRAPH), tr("Bandwidth"), grp));
ui->stackPages->add(trsdlg = new TurtleRouterStatistics(ui->stackPages), ui->stackPages->add(trsdlg = new TurtleRouterStatistics(ui->stackPages),
action = createPageAction(QIcon(IMAGE_TURTLE), tr("Turtle Router"), grp)); action = createPageAction(QIcon(IMAGE_TURTLE), tr("Turtle Router"), grp));
@ -135,7 +142,7 @@ void StatisticsWindow::initStackedPage()
action = createPageAction(QIcon(IMAGE_GLOBALROUTER), tr("Global Router"), grp)); action = createPageAction(QIcon(IMAGE_GLOBALROUTER), tr("Global Router"), grp));
ui->stackPages->add(gxsdlg = new GxsTransportStatistics(ui->stackPages), ui->stackPages->add(gxsdlg = new GxsTransportStatistics(ui->stackPages),
action = createPageAction(QIcon(IMAGE_GLOBALROUTER), tr("Gxs Transport"), grp)); action = createPageAction(QIcon(IMAGE_GXSTRANSPORT), tr("Gxs Transport"), grp));
ui->stackPages->add(rttdlg = new RttStatistics(ui->stackPages), ui->stackPages->add(rttdlg = new RttStatistics(ui->stackPages),
action = createPageAction(QIcon(IMAGE_RTT), tr("RTT Statistics"), grp)); action = createPageAction(QIcon(IMAGE_RTT), tr("RTT Statistics"), grp));
@ -183,7 +190,7 @@ QAction *StatisticsWindow::createPageAction(const QIcon &icon, const QString &te
font = action->font(); font = action->font();
font.setPointSize(9); font.setPointSize(9);
action->setCheckable(true); action->setCheckable(true);
action->setFont(font); // action->setFont(font);
return action; return action;
} }