2017-02-08 00:14:49 +03:00
/************************************************************************
* file name : main_window . cpp
* - - - - - - - - - - - - - - - - - :
* creation time : 2016 / 06 / 26
* author : Victor Zarubkin
* email : v . s . zarubkin @ gmail . com
* - - - - - - - - - - - - - - - - - :
* description : The file contains implementation of MainWindow for easy_profiler GUI .
* - - - - - - - - - - - - - - - - - :
* change log : * 2016 / 06 / 26 Victor Zarubkin : Initial commit .
* :
2018-01-28 20:52:17 +03:00
* : * 2016 / 06 / 27 Victor Zarubkin : Passing blocks number to BlocksTreeWidget : : setTree ( ) .
2017-02-08 00:14:49 +03:00
* :
* : * 2016 / 06 / 29 Victor Zarubkin : Added menu with tests .
* :
* : * 2016 / 06 / 30 Sergey Yagovtsev : Open file by command line argument
* :
* : *
* - - - - - - - - - - - - - - - - - :
* license : Lightweight profiler library for c + +
2019-10-20 16:12:37 +03:00
* : Copyright ( C ) 2016 - 2019 Sergey Yagovtsev , Victor Zarubkin
2017-02-08 00:14:49 +03:00
* :
2017-03-30 06:55:15 +03:00
* : Licensed under either of
* : * MIT license ( LICENSE . MIT or http : //opensource.org/licenses/MIT)
* : * Apache License , Version 2.0 , ( LICENSE . APACHE or http : //www.apache.org/licenses/LICENSE-2.0)
* : at your option .
2017-02-08 00:14:49 +03:00
* :
2017-03-30 06:55:15 +03:00
* : The MIT License
* :
* : Permission is hereby granted , free of charge , to any person obtaining a copy
* : of this software and associated documentation files ( the " Software " ) , to deal
* : in the Software without restriction , including without limitation the rights
* : to use , copy , modify , merge , publish , distribute , sublicense , and / or sell copies
* : of the Software , and to permit persons to whom the Software is furnished
* : to do so , subject to the following conditions :
* :
* : The above copyright notice and this permission notice shall be included in all
* : copies or substantial portions of the Software .
* :
* : THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR IMPLIED ,
* : INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY , FITNESS FOR A PARTICULAR
* : PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* : LIABLE FOR ANY CLAIM , DAMAGES OR OTHER LIABILITY , WHETHER IN AN ACTION OF CONTRACT ,
* : TORT OR OTHERWISE , ARISING FROM , OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* : USE OR OTHER DEALINGS IN THE SOFTWARE .
* :
* : The Apache License , Version 2.0 ( the " License " )
* :
* : You may not use this file except in compliance with the License .
2017-02-08 00:14:49 +03:00
* : You may obtain a copy of the License at
* :
* : http : //www.apache.org/licenses/LICENSE-2.0
* :
* : Unless required by applicable law or agreed to in writing , software
* : distributed under the License is distributed on an " AS IS " BASIS ,
* : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
* : See the License for the specific language governing permissions and
* : limitations under the License .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include <chrono>
# include <fstream>
# include <QApplication>
# include <QCoreApplication>
2018-05-19 23:40:01 +03:00
# include <QDebug>
2017-02-08 00:14:49 +03:00
# include <QAction>
# include <QCloseEvent>
2018-05-19 23:40:01 +03:00
# include <QDateTime>
# include <QDragEnterEvent>
# include <QDragMoveEvent>
# include <QDragLeaveEvent>
# include <QDropEvent>
# include <QFile>
# include <QFileDialog>
# include <QFileInfo>
2017-02-08 00:14:49 +03:00
# include <QFont>
2018-05-19 23:40:01 +03:00
# include <QFontMetrics>
2018-02-01 23:17:01 +03:00
# include <QFontMetricsF>
2018-05-19 23:40:01 +03:00
# include <QMenu>
# include <QMenuBar>
# include <QMessageBox>
# include <QMimeData>
# include <QLabel>
# include <QLineEdit>
# include <QPushButton>
2017-02-08 00:14:49 +03:00
# include <QProgressDialog>
2018-05-19 23:40:01 +03:00
# include <QTextCodec>
2019-10-20 16:12:37 +03:00
# include <QPlainTextEdit>
2018-05-19 23:40:01 +03:00
# include <QTextStream>
2017-02-08 00:14:49 +03:00
# include <QToolBar>
# include <QToolButton>
2018-05-19 23:40:01 +03:00
# include <QSet>
# include <QSettings>
# include <QSignalBlocker>
2017-02-08 00:14:49 +03:00
# include <QSpinBox>
2018-05-19 23:40:01 +03:00
# include <QStatusBar>
2017-02-08 00:14:49 +03:00
# include <QVBoxLayout>
2018-05-19 23:40:01 +03:00
# include <QWidgetAction>
2017-02-08 00:14:49 +03:00
# include "main_window.h"
2018-03-12 01:47:20 +03:00
# include "arbitrary_value_inspector.h"
2017-02-08 00:14:49 +03:00
# include "blocks_tree_widget.h"
# include "blocks_graphics_view.h"
# include "descriptors_tree_widget.h"
2018-05-07 21:58:37 +03:00
# include "fps_widget.h"
2017-02-08 00:14:49 +03:00
# include "globals.h"
2018-06-09 02:18:39 +03:00
# include "dialog.h"
2017-03-05 23:50:38 +03:00
# include <easy/easy_net.h>
2017-11-09 23:34:17 +03:00
# include <easy/profiler.h>
2018-05-08 21:14:46 +03:00
# include <easy/writer.h>
2017-02-08 00:14:49 +03:00
# ifdef max
# undef max
# endif
# ifdef min
# undef min
# endif
//////////////////////////////////////////////////////////////////////////
2017-05-02 23:21:15 +03:00
# define EASY_DEFAULT_WINDOW_TITLE "EasyProfiler"
2017-02-08 00:14:49 +03:00
const int LOADER_TIMER_INTERVAL = 40 ;
const auto NETWORK_CACHE_FILE = " easy_profiler_stream.cache " ;
//////////////////////////////////////////////////////////////////////////
2019-10-20 16:12:37 +03:00
static const QStringList & UI_themes ( )
2017-11-26 15:37:39 +03:00
{
static const QStringList themes {
" default "
} ;
return themes ;
}
//////////////////////////////////////////////////////////////////////////
2017-02-08 00:14:49 +03:00
inline void clear_stream ( std : : stringstream & _stream )
{
# if defined(__GNUC__) && __GNUC__ < 5
// gcc 4 has a known bug which has been solved in gcc 5:
// std::stringstream has no swap() method :(
_stream . str ( std : : string ( ) ) ;
# else
std : : stringstream ( ) . swap ( _stream ) ;
# endif
}
2019-10-20 16:12:37 +03:00
static void convertPointSizes ( QString & style )
2017-11-26 15:37:39 +03:00
{
2019-10-20 16:12:37 +03:00
// Find font family
const auto fontMatch = QRegularExpression ( " font-family: \\ s* \\ \" (.*) \\ \" \\ s*; " ) . match ( style ) ;
const auto fontFamily = fontMatch . hasMatch ( ) ? fontMatch . captured ( fontMatch . lastCapturedIndex ( ) ) : QString ( " DejaVu Sans " ) ;
//QMessageBox::information(nullptr, "Found font family", fontFamily);
2018-05-19 23:40:01 +03:00
2019-10-20 16:12:37 +03:00
// Calculate point size using current font
const auto pointSizeF = QFontMetricsF ( QFont ( fontFamily , 100 ) ) . height ( ) * 1e-2 ;
//QMessageBox::information(nullptr, "Point size", QString("100pt = %1\n1pt = %2").arg(pointSizeF * 1e2).arg(pointSizeF));
2018-05-19 23:40:01 +03:00
2019-10-20 16:12:37 +03:00
// Find and convert all sizes from points to pixels
QRegularExpression re ( " ( \\ d+ \\ .? \\ d*) ex " ) ;
auto it = re . globalMatch ( style ) ;
2018-05-19 23:40:01 +03:00
2019-10-20 16:12:37 +03:00
std : : vector < QStringList > matches ;
{
QSet < QString > uniqueMatches ;
while ( it . hasNext ( ) )
{
const auto match = it . next ( ) ;
if ( ! uniqueMatches . contains ( match . captured ( ) ) )
2018-05-19 23:40:01 +03:00
{
2019-10-20 16:12:37 +03:00
uniqueMatches . insert ( match . captured ( ) ) ;
matches . emplace_back ( match . capturedTexts ( ) ) ;
2018-05-19 23:40:01 +03:00
}
2019-10-20 16:12:37 +03:00
}
}
for ( const auto & capturedTexts : matches )
{
const auto pt = capturedTexts . back ( ) . toDouble ( ) ;
const int pixels = static_cast < int > ( lround ( pointSizeF * pt ) ) ;
style . replace ( QString ( " %1 " ) . arg ( capturedTexts . front ( ) ) , QString ( " %1px " ) . arg ( pixels ) ) ;
style . replace ( QString ( " :%1 " ) . arg ( capturedTexts . front ( ) ) , QString ( " :%1px " ) . arg ( pixels ) ) ;
}
}
static void replaceOsDependentSettings ( QString & style )
{
// Find and convert all OS dependent options
// Example: "/*{lin}font-weight: bold;*/" -> "font-weight: bold;"
2018-05-19 23:40:01 +03:00
2019-10-20 16:12:37 +03:00
# if defined(_WIN32)
QRegularExpression re ( " / \\ * \\ {win \\ }(.*) \ \ */ " ) ;
# elif defined(__APPLE__)
QRegularExpression re ( " / \\ * \\ {mac \\ }(.*) \ \ */ " ) ;
# else
QRegularExpression re ( " / \\ * \\ {lin \\ }(.*) \ \ */ " ) ;
# endif
auto it = re . globalMatch ( style ) ;
std : : vector < QStringList > matches ;
{
QSet < QString > uniqueMatches ;
while ( it . hasNext ( ) )
{
const auto match = it . next ( ) ;
if ( ! uniqueMatches . contains ( match . captured ( ) ) )
2018-05-19 23:40:01 +03:00
{
2019-10-20 16:12:37 +03:00
uniqueMatches . insert ( match . captured ( ) ) ;
matches . emplace_back ( match . capturedTexts ( ) ) ;
2018-05-19 23:40:01 +03:00
}
2019-10-20 16:12:37 +03:00
}
}
2018-05-19 23:40:01 +03:00
2019-10-20 16:12:37 +03:00
for ( const auto & capturedTexts : matches )
{
style . replace ( capturedTexts . front ( ) , capturedTexts . back ( ) ) ;
}
}
static void loadTheme ( const QString & _theme )
{
QFile file ( QStringLiteral ( " :/themes/ " ) + _theme ) ;
if ( file . open ( QFile : : ReadOnly | QFile : : Text ) )
{
QTextStream in ( & file ) ;
QString style = in . readAll ( ) ;
if ( ! style . isEmpty ( ) )
{
convertPointSizes ( style ) ;
replaceOsDependentSettings ( style ) ;
2017-11-26 15:37:39 +03:00
qApp - > setStyleSheet ( style ) ;
2018-02-01 23:17:01 +03:00
}
2017-11-26 15:37:39 +03:00
}
}
2017-02-08 00:14:49 +03:00
//////////////////////////////////////////////////////////////////////////
2018-02-01 23:17:01 +03:00
DockWidget : : DockWidget ( const QString & title , QWidget * parent )
: QDockWidget ( title , parent )
, m_floatingButton ( new QPushButton ( ) )
{
m_floatingButton - > setObjectName ( " EasyDockWidgetFloatButton " ) ;
m_floatingButton - > setProperty ( " floating " , isFloating ( ) ) ;
connect ( m_floatingButton , & QPushButton : : clicked , this , & DockWidget : : toggleState ) ;
connect ( this , & QDockWidget : : topLevelChanged , this , & DockWidget : : onTopLevelChanged ) ;
2017-11-16 22:32:28 +03:00
auto closeButton = new QPushButton ( ) ;
closeButton - > setObjectName ( " EasyDockWidgetCloseButton " ) ;
2018-02-01 23:17:01 +03:00
connect ( closeButton , & QPushButton : : clicked , this , & DockWidget : : close ) ;
2017-11-16 22:32:28 +03:00
auto caption = new QWidget ( this ) ;
caption - > setObjectName ( " EasyDockWidgetTitle " ) ;
auto lay = new QHBoxLayout ( caption ) ;
lay - > setContentsMargins ( 0 , 0 , 0 , 0 ) ;
lay - > setSpacing ( 2 ) ;
lay - > addWidget ( new QLabel ( title ) ) ;
lay - > addStretch ( 100 ) ;
2018-02-01 23:17:01 +03:00
lay - > addWidget ( m_floatingButton ) ;
2017-11-16 22:32:28 +03:00
lay - > addWidget ( closeButton ) ;
setTitleBarWidget ( caption ) ;
}
2018-02-01 23:17:01 +03:00
DockWidget : : ~ DockWidget ( )
{
}
void DockWidget : : toggleState ( )
{
setFloating ( ! isFloating ( ) ) ;
}
void DockWidget : : onTopLevelChanged ( )
2017-11-16 22:32:28 +03:00
{
2018-02-01 23:17:01 +03:00
m_floatingButton - > setProperty ( " floating " , isFloating ( ) ) ;
m_floatingButton - > style ( ) - > unpolish ( m_floatingButton ) ;
m_floatingButton - > style ( ) - > polish ( m_floatingButton ) ;
m_floatingButton - > update ( ) ;
}
void MainWindow : : configureSizes ( )
{
QWidget w ( this ) ;
w . show ( ) ; // All sizes (font() size for example) become valid only after show()
2018-03-26 21:38:41 +03:00
EASY_GLOBALS . font . default_font = w . font ( ) ;
const QFontMetricsF fm ( w . font ( ) ) ;
2019-10-20 16:12:37 +03:00
# ifdef _WIN32
2018-06-09 02:18:39 +03:00
EASY_CONSTEXPR qreal DefaultHeight = 16 ;
# else
EASY_CONSTEXPR qreal DefaultHeight = 17 ;
# endif
2018-02-01 23:17:01 +03:00
auto & size = EASY_GLOBALS . size ;
2018-03-26 21:38:41 +03:00
size . font_height = static_cast < int > ( fm . height ( ) + 0.5 ) ;
2018-06-09 02:18:39 +03:00
size . pixelRatio = std : : max ( fm . height ( ) / DefaultHeight , 1.0 ) ;
2018-03-26 21:38:41 +03:00
size . font_line_spacing = static_cast < int > ( fm . lineSpacing ( ) + 0.5 ) ;
2018-02-01 23:17:01 +03:00
size . graphics_row_height = size . font_height + px ( 4 ) ;
size . graphics_row_spacing = 0 ;
size . graphics_row_full = size . graphics_row_height ;
size . threads_row_spacing = size . graphics_row_full > > 1 ;
2018-06-13 21:43:16 +03:00
size . timeline_height = size . font_height + px ( 10 ) ;
2019-10-20 16:12:37 +03:00
size . icon_size = size . font_height + px ( 5 ) ;
2018-02-01 23:17:01 +03:00
const auto fontFamily = w . font ( ) . family ( ) ;
const auto pixelSize = w . font ( ) . pixelSize ( ) ;
2018-05-19 23:40:01 +03:00
const auto pointSize = w . font ( ) . pointSize ( ) ;
const auto updateFont = [ & ] ( QFont & font )
2018-02-01 23:17:01 +03:00
{
font . setFamily ( fontFamily ) ;
2018-05-22 21:36:18 +03:00
if ( pixelSize > = 0 )
font . setPixelSize ( pixelSize ) ;
if ( pointSize > = 0 )
font . setPointSize ( pointSize ) ;
2018-02-01 23:17:01 +03:00
} ;
auto & fonts = EASY_GLOBALS . font ;
updateFont ( fonts . background ) ;
updateFont ( fonts . item ) ;
updateFont ( fonts . selected_item ) ;
fonts . ruler . setFamily ( fontFamily ) ;
2018-06-13 21:43:16 +03:00
/*
2018-02-01 23:17:01 +03:00
printf ( " Viewport info: \n " ) ;
printf ( " - device pixel ratio = %f \n " , size . pixelRatio ) ;
printf ( " - font height = %dpx \n " , size . font_height ) ;
2018-03-26 21:38:41 +03:00
printf ( " - font line spacing = %dpx \n " , size . font_line_spacing ) ;
2018-02-01 23:17:01 +03:00
printf ( " - diagram row = %dpx \n " , size . graphics_row_height ) ;
printf ( " - diagram spacing = %dpx \n " , size . threads_row_spacing ) ;
printf ( " - icon size = %dx%d px \n " , size . icon_size , size . icon_size ) ;
2018-06-13 21:43:16 +03:00
*/
2018-02-01 23:17:01 +03:00
w . hide ( ) ;
2017-11-16 22:32:28 +03:00
}
2018-04-22 03:34:26 +03:00
MainWindow : : MainWindow ( ) : Parent ( ) , m_theme ( " default " ) , m_lastAddress ( " localhost " ) , m_lastPort ( profiler : : DEFAULT_PORT )
2017-02-08 00:14:49 +03:00
{
2017-11-20 23:34:45 +03:00
{ QIcon icon ( " :/images/logo " ) ; if ( ! icon . isNull ( ) ) QApplication : : setWindowIcon ( icon ) ; }
2017-02-08 00:14:49 +03:00
setObjectName ( " ProfilerGUI_MainWindow " ) ;
2017-05-02 23:21:15 +03:00
setWindowTitle ( EASY_DEFAULT_WINDOW_TITLE ) ;
2017-02-08 00:14:49 +03:00
setDockNestingEnabled ( true ) ;
setAcceptDrops ( true ) ;
2017-02-15 21:45:14 +03:00
setStatusBar ( nullptr ) ;
2017-02-08 00:14:49 +03:00
2017-11-26 15:37:39 +03:00
loadSettings ( ) ;
loadTheme ( m_theme ) ;
2018-02-01 23:17:01 +03:00
configureSizes ( ) ;
resize ( px ( 800 ) , px ( 600 ) ) ;
2017-11-26 15:37:39 +03:00
2018-02-01 23:17:01 +03:00
m_graphicsView = new DockWidget ( " Diagram " , this ) ;
2017-02-08 00:14:49 +03:00
m_graphicsView - > setObjectName ( " ProfilerGUI_Diagram " ) ;
2018-02-01 23:17:01 +03:00
m_graphicsView - > setMinimumHeight ( px ( 50 ) ) ;
2017-02-08 00:14:49 +03:00
m_graphicsView - > setAllowedAreas ( Qt : : AllDockWidgetAreas ) ;
2018-01-28 20:52:17 +03:00
auto graphicsView = new DiagramWidget ( this ) ;
2018-01-21 19:37:44 +03:00
graphicsView - > setObjectName ( " ProfilerGUI_Diagram_GraphicsView " ) ;
2019-10-06 17:34:42 +03:00
connect ( this , & MainWindow : : activationChanged , graphicsView - > view ( ) , & BlocksGraphicsView : : onWindowActivationChanged , Qt : : QueuedConnection ) ;
connect ( this , & MainWindow : : activationChanged , graphicsView - > threadsView ( ) , & ThreadNamesWidget : : onWindowActivationChanged , Qt : : QueuedConnection ) ;
2017-02-08 00:14:49 +03:00
m_graphicsView - > setWidget ( graphicsView ) ;
2018-02-01 23:17:01 +03:00
m_treeWidget = new DockWidget ( " Hierarchy " , this ) ;
2017-02-08 00:14:49 +03:00
m_treeWidget - > setObjectName ( " ProfilerGUI_Hierarchy " ) ;
2018-02-01 23:17:01 +03:00
m_treeWidget - > setMinimumHeight ( px ( 50 ) ) ;
2017-02-08 00:14:49 +03:00
m_treeWidget - > setAllowedAreas ( Qt : : AllDockWidgetAreas ) ;
2018-01-28 20:52:17 +03:00
auto treeWidget = new HierarchyWidget ( this ) ;
2017-02-08 00:14:49 +03:00
m_treeWidget - > setWidget ( treeWidget ) ;
2018-02-01 23:17:01 +03:00
m_fpsViewer = new DockWidget ( " FPS Monitor " , this ) ;
2017-04-03 23:16:36 +03:00
m_fpsViewer - > setObjectName ( " ProfilerGUI_FPS " ) ;
2018-05-07 21:58:37 +03:00
m_fpsViewer - > setWidget ( new FpsWidget ( this ) ) ;
2017-04-03 23:16:36 +03:00
m_fpsViewer - > setAllowedAreas ( Qt : : TopDockWidgetArea | Qt : : BottomDockWidgetArea ) ;
2017-02-08 00:14:49 +03:00
addDockWidget ( Qt : : TopDockWidgetArea , m_graphicsView ) ;
addDockWidget ( Qt : : BottomDockWidgetArea , m_treeWidget ) ;
2017-04-03 23:16:36 +03:00
addDockWidget ( Qt : : TopDockWidgetArea , m_fpsViewer ) ;
2017-02-08 00:14:49 +03:00
# if EASY_GUI_USE_DESCRIPTORS_DOCK_WINDOW != 0
2018-01-28 20:52:17 +03:00
auto descTree = new BlockDescriptorsWidget ( ) ;
2018-02-01 23:17:01 +03:00
m_descTreeWidget = new DockWidget ( " Blocks " ) ;
2017-02-08 00:14:49 +03:00
m_descTreeWidget - > setObjectName ( " ProfilerGUI_Blocks " ) ;
2018-02-01 23:17:01 +03:00
m_descTreeWidget - > setMinimumHeight ( px ( 50 ) ) ;
2017-02-08 00:14:49 +03:00
m_descTreeWidget - > setAllowedAreas ( Qt : : AllDockWidgetAreas ) ;
m_descTreeWidget - > setWidget ( descTree ) ;
addDockWidget ( Qt : : BottomDockWidgetArea , m_descTreeWidget ) ;
# endif
auto toolbar = addToolBar ( " FileToolbar " ) ;
2018-02-01 23:17:01 +03:00
toolbar - > setIconSize ( applicationIconsSize ( ) ) ;
2017-02-08 00:14:49 +03:00
toolbar - > setObjectName ( " ProfilerGUI_FileToolbar " ) ;
toolbar - > setContentsMargins ( 1 , 0 , 1 , 0 ) ;
m_loadActionMenu = new QMenu ( this ) ;
auto action = m_loadActionMenu - > menuAction ( ) ;
action - > setText ( " Open file " ) ;
2017-11-26 15:37:39 +03:00
action - > setIcon ( QIcon ( imagePath ( " open " ) ) ) ;
2017-02-08 00:14:49 +03:00
connect ( action , & QAction : : triggered , this , & This : : onOpenFileClicked ) ;
toolbar - > addAction ( action ) ;
for ( const auto & f : m_lastFiles )
{
action = new QAction ( f , this ) ;
connect ( action , & QAction : : triggered , this , & This : : onOpenFileClicked ) ;
m_loadActionMenu - > addAction ( action ) ;
}
2017-11-26 15:37:39 +03:00
m_saveAction = toolbar - > addAction ( QIcon ( imagePath ( " save " ) ) , tr ( " Save " ) , this , SLOT ( onSaveFileClicked ( bool ) ) ) ;
m_deleteAction = toolbar - > addAction ( QIcon ( imagePath ( " delete " ) ) , tr ( " Clear all " ) , this , SLOT ( onDeleteClicked ( bool ) ) ) ;
2017-02-08 00:14:49 +03:00
m_saveAction - > setEnabled ( false ) ;
m_deleteAction - > setEnabled ( false ) ;
toolbar = addToolBar ( " ProfileToolbar " ) ;
2018-02-01 23:17:01 +03:00
toolbar - > setIconSize ( applicationIconsSize ( ) ) ;
2017-02-08 00:14:49 +03:00
toolbar - > setObjectName ( " ProfilerGUI_ProfileToolbar " ) ;
toolbar - > setContentsMargins ( 1 , 0 , 1 , 0 ) ;
2017-11-26 15:37:39 +03:00
toolbar - > addAction ( QIcon ( imagePath ( " list " ) ) , tr ( " Blocks " ) , this , SLOT ( onEditBlocksClicked ( bool ) ) ) ;
m_captureAction = toolbar - > addAction ( QIcon ( imagePath ( " start " ) ) , tr ( " Capture " ) , this , SLOT ( onCaptureClicked ( bool ) ) ) ;
2017-02-08 00:14:49 +03:00
m_captureAction - > setEnabled ( false ) ;
toolbar - > addSeparator ( ) ;
2017-11-26 15:37:39 +03:00
m_connectAction = toolbar - > addAction ( QIcon ( imagePath ( " connect " ) ) , tr ( " Connect " ) , this , SLOT ( onConnectClicked ( bool ) ) ) ;
2017-02-08 00:14:49 +03:00
auto lbl = new QLabel ( " Address: " , toolbar ) ;
lbl - > setContentsMargins ( 5 , 0 , 2 , 0 ) ;
toolbar - > addWidget ( lbl ) ;
m_addressEdit = new QLineEdit ( ) ;
m_addressEdit - > setToolTip ( " Enter IP-address or host name " ) ;
//QRegExp rx("^0*(2(5[0-5]|[0-4]\\d)|1?\\d{1,2})(\\.0*(2(5[0-5]|[0-4]\\d)|1?\\d{1,2})){3}$");
//m_addressEdit->setValidator(new QRegExpValidator(rx, m_addressEdit));
m_addressEdit - > setText ( m_lastAddress ) ;
m_addressEdit - > setFixedWidth ( ( m_addressEdit - > fontMetrics ( ) . width ( QString ( " 255.255.255.255 " ) ) * 3 ) / 2 ) ;
toolbar - > addWidget ( m_addressEdit ) ;
lbl = new QLabel ( " Port: " , toolbar ) ;
lbl - > setContentsMargins ( 5 , 0 , 2 , 0 ) ;
toolbar - > addWidget ( lbl ) ;
m_portEdit = new QLineEdit ( ) ;
m_portEdit - > setValidator ( new QIntValidator ( 1 , 65535 , m_portEdit ) ) ;
m_portEdit - > setText ( QString : : number ( m_lastPort ) ) ;
m_portEdit - > setFixedWidth ( m_portEdit - > fontMetrics ( ) . width ( QString ( " 000000 " ) ) + 10 ) ;
toolbar - > addWidget ( m_portEdit ) ;
2017-12-28 00:23:14 +03:00
connect ( m_addressEdit , & QLineEdit : : returnPressed , [ this ] { onConnectClicked ( true ) ; } ) ;
connect ( m_portEdit , & QLineEdit : : returnPressed , [ this ] { onConnectClicked ( true ) ; } ) ;
2017-02-08 00:14:49 +03:00
toolbar = addToolBar ( " SetupToolbar " ) ;
2018-02-01 23:17:01 +03:00
toolbar - > setIconSize ( applicationIconsSize ( ) ) ;
2017-02-08 00:14:49 +03:00
toolbar - > setObjectName ( " ProfilerGUI_SetupToolbar " ) ;
toolbar - > setContentsMargins ( 1 , 0 , 1 , 0 ) ;
2017-11-26 15:37:39 +03:00
toolbar - > addAction ( QIcon ( imagePath ( " expand " ) ) , " Expand all " , this , SLOT ( onExpandAllClicked ( bool ) ) ) ;
toolbar - > addAction ( QIcon ( imagePath ( " collapse " ) ) , " Collapse all " , this , SLOT ( onCollapseAllClicked ( bool ) ) ) ;
2017-02-08 00:14:49 +03:00
2018-03-18 03:12:10 +03:00
action = toolbar - > addAction ( QIcon ( imagePath ( " binoculars " ) ) , " See blocks hierarchy " ) ;
action - > setToolTip ( " Build blocks hierarchy \n for current visible area \n or zoom to current selected area. " ) ;
connect ( action , & QAction : : triggered , [ this ] ( bool ) {
static_cast < DiagramWidget * > ( m_graphicsView - > widget ( ) ) - > view ( ) - > inspectCurrentView ( true ) ;
} ) ;
2018-04-22 16:15:10 +03:00
action = toolbar - > addAction ( QIcon ( imagePath ( " crop " ) ) , " Snapshot " ) ;
2018-04-25 21:37:18 +03:00
action - > setToolTip ( " Take a snapshot. \n Save selected area to \n separate .prof file. " ) ;
action - > setEnabled ( false ) ;
2018-04-22 16:15:10 +03:00
connect ( action , & QAction : : triggered , this , & This : : onSnapshotClicked ) ;
2018-04-25 21:37:18 +03:00
connect ( & EASY_GLOBALS . events , & profiler_gui : : GlobalSignals : : rulerVisible , action , & QAction : : setEnabled ) ;
2018-04-22 03:34:26 +03:00
2017-02-08 00:14:49 +03:00
toolbar - > addSeparator ( ) ;
auto menu = new QMenu ( " Settings " , this ) ;
2017-06-07 02:08:53 +03:00
menu - > setToolTipsVisible ( true ) ;
2018-02-01 23:17:01 +03:00
auto toolButton = new QToolButton ( toolbar ) ;
2017-11-26 15:37:39 +03:00
toolButton - > setIcon ( QIcon ( imagePath ( " settings " ) ) ) ;
2017-02-08 00:14:49 +03:00
toolButton - > setMenu ( menu ) ;
toolButton - > setPopupMode ( QToolButton : : InstantPopup ) ;
toolbar - > addWidget ( toolButton ) ;
action = menu - > addAction ( " Statistics enabled " ) ;
action - > setCheckable ( true ) ;
action - > setChecked ( EASY_GLOBALS . enable_statistics ) ;
connect ( action , & QAction : : triggered , this , & This : : onEnableDisableStatistics ) ;
if ( EASY_GLOBALS . enable_statistics )
{
auto f = action - > font ( ) ;
f . setBold ( true ) ;
action - > setFont ( f ) ;
2017-11-26 15:37:39 +03:00
action - > setIcon ( QIcon ( imagePath ( " stats " ) ) ) ;
2017-02-08 00:14:49 +03:00
}
else
{
action - > setText ( " Statistics disabled " ) ;
2017-11-26 15:37:39 +03:00
action - > setIcon ( QIcon ( imagePath ( " stats-off " ) ) ) ;
2017-02-08 00:14:49 +03:00
}
2017-06-07 02:08:53 +03:00
action = menu - > addAction ( " Only frames on histogram " ) ;
action - > setToolTip ( " Display only top-level blocks on histogram. " ) ;
action - > setCheckable ( true ) ;
action - > setChecked ( EASY_GLOBALS . display_only_frames_on_histogram ) ;
connect ( action , & QAction : : triggered , [ this ] ( bool _checked )
{
EASY_GLOBALS . display_only_frames_on_histogram = _checked ;
emit EASY_GLOBALS . events . displayOnlyFramesOnHistogramChanged ( ) ;
} ) ;
2017-02-08 00:14:49 +03:00
menu - > addSeparator ( ) ;
auto submenu = menu - > addMenu ( " View " ) ;
submenu - > setToolTipsVisible ( true ) ;
2018-05-24 02:19:48 +03:00
action = submenu - > addAction ( " Draw borders " ) ;
action - > setToolTip ( " Draw borders for blocks on diagram. \n This slightly reduces performance. " ) ;
2017-02-08 00:14:49 +03:00
action - > setCheckable ( true ) ;
action - > setChecked ( EASY_GLOBALS . draw_graphics_items_borders ) ;
connect ( action , & QAction : : triggered , [ this ] ( bool _checked ) { EASY_GLOBALS . draw_graphics_items_borders = _checked ; refreshDiagram ( ) ; } ) ;
action = submenu - > addAction ( " Overlap narrow children " ) ;
action - > setToolTip ( " Children blocks will be overlaped by narrow \n parent blocks. See also \' Blocks narrow size \' . \n This improves performance. " ) ;
action - > setCheckable ( true ) ;
action - > setChecked ( EASY_GLOBALS . hide_narrow_children ) ;
connect ( action , & QAction : : triggered , [ this ] ( bool _checked ) { EASY_GLOBALS . hide_narrow_children = _checked ; refreshDiagram ( ) ; } ) ;
action = submenu - > addAction ( " Hide min-size blocks " ) ;
action - > setToolTip ( " Hides blocks which screen size \n is less than \' Min blocks size \' . " ) ;
action - > setCheckable ( true ) ;
action - > setChecked ( EASY_GLOBALS . hide_minsize_blocks ) ;
connect ( action , & QAction : : triggered , [ this ] ( bool _checked ) { EASY_GLOBALS . hide_minsize_blocks = _checked ; refreshDiagram ( ) ; } ) ;
action = submenu - > addAction ( " Build hierarchy only for current thread " ) ;
action - > setToolTip ( " Hierarchy tree will be built \n for blocks from current thread only. \n This improves performance \n and saves a lot of memory. " ) ;
action - > setCheckable ( true ) ;
action - > setChecked ( EASY_GLOBALS . only_current_thread_hierarchy ) ;
connect ( action , & QAction : : triggered , this , & This : : onHierarchyFlagChange ) ;
action = submenu - > addAction ( " Add zero blocks to hierarchy " ) ;
action - > setToolTip ( " Zero duration blocks will be added into hierarchy tree. \n This reduces performance and increases memory consumption. " ) ;
action - > setCheckable ( true ) ;
action - > setChecked ( EASY_GLOBALS . add_zero_blocks_to_hierarchy ) ;
connect ( action , & QAction : : triggered , [ this ] ( bool _checked )
{
EASY_GLOBALS . add_zero_blocks_to_hierarchy = _checked ;
emit EASY_GLOBALS . events . hierarchyFlagChanged ( _checked ) ;
} ) ;
action = submenu - > addAction ( " Enable zero duration blocks on diagram " ) ;
action - > setToolTip ( " If checked then allows diagram to paint zero duration blocks \n with 1px width on each scale. Otherwise, such blocks will be resized \n to 250ns duration. " ) ;
action - > setCheckable ( true ) ;
action - > setChecked ( EASY_GLOBALS . enable_zero_length ) ;
connect ( action , & QAction : : triggered , [ this ] ( bool _checked ) { EASY_GLOBALS . enable_zero_length = _checked ; refreshDiagram ( ) ; } ) ;
action = submenu - > addAction ( " Highlight similar blocks " ) ;
action - > setToolTip ( " Highlight all visible blocks which are similar \n to the current selected block. \n This reduces performance. " ) ;
action - > setCheckable ( true ) ;
action - > setChecked ( EASY_GLOBALS . highlight_blocks_with_same_id ) ;
connect ( action , & QAction : : triggered , [ this ] ( bool _checked ) { EASY_GLOBALS . highlight_blocks_with_same_id = _checked ; refreshDiagram ( ) ; } ) ;
action = submenu - > addAction ( " Collapse blocks on tree reset " ) ;
action - > setToolTip ( " This collapses all blocks on diagram \n after hierarchy tree reset. " ) ;
action - > setCheckable ( true ) ;
action - > setChecked ( EASY_GLOBALS . collapse_items_on_tree_close ) ;
connect ( action , & QAction : : triggered , this , & This : : onCollapseItemsAfterCloseChanged ) ;
action = submenu - > addAction ( " Expand all on file open " ) ;
action - > setToolTip ( " If checked then all blocks on diagram \n will be initially expanded. " ) ;
action - > setCheckable ( true ) ;
action - > setChecked ( EASY_GLOBALS . all_items_expanded_by_default ) ;
connect ( action , & QAction : : triggered , this , & This : : onAllItemsExpandedByDefaultChange ) ;
action = submenu - > addAction ( " Bind diagram and tree expand " ) ;
action - > setToolTip ( " Expanding/collapsing blocks at diagram expands/collapses \n blocks at hierarchy tree and wise versa. " ) ;
action - > setCheckable ( true ) ;
action - > setChecked ( EASY_GLOBALS . bind_scene_and_tree_expand_status ) ;
connect ( action , & QAction : : triggered , this , & This : : onBindExpandStatusChange ) ;
2019-10-20 16:12:37 +03:00
action = submenu - > addAction ( " Hide stats for single blocks in tree " ) ;
action - > setToolTip ( " If checked then such stats like Min,Max,Avg etc. \n will not be displayed in stats tree for blocks \n with number of calls == 1 " ) ;
action - > setCheckable ( true ) ;
action - > setChecked ( EASY_GLOBALS . display_only_relevant_stats ) ;
connect ( action , & QAction : : triggered , this , & This : : onDisplayRelevantStatsChange ) ;
2017-02-08 00:14:49 +03:00
action = submenu - > addAction ( " Selecting block changes current thread " ) ;
action - > setToolTip ( " Automatically select thread while selecting a block. \n If not checked then you will have to select current thread \n manually double clicking on thread name on a diagram. " ) ;
action - > setCheckable ( true ) ;
action - > setChecked ( EASY_GLOBALS . selecting_block_changes_thread ) ;
connect ( action , & QAction : : triggered , [ this ] ( bool _checked ) { EASY_GLOBALS . selecting_block_changes_thread = _checked ; } ) ;
2017-03-13 20:30:57 +03:00
action = submenu - > addAction ( " Draw event markers " ) ;
action - > setToolTip ( " Display event markers under the blocks \n (even if event-blocks are not visible). \n This slightly reduces performance. " ) ;
2017-02-08 00:14:49 +03:00
action - > setCheckable ( true ) ;
2017-03-13 20:30:57 +03:00
action - > setChecked ( EASY_GLOBALS . enable_event_markers ) ;
connect ( action , & QAction : : triggered , [ this ] ( bool _checked )
{
EASY_GLOBALS . enable_event_markers = _checked ;
refreshDiagram ( ) ;
} ) ;
action = submenu - > addAction ( " Automatically adjust histogram height " ) ;
action - > setToolTip ( " You do not need to adjust boundaries manually, \n but this restricts you from adjusting boundaries at all (zoom mode). \n You can still adjust boundaries in overview mode though. " ) ;
action - > setCheckable ( true ) ;
action - > setChecked ( EASY_GLOBALS . auto_adjust_histogram_height ) ;
connect ( action , & QAction : : triggered , [ ] ( bool _checked )
{
EASY_GLOBALS . auto_adjust_histogram_height = _checked ;
emit EASY_GLOBALS . events . autoAdjustHistogramChanged ( ) ;
} ) ;
2017-02-08 00:14:49 +03:00
2018-01-21 19:37:44 +03:00
action = submenu - > addAction ( " Automatically adjust chart height " ) ;
action - > setToolTip ( " Same as similar option for histogram \n but used for arbitrary values charts. " ) ;
action - > setCheckable ( true ) ;
action - > setChecked ( EASY_GLOBALS . auto_adjust_chart_height ) ;
connect ( action , & QAction : : triggered , [ ] ( bool _checked )
{
EASY_GLOBALS . auto_adjust_chart_height = _checked ;
emit EASY_GLOBALS . events . autoAdjustChartChanged ( ) ;
} ) ;
2017-02-08 00:14:49 +03:00
action = submenu - > addAction ( " Use decorated thread names " ) ;
action - > setToolTip ( " Add \' Thread \' word into thread name if there is no one already. \n Examples: \' Render \' will change to \' Render Thread \' \n \' WorkerThread \' will not change. " ) ;
action - > setCheckable ( true ) ;
action - > setChecked ( EASY_GLOBALS . use_decorated_thread_name ) ;
connect ( action , & QAction : : triggered , [ this ] ( bool _checked )
{
EASY_GLOBALS . use_decorated_thread_name = _checked ;
emit EASY_GLOBALS . events . threadNameDecorationChanged ( ) ;
} ) ;
2017-06-05 21:26:10 +03:00
action = submenu - > addAction ( " Display hex thread id " ) ;
action - > setToolTip ( " Display hex thread id instead of decimal. " ) ;
action - > setCheckable ( true ) ;
action - > setChecked ( EASY_GLOBALS . hex_thread_id ) ;
connect ( action , & QAction : : triggered , [ this ] ( bool _checked )
{
EASY_GLOBALS . hex_thread_id = _checked ;
emit EASY_GLOBALS . events . hexThreadIdChanged ( ) ;
} ) ;
2017-02-08 00:14:49 +03:00
submenu - > addSeparator ( ) ;
auto actionGroup = new QActionGroup ( this ) ;
actionGroup - > setExclusive ( true ) ;
2018-05-24 02:19:48 +03:00
action = new QAction ( " Ruler text at top " , actionGroup ) ;
action - > setToolTip ( " Draw duration of selected interval \n at the top of the diagram. " ) ;
2017-02-08 00:14:49 +03:00
action - > setCheckable ( true ) ;
2018-05-24 02:19:48 +03:00
action - > setData ( static_cast < int > ( profiler_gui : : RulerTextPosition_Top ) ) ;
if ( EASY_GLOBALS . chrono_text_position = = profiler_gui : : RulerTextPosition_Top )
2017-02-08 00:14:49 +03:00
action - > setChecked ( true ) ;
submenu - > addAction ( action ) ;
2018-05-24 02:19:48 +03:00
connect ( action , & QAction : : triggered , this , & This : : onRulerTextPosChanged ) ;
2017-02-08 00:14:49 +03:00
2018-05-24 02:19:48 +03:00
action = new QAction ( " Ruler text at center " , actionGroup ) ;
action - > setToolTip ( " Draw duration of selected interval \n at the center of the diagram. " ) ;
2017-02-08 00:14:49 +03:00
action - > setCheckable ( true ) ;
2018-05-24 02:19:48 +03:00
action - > setData ( static_cast < int > ( profiler_gui : : RulerTextPosition_Center ) ) ;
if ( EASY_GLOBALS . chrono_text_position = = profiler_gui : : RulerTextPosition_Center )
2017-02-08 00:14:49 +03:00
action - > setChecked ( true ) ;
submenu - > addAction ( action ) ;
2018-05-24 02:19:48 +03:00
connect ( action , & QAction : : triggered , this , & This : : onRulerTextPosChanged ) ;
2017-02-08 00:14:49 +03:00
2018-05-24 02:19:48 +03:00
action = new QAction ( " Ruler text at bottom " , actionGroup ) ;
action - > setToolTip ( " Draw duration of selected interval \n at the bottom of the diagram. " ) ;
2017-02-08 00:14:49 +03:00
action - > setCheckable ( true ) ;
2018-05-24 02:19:48 +03:00
action - > setData ( static_cast < int > ( profiler_gui : : RulerTextPosition_Bottom ) ) ;
if ( EASY_GLOBALS . chrono_text_position = = profiler_gui : : RulerTextPosition_Bottom )
2017-02-08 00:14:49 +03:00
action - > setChecked ( true ) ;
submenu - > addAction ( action ) ;
2018-05-24 02:19:48 +03:00
connect ( action , & QAction : : triggered , this , & This : : onRulerTextPosChanged ) ;
2017-02-08 00:14:49 +03:00
submenu - > addSeparator ( ) ;
auto w = new QWidget ( submenu ) ;
auto l = new QHBoxLayout ( w ) ;
2017-11-16 22:32:28 +03:00
l - > setContentsMargins ( 26 , 1 , 16 , 1 ) ;
2017-02-08 00:14:49 +03:00
l - > addWidget ( new QLabel ( " Min blocks spacing, px " , w ) , 0 , Qt : : AlignLeft ) ;
auto spinbox = new QSpinBox ( w ) ;
2017-04-03 23:16:36 +03:00
spinbox - > setRange ( 0 , 400 ) ;
2017-02-08 00:14:49 +03:00
spinbox - > setValue ( EASY_GLOBALS . blocks_spacing ) ;
2018-06-13 21:43:16 +03:00
spinbox - > setFixedWidth ( px ( 70 ) ) ;
connect ( spinbox , Overload < int > : : of ( & QSpinBox : : valueChanged ) , this , & This : : onSpacingChange ) ;
2017-02-08 00:14:49 +03:00
l - > addWidget ( spinbox ) ;
w - > setLayout ( l ) ;
auto waction = new QWidgetAction ( submenu ) ;
waction - > setDefaultWidget ( w ) ;
submenu - > addAction ( waction ) ;
w = new QWidget ( submenu ) ;
l = new QHBoxLayout ( w ) ;
2017-11-16 22:32:28 +03:00
l - > setContentsMargins ( 26 , 1 , 16 , 1 ) ;
2017-02-08 00:14:49 +03:00
l - > addWidget ( new QLabel ( " Min blocks size, px " , w ) , 0 , Qt : : AlignLeft ) ;
spinbox = new QSpinBox ( w ) ;
2017-04-03 23:16:36 +03:00
spinbox - > setRange ( 1 , 400 ) ;
2017-02-08 00:14:49 +03:00
spinbox - > setValue ( EASY_GLOBALS . blocks_size_min ) ;
2018-06-13 21:43:16 +03:00
spinbox - > setFixedWidth ( px ( 70 ) ) ;
connect ( spinbox , Overload < int > : : of ( & QSpinBox : : valueChanged ) , this , & This : : onMinSizeChange ) ;
2017-02-08 00:14:49 +03:00
l - > addWidget ( spinbox ) ;
w - > setLayout ( l ) ;
waction = new QWidgetAction ( submenu ) ;
waction - > setDefaultWidget ( w ) ;
submenu - > addAction ( waction ) ;
w = new QWidget ( submenu ) ;
l = new QHBoxLayout ( w ) ;
2017-11-16 22:32:28 +03:00
l - > setContentsMargins ( 26 , 1 , 16 , 1 ) ;
2017-02-08 00:14:49 +03:00
l - > addWidget ( new QLabel ( " Blocks narrow size, px " , w ) , 0 , Qt : : AlignLeft ) ;
spinbox = new QSpinBox ( w ) ;
2017-04-03 23:16:36 +03:00
spinbox - > setRange ( 1 , 400 ) ;
2017-02-08 00:14:49 +03:00
spinbox - > setValue ( EASY_GLOBALS . blocks_narrow_size ) ;
2018-06-13 21:43:16 +03:00
spinbox - > setFixedWidth ( px ( 70 ) ) ;
connect ( spinbox , Overload < int > : : of ( & QSpinBox : : valueChanged ) , this , & This : : onNarrowSizeChange ) ;
2017-02-08 00:14:49 +03:00
l - > addWidget ( spinbox ) ;
w - > setLayout ( l ) ;
waction = new QWidgetAction ( submenu ) ;
waction - > setDefaultWidget ( w ) ;
submenu - > addAction ( waction ) ;
2017-04-03 23:16:36 +03:00
submenu = menu - > addMenu ( " FPS Monitor " ) ;
w = new QWidget ( submenu ) ;
l = new QHBoxLayout ( w ) ;
2017-11-16 22:32:28 +03:00
l - > setContentsMargins ( 26 , 1 , 16 , 1 ) ;
2017-04-03 23:16:36 +03:00
l - > addWidget ( new QLabel ( " Request interval, ms " , w ) , 0 , Qt : : AlignLeft ) ;
spinbox = new QSpinBox ( w ) ;
spinbox - > setRange ( 1 , 600000 ) ;
spinbox - > setValue ( EASY_GLOBALS . fps_timer_interval ) ;
2018-06-13 21:43:16 +03:00
spinbox - > setFixedWidth ( px ( 70 ) ) ;
connect ( spinbox , Overload < int > : : of ( & QSpinBox : : valueChanged ) , this , & This : : onFpsIntervalChange ) ;
2017-04-03 23:16:36 +03:00
l - > addWidget ( spinbox ) ;
w - > setLayout ( l ) ;
waction = new QWidgetAction ( submenu ) ;
waction - > setDefaultWidget ( w ) ;
submenu - > addAction ( waction ) ;
w = new QWidget ( submenu ) ;
l = new QHBoxLayout ( w ) ;
2017-11-16 22:32:28 +03:00
l - > setContentsMargins ( 26 , 1 , 16 , 1 ) ;
2017-04-03 23:16:36 +03:00
l - > addWidget ( new QLabel ( " Max history size " , w ) , 0 , Qt : : AlignLeft ) ;
spinbox = new QSpinBox ( w ) ;
spinbox - > setRange ( 2 , 200 ) ;
spinbox - > setValue ( EASY_GLOBALS . max_fps_history ) ;
2018-06-13 21:43:16 +03:00
spinbox - > setFixedWidth ( px ( 70 ) ) ;
connect ( spinbox , Overload < int > : : of ( & QSpinBox : : valueChanged ) , this , & This : : onFpsHistoryChange ) ;
2017-04-03 23:16:36 +03:00
l - > addWidget ( spinbox ) ;
w - > setLayout ( l ) ;
waction = new QWidgetAction ( submenu ) ;
waction - > setDefaultWidget ( w ) ;
submenu - > addAction ( waction ) ;
2017-04-05 22:37:40 +03:00
w = new QWidget ( submenu ) ;
l = new QHBoxLayout ( w ) ;
2017-11-16 22:32:28 +03:00
l - > setContentsMargins ( 26 , 1 , 16 , 1 ) ;
2017-04-05 22:37:40 +03:00
l - > addWidget ( new QLabel ( " Line width, px " , w ) , 0 , Qt : : AlignLeft ) ;
spinbox = new QSpinBox ( w ) ;
spinbox - > setRange ( 1 , 6 ) ;
spinbox - > setValue ( EASY_GLOBALS . fps_widget_line_width ) ;
2018-06-13 21:43:16 +03:00
spinbox - > setFixedWidth ( px ( 70 ) ) ;
connect ( spinbox , Overload < int > : : of ( & QSpinBox : : valueChanged ) , this , & This : : onFpsMonitorLineWidthChange ) ;
2017-04-05 22:37:40 +03:00
l - > addWidget ( spinbox ) ;
w - > setLayout ( l ) ;
waction = new QWidgetAction ( submenu ) ;
waction - > setDefaultWidget ( w ) ;
submenu - > addAction ( waction ) ;
2017-04-03 23:16:36 +03:00
2017-02-08 00:14:49 +03:00
submenu = menu - > addMenu ( " Units " ) ;
actionGroup = new QActionGroup ( this ) ;
actionGroup - > setExclusive ( true ) ;
action = new QAction ( " Auto " , actionGroup ) ;
action - > setCheckable ( true ) ;
2018-04-22 03:34:26 +03:00
action - > setData ( static_cast < int > ( profiler_gui : : TimeUnits_auto ) ) ;
if ( EASY_GLOBALS . time_units = = profiler_gui : : TimeUnits_auto )
2017-02-08 00:14:49 +03:00
action - > setChecked ( true ) ;
submenu - > addAction ( action ) ;
connect ( action , & QAction : : triggered , this , & This : : onUnitsChanged ) ;
action = new QAction ( " Milliseconds " , actionGroup ) ;
action - > setCheckable ( true ) ;
2018-04-22 03:34:26 +03:00
action - > setData ( static_cast < int > ( profiler_gui : : TimeUnits_ms ) ) ;
if ( EASY_GLOBALS . time_units = = profiler_gui : : TimeUnits_ms )
2017-02-08 00:14:49 +03:00
action - > setChecked ( true ) ;
submenu - > addAction ( action ) ;
connect ( action , & QAction : : triggered , this , & This : : onUnitsChanged ) ;
action = new QAction ( " Microseconds " , actionGroup ) ;
action - > setCheckable ( true ) ;
2018-04-22 03:34:26 +03:00
action - > setData ( static_cast < int > ( profiler_gui : : TimeUnits_us ) ) ;
if ( EASY_GLOBALS . time_units = = profiler_gui : : TimeUnits_us )
2017-02-08 00:14:49 +03:00
action - > setChecked ( true ) ;
submenu - > addAction ( action ) ;
connect ( action , & QAction : : triggered , this , & This : : onUnitsChanged ) ;
action = new QAction ( " Nanoseconds " , actionGroup ) ;
action - > setCheckable ( true ) ;
2018-04-22 03:34:26 +03:00
action - > setData ( static_cast < int > ( profiler_gui : : TimeUnits_ns ) ) ;
if ( EASY_GLOBALS . time_units = = profiler_gui : : TimeUnits_ns )
2017-02-08 00:14:49 +03:00
action - > setChecked ( true ) ;
submenu - > addAction ( action ) ;
connect ( action , & QAction : : triggered , this , & This : : onUnitsChanged ) ;
submenu = menu - > addMenu ( " Remote " ) ;
m_eventTracingEnableAction = submenu - > addAction ( " Event tracing enabled " ) ;
m_eventTracingEnableAction - > setCheckable ( true ) ;
m_eventTracingEnableAction - > setEnabled ( false ) ;
connect ( m_eventTracingEnableAction , & QAction : : triggered , this , & This : : onEventTracingEnableChange ) ;
m_eventTracingPriorityAction = submenu - > addAction ( " Low priority event tracing " ) ;
m_eventTracingPriorityAction - > setCheckable ( true ) ;
m_eventTracingPriorityAction - > setChecked ( EASY_OPTION_LOW_PRIORITY_EVENT_TRACING ) ;
m_eventTracingPriorityAction - > setEnabled ( false ) ;
connect ( m_eventTracingPriorityAction , & QAction : : triggered , this , & This : : onEventTracingPriorityChange ) ;
submenu = menu - > addMenu ( " Encoding " ) ;
actionGroup = new QActionGroup ( this ) ;
actionGroup - > setExclusive ( true ) ;
auto default_codec_mib = QTextCodec : : codecForLocale ( ) - > mibEnum ( ) ;
{
2017-11-23 22:01:44 +03:00
QList < QAction * > actions ;
2017-02-08 00:14:49 +03:00
2017-11-23 22:01:44 +03:00
for ( int mib : QTextCodec : : availableMibs ( ) )
{
auto codec = QTextCodec : : codecForMib ( mib ) - > name ( ) ;
action = new QAction ( codec , actionGroup ) ;
action - > setData ( mib ) ;
action - > setCheckable ( true ) ;
if ( mib = = default_codec_mib )
action - > setChecked ( true ) ;
actions . push_back ( action ) ;
connect ( action , & QAction : : triggered , this , & This : : onEncodingChanged ) ;
}
qSort ( actions . begin ( ) , actions . end ( ) , [ ] ( QAction * lhs , QAction * rhs ) {
return lhs - > text ( ) . compare ( rhs - > text ( ) , Qt : : CaseInsensitive ) < 0 ;
} ) ;
2017-02-08 00:14:49 +03:00
2017-11-23 22:01:44 +03:00
submenu - > addActions ( actions ) ;
2017-02-08 00:14:49 +03:00
}
2017-11-26 15:37:39 +03:00
2018-06-09 02:18:39 +03:00
submenu = menu - > addMenu ( " Appearance " ) ;
actionGroup = new QActionGroup ( this ) ;
actionGroup - > setExclusive ( true ) ;
action = submenu - > addAction ( " Custom window headers " ) ;
action - > setCheckable ( true ) ;
action - > setChecked ( EASY_GLOBALS . use_custom_window_header ) ;
connect ( action , & QAction : : triggered , [ = ] ( bool checked )
{
actionGroup - > setEnabled ( checked ) ;
onCustomWindowHeaderTriggered ( checked ) ;
} ) ;
action = new QAction ( " Position: right " , actionGroup ) ;
action - > setCheckable ( true ) ;
action - > setChecked ( EASY_GLOBALS . is_right_window_header_controls ) ;
connect ( action , & QAction : : triggered , this , & This : : onRightWindowHeaderPosition ) ;
submenu - > addAction ( action ) ;
action = new QAction ( " Position: left " , actionGroup ) ;
action - > setCheckable ( true ) ;
action - > setChecked ( ! EASY_GLOBALS . is_right_window_header_controls ) ;
connect ( action , & QAction : : triggered , this , & This : : onLeftWindowHeaderPosition ) ;
submenu - > addAction ( action ) ;
actionGroup - > setEnabled ( EASY_GLOBALS . use_custom_window_header ) ;
submenu - > addSeparator ( ) ;
action = submenu - > addAction ( " See viewport info " ) ;
connect ( action , & QAction : : triggered , this , & This : : onViewportInfoClicked ) ;
auto submenu2 = submenu - > addMenu ( " Theme " ) ;
2017-11-26 15:37:39 +03:00
actionGroup = new QActionGroup ( this ) ;
actionGroup - > setExclusive ( true ) ;
for ( const auto & theme : UI_themes ( ) )
{
action = new QAction ( theme , actionGroup ) ;
action - > setCheckable ( true ) ;
action - > setChecked ( action - > text ( ) = = EASY_GLOBALS . theme ) ;
2018-01-28 20:52:17 +03:00
connect ( action , & QAction : : triggered , this , & MainWindow : : onThemeChange ) ;
2018-06-09 02:18:39 +03:00
submenu2 - > addAction ( action ) ;
2017-11-26 15:37:39 +03:00
}
2018-03-15 21:01:19 +03:00
2017-02-08 00:14:49 +03:00
auto tb_height = toolbar - > height ( ) + 4 ;
toolbar = addToolBar ( " FrameToolbar " ) ;
2018-02-01 23:17:01 +03:00
toolbar - > setIconSize ( applicationIconsSize ( ) ) ;
2017-02-08 00:14:49 +03:00
toolbar - > setObjectName ( " ProfilerGUI_FrameToolbar " ) ;
toolbar - > setContentsMargins ( 1 , 0 , 1 , 0 ) ;
toolbar - > setMinimumHeight ( tb_height ) ;
2017-03-07 00:29:34 +03:00
lbl = new QLabel ( " Expected frame time: " , toolbar ) ;
2017-02-08 00:14:49 +03:00
lbl - > setContentsMargins ( 5 , 2 , 2 , 2 ) ;
toolbar - > addWidget ( lbl ) ;
m_frameTimeEdit = new QLineEdit ( ) ;
2018-06-13 21:43:16 +03:00
m_frameTimeEdit - > setFixedWidth ( px ( 70 ) ) ;
2017-02-08 00:14:49 +03:00
auto val = new QDoubleValidator ( m_frameTimeEdit ) ;
val - > setLocale ( QLocale : : c ( ) ) ;
val - > setBottom ( 0 ) ;
m_frameTimeEdit - > setValidator ( val ) ;
m_frameTimeEdit - > setText ( QString : : number ( EASY_GLOBALS . frame_time * 1e-3 ) ) ;
connect ( m_frameTimeEdit , & QLineEdit : : editingFinished , this , & This : : onFrameTimeEditFinish ) ;
2018-04-22 03:34:26 +03:00
connect ( & EASY_GLOBALS . events , & profiler_gui : : GlobalSignals : : expectedFrameTimeChanged , this , & This : : onFrameTimeChanged ) ;
2017-02-08 00:14:49 +03:00
toolbar - > addWidget ( m_frameTimeEdit ) ;
lbl = new QLabel ( " ms " , toolbar ) ;
lbl - > setContentsMargins ( 5 , 2 , 1 , 1 ) ;
toolbar - > addWidget ( lbl ) ;
2018-04-22 03:34:26 +03:00
m_readerTimer . setInterval ( LOADER_TIMER_INTERVAL ) ;
2017-02-08 00:14:49 +03:00
2018-01-28 20:52:17 +03:00
connect ( graphicsView - > view ( ) , & BlocksGraphicsView : : intervalChanged , treeWidget - > tree ( ) , & BlocksTreeWidget : : setTreeBlocks ) ;
2017-02-08 00:14:49 +03:00
connect ( & m_readerTimer , & QTimer : : timeout , this , & This : : onFileReaderTimeout ) ;
connect ( & m_listenerTimer , & QTimer : : timeout , this , & This : : onListenerTimerTimeout ) ;
2017-04-03 23:16:36 +03:00
connect ( & m_fpsRequestTimer , & QTimer : : timeout , this , & This : : onFrameTimeRequestTimeout ) ;
2017-02-08 00:14:49 +03:00
loadGeometry ( ) ;
if ( QCoreApplication : : arguments ( ) . size ( ) > 1 )
{
auto opened_filename = QCoreApplication : : arguments ( ) . at ( 1 ) ;
loadFile ( opened_filename ) ;
}
2018-03-15 21:01:19 +03:00
using profiler_gui : : GlobalSignals ;
connect ( & EASY_GLOBALS . events , & GlobalSignals : : blockStatusChanged , this , & This : : onBlockStatusChange ) ;
connect ( & EASY_GLOBALS . events , & GlobalSignals : : blocksRefreshRequired , this , & This : : onGetBlockDescriptionsClicked ) ;
connect ( & EASY_GLOBALS . events , & GlobalSignals : : selectValue , this , & This : : onSelectValue ) ;
2017-02-08 00:14:49 +03:00
}
2018-01-28 20:52:17 +03:00
MainWindow : : ~ MainWindow ( )
2017-02-08 00:14:49 +03:00
{
}
2018-02-20 22:11:43 +03:00
void MainWindow : : validateLastDir ( )
{
if ( m_lastFiles . empty ( ) )
EASY_GLOBALS . lastFileDir = QString ( ) ;
else
EASY_GLOBALS . lastFileDir = QFileInfo ( m_lastFiles . front ( ) ) . absoluteDir ( ) . canonicalPath ( ) ;
}
2017-02-08 00:14:49 +03:00
//////////////////////////////////////////////////////////////////////////
2018-01-28 20:52:17 +03:00
void MainWindow : : dragEnterEvent ( QDragEnterEvent * drag_event )
2017-02-08 00:14:49 +03:00
{
if ( drag_event - > mimeData ( ) - > hasUrls ( ) )
drag_event - > acceptProposedAction ( ) ;
}
2018-01-28 20:52:17 +03:00
void MainWindow : : dragMoveEvent ( QDragMoveEvent * drag_event )
2017-02-08 00:14:49 +03:00
{
if ( drag_event - > mimeData ( ) - > hasUrls ( ) )
drag_event - > acceptProposedAction ( ) ;
}
2018-01-28 20:52:17 +03:00
void MainWindow : : dragLeaveEvent ( QDragLeaveEvent * drag_event )
2017-02-08 00:14:49 +03:00
{
drag_event - > accept ( ) ;
}
2018-01-28 20:52:17 +03:00
void MainWindow : : dropEvent ( QDropEvent * drop_event )
2017-02-08 00:14:49 +03:00
{
const auto & urls = drop_event - > mimeData ( ) - > urls ( ) ;
if ( ! urls . empty ( ) )
2017-05-02 23:21:15 +03:00
{
if ( m_bNetworkFileRegime )
{
// Warn user about unsaved network information and suggest to save
2018-06-09 02:18:39 +03:00
auto result = Dialog : : question ( this , " Unsaved session "
, " You have unsaved data! \n Save before opening new file? "
, QMessageBox : : Yes | QMessageBox : : No | QMessageBox : : Cancel ) ;
2017-05-02 23:21:15 +03:00
if ( result = = QMessageBox : : Yes )
{
onSaveFileClicked ( true ) ;
}
else if ( result ! = QMessageBox : : No )
{
// User cancelled opening new file
return ;
}
}
2017-02-08 00:14:49 +03:00
loadFile ( urls . front ( ) . toLocalFile ( ) ) ;
2017-05-02 23:21:15 +03:00
}
2017-02-08 00:14:49 +03:00
}
//////////////////////////////////////////////////////////////////////////
2018-01-28 20:52:17 +03:00
void MainWindow : : onThemeChange ( bool )
2017-11-26 15:37:39 +03:00
{
auto action = qobject_cast < QAction * > ( sender ( ) ) ;
if ( action = = nullptr )
return ;
2017-11-27 22:02:15 +03:00
auto newTheme = action - > text ( ) ;
if ( m_theme ! = newTheme )
{
m_theme = std : : move ( newTheme ) ;
2018-05-19 23:40:01 +03:00
2018-06-09 02:18:39 +03:00
Dialog : : information ( this , " UI theme changed "
, " You may need to restart the application \n to apply the theme correctly. " ) ;
2018-05-19 23:40:01 +03:00
loadTheme ( m_theme ) ;
validateLineEdits ( ) ;
configureSizes ( ) ;
2017-11-27 22:02:15 +03:00
}
2017-11-26 15:37:39 +03:00
}
//////////////////////////////////////////////////////////////////////////
2018-01-28 20:52:17 +03:00
void MainWindow : : onOpenFileClicked ( bool )
2017-02-08 00:14:49 +03:00
{
auto action = qobject_cast < QAction * > ( sender ( ) ) ;
if ( action = = nullptr )
return ;
2017-05-02 23:21:15 +03:00
QString filename ;
2017-02-08 00:14:49 +03:00
if ( action = = m_loadActionMenu - > menuAction ( ) )
2017-05-02 23:21:15 +03:00
filename = QFileDialog : : getOpenFileName ( this , " Open EasyProfiler File " , m_lastFiles . empty ( ) ? QString ( ) : m_lastFiles . front ( ) , " EasyProfiler File (*.prof);;All Files (*.*) " ) ;
2017-02-08 00:14:49 +03:00
else
2017-05-02 23:21:15 +03:00
filename = action - > text ( ) ;
if ( ! filename . isEmpty ( ) )
2017-02-08 00:14:49 +03:00
{
2017-05-02 23:21:15 +03:00
if ( m_bNetworkFileRegime )
{
// Warn user about unsaved network information and suggest to save
2018-06-09 02:18:39 +03:00
auto result = Dialog : : question ( this , " Unsaved session "
, " You have unsaved data! \n Save before opening new file? "
, QMessageBox : : Yes | QMessageBox : : No | QMessageBox : : Cancel ) ;
2017-05-02 23:21:15 +03:00
if ( result = = QMessageBox : : Yes )
{
onSaveFileClicked ( true ) ;
}
else if ( result ! = QMessageBox : : No )
{
// User cancelled opening new file
return ;
}
}
loadFile ( filename ) ;
2017-02-08 00:14:49 +03:00
}
}
//////////////////////////////////////////////////////////////////////////
2018-06-09 02:18:39 +03:00
void MainWindow : : addFileToList ( const QString & filename , bool changeWindowTitle )
2017-02-08 00:14:49 +03:00
{
2018-06-09 02:18:39 +03:00
auto index = m_lastFiles . indexOf ( filename , 0 ) ;
if ( index > = 0 )
{
if ( index ! = 0 )
{
// This file has been already loaded. Move it to the front.
m_lastFiles . move ( index , 0 ) ;
auto fileActions = m_loadActionMenu - > actions ( ) ;
auto action = fileActions . at ( index ) ;
m_loadActionMenu - > removeAction ( action ) ;
m_loadActionMenu - > insertAction ( fileActions . front ( ) , action ) ;
validateLastDir ( ) ;
}
m_bOpenedCacheFile = filename . contains ( NETWORK_CACHE_FILE ) ;
if ( changeWindowTitle )
{
if ( m_bOpenedCacheFile )
setWindowTitle ( QString ( EASY_DEFAULT_WINDOW_TITLE " - [%1] - UNSAVED network cache file " ) . arg ( filename ) ) ;
else
setWindowTitle ( QString ( EASY_DEFAULT_WINDOW_TITLE " - [%1] " ) . arg ( filename ) ) ;
}
return ;
}
2017-02-08 00:14:49 +03:00
m_lastFiles . push_front ( filename ) ;
2018-02-20 22:11:43 +03:00
validateLastDir ( ) ;
2017-02-08 00:14:49 +03:00
auto action = new QAction ( filename , this ) ;
connect ( action , & QAction : : triggered , this , & This : : onOpenFileClicked ) ;
auto fileActions = m_loadActionMenu - > actions ( ) ;
if ( fileActions . empty ( ) )
m_loadActionMenu - > addAction ( action ) ;
else
m_loadActionMenu - > insertAction ( fileActions . front ( ) , action ) ;
if ( m_lastFiles . size ( ) > 10 )
{
// Keep 10 files at the list
m_lastFiles . pop_back ( ) ;
m_loadActionMenu - > removeAction ( fileActions . back ( ) ) ;
delete fileActions . back ( ) ;
}
2017-05-02 23:21:15 +03:00
m_bOpenedCacheFile = filename . contains ( NETWORK_CACHE_FILE ) ;
2018-06-09 02:18:39 +03:00
if ( changeWindowTitle )
{
if ( m_bOpenedCacheFile )
setWindowTitle ( QString ( EASY_DEFAULT_WINDOW_TITLE " - [%1] - UNSAVED network cache file " ) . arg ( m_lastFiles . front ( ) ) ) ;
else
setWindowTitle ( QString ( EASY_DEFAULT_WINDOW_TITLE " - [%1] " ) . arg ( m_lastFiles . front ( ) ) ) ;
}
2017-02-08 00:14:49 +03:00
}
2018-01-28 20:52:17 +03:00
void MainWindow : : loadFile ( const QString & filename )
2017-02-08 00:14:49 +03:00
{
const auto i = filename . lastIndexOf ( QChar ( ' / ' ) ) ;
const auto j = filename . lastIndexOf ( QChar ( ' \\ ' ) ) ;
2018-01-28 20:52:17 +03:00
createProgressDialog ( QString ( " Loading %1... " ) . arg ( filename . mid ( std : : max ( i , j ) + 1 ) ) ) ;
2017-11-27 22:02:15 +03:00
2018-04-22 03:34:26 +03:00
m_readerTimer . start ( ) ;
2017-02-08 00:14:49 +03:00
m_reader . load ( filename ) ;
}
2018-01-28 20:52:17 +03:00
void MainWindow : : readStream ( std : : stringstream & _data )
2017-02-08 00:14:49 +03:00
{
2017-11-27 22:02:15 +03:00
createProgressDialog ( tr ( " Reading from stream... " ) ) ;
2018-04-22 03:34:26 +03:00
m_readerTimer . start ( ) ;
2018-01-04 15:15:02 +01:00
m_reader . load ( _data ) ;
2017-02-08 00:14:49 +03:00
}
//////////////////////////////////////////////////////////////////////////
2018-01-28 20:52:17 +03:00
void MainWindow : : onSaveFileClicked ( bool )
2017-02-08 00:14:49 +03:00
{
if ( m_serializedBlocks . empty ( ) )
return ;
QString lastFile = m_lastFiles . empty ( ) ? QString ( ) : m_lastFiles . front ( ) ;
const auto i = lastFile . lastIndexOf ( QChar ( ' / ' ) ) ;
const auto j = lastFile . lastIndexOf ( QChar ( ' \\ ' ) ) ;
2018-01-28 20:52:17 +03:00
auto k = std : : max ( i , j ) ;
2017-02-08 00:14:49 +03:00
QString dir ;
if ( k > 0 )
dir = lastFile . mid ( 0 , + + k ) ;
2017-05-02 23:21:15 +03:00
if ( m_bNetworkFileRegime )
{
// Current file is network cache file, use current system time as output file name
if ( ! dir . isEmpty ( ) )
dir + = QDateTime : : currentDateTime ( ) . toString ( " /yyyy-MM-dd_HH-mm-ss.prof " ) ;
else
dir = QDateTime : : currentDateTime ( ) . toString ( " yyyy-MM-dd_HH-mm-ss.prof " ) ;
}
else if ( m_bOpenedCacheFile )
{
// Opened old network cache file, use it's last modification time as output file name
QFileInfo fileInfo ( lastFile ) ;
if ( ! fileInfo . exists ( ) )
{
// Can not open the file!
2018-06-09 02:18:39 +03:00
Dialog : : warning ( this , " Warning "
, " Cannot open source file. \n Saving incomplete. " , QMessageBox : : Close ) ;
2017-05-02 23:21:15 +03:00
m_lastFiles . pop_front ( ) ;
auto action = m_loadActionMenu - > actions ( ) . front ( ) ;
m_loadActionMenu - > removeAction ( action ) ;
delete action ;
2018-02-20 22:11:43 +03:00
validateLastDir ( ) ;
2017-05-02 23:21:15 +03:00
return ;
}
if ( ! dir . isEmpty ( ) )
dir + = fileInfo . lastModified ( ) . toString ( " /yyyy-MM-dd_HH-mm-ss.prof " ) ;
else
dir = fileInfo . lastModified ( ) . toString ( " yyyy-MM-dd_HH-mm-ss.prof " ) ;
}
else
{
dir = lastFile ;
}
auto filename = QFileDialog : : getSaveFileName ( this , " Save EasyProfiler File " , dir , " EasyProfiler File (*.prof);;All Files (*.*) " ) ;
2018-06-09 02:18:39 +03:00
if ( filename . isEmpty ( ) )
return ;
if ( EASY_GLOBALS . has_local_changes )
2017-02-08 00:14:49 +03:00
{
2018-06-09 02:18:39 +03:00
createProgressDialog ( tr ( " Saving file... " ) ) ;
m_readerTimer . start ( ) ;
m_reader . save ( filename , m_beginEndTime . beginTime , m_beginEndTime . endTime , m_serializedDescriptors ,
EASY_GLOBALS . descriptors , m_descriptorsNumberInFile , EASY_GLOBALS . profiler_blocks ,
EASY_GLOBALS . bookmarks , easyBlocksTree , EASY_GLOBALS . pid , false ) ;
return ;
}
// Check if the same file has been selected
{
QFileInfo fileInfo1 ( m_bNetworkFileRegime ? QString ( NETWORK_CACHE_FILE ) : lastFile ) , fileInfo2 ( filename ) ;
if ( fileInfo1 . exists ( ) & & fileInfo2 . exists ( ) & & fileInfo1 = = fileInfo2 )
2017-05-02 23:21:15 +03:00
{
2018-06-09 02:18:39 +03:00
// Selected the same file - do nothing
return ;
2017-05-02 23:21:15 +03:00
}
2018-06-09 02:18:39 +03:00
}
2017-05-02 23:21:15 +03:00
2018-06-09 02:18:39 +03:00
bool inOk = false , outOk = false ;
int8_t retry1 = - 1 ;
while ( + + retry1 < 4 )
{
std : : ifstream inFile ( m_bNetworkFileRegime ? NETWORK_CACHE_FILE : lastFile . toStdString ( ) . c_str ( ) , std : : fstream : : binary ) ;
if ( ! inFile . is_open ( ) )
2017-02-08 00:14:49 +03:00
{
2018-06-09 02:18:39 +03:00
std : : this_thread : : sleep_for ( std : : chrono : : milliseconds ( 500 ) ) ;
continue ;
}
2017-02-08 00:14:49 +03:00
2018-06-09 02:18:39 +03:00
inOk = true ;
2017-02-08 00:14:49 +03:00
2018-06-09 02:18:39 +03:00
int8_t retry2 = - 1 ;
while ( + + retry2 < 4 )
{
std : : ofstream outFile ( filename . toStdString ( ) , std : : fstream : : binary ) ;
if ( ! outFile . is_open ( ) )
2017-02-08 00:14:49 +03:00
{
2018-06-09 02:18:39 +03:00
std : : this_thread : : sleep_for ( std : : chrono : : milliseconds ( 500 ) ) ;
continue ;
2017-02-08 00:14:49 +03:00
}
2018-06-09 02:18:39 +03:00
outFile < < inFile . rdbuf ( ) ;
outOk = true ;
2017-02-08 00:14:49 +03:00
break ;
}
2018-06-09 02:18:39 +03:00
break ;
}
if ( outOk )
{
if ( m_bNetworkFileRegime )
2017-02-08 00:14:49 +03:00
{
2018-06-09 02:18:39 +03:00
// Remove temporary network cahche file
QFile : : remove ( QString ( NETWORK_CACHE_FILE ) ) ;
}
else if ( m_bOpenedCacheFile )
{
// Remove old temporary network cahche file
2017-05-02 23:21:15 +03:00
2018-06-09 02:18:39 +03:00
QFile : : remove ( lastFile . toStdString ( ) . c_str ( ) ) ;
2017-05-02 23:21:15 +03:00
2018-06-09 02:18:39 +03:00
m_lastFiles . pop_front ( ) ;
auto action = m_loadActionMenu - > actions ( ) . front ( ) ;
m_loadActionMenu - > removeAction ( action ) ;
delete action ;
validateLastDir ( ) ;
}
2017-05-02 23:21:15 +03:00
2018-06-09 02:18:39 +03:00
addFileToList ( filename ) ;
2017-05-02 23:21:15 +03:00
2018-06-09 02:18:39 +03:00
m_bNetworkFileRegime = false ;
}
else if ( inOk )
{
Dialog : : warning ( this , " Warning "
, " Cannot open destination file. \n Saving incomplete. " , QMessageBox : : Close ) ;
}
else
{
if ( m_bNetworkFileRegime )
Dialog : : warning ( this , " Warning "
, " Cannot open network cache file. \n Saving incomplete. " , QMessageBox : : Close ) ;
2017-02-08 00:14:49 +03:00
else
2018-06-09 02:18:39 +03:00
Dialog : : warning ( this , " Warning "
, " Cannot open source file. \n Saving incomplete. " , QMessageBox : : Close ) ;
2017-02-08 00:14:49 +03:00
}
}
//////////////////////////////////////////////////////////////////////////
2018-01-28 20:52:17 +03:00
void MainWindow : : clear ( )
2017-02-08 00:14:49 +03:00
{
2018-03-13 01:28:58 +03:00
emit EASY_GLOBALS . events . allDataGoingToBeDeleted ( ) ;
2017-02-08 00:14:49 +03:00
EASY_GLOBALS . selected_thread = 0 ;
2018-04-22 03:34:26 +03:00
profiler_gui : : set_max ( EASY_GLOBALS . selected_block ) ;
profiler_gui : : set_max ( EASY_GLOBALS . selected_block_id ) ;
2017-02-08 00:14:49 +03:00
EASY_GLOBALS . profiler_blocks . clear ( ) ;
EASY_GLOBALS . descriptors . clear ( ) ;
EASY_GLOBALS . gui_blocks . clear ( ) ;
m_serializedBlocks . clear ( ) ;
m_serializedDescriptors . clear ( ) ;
m_saveAction - > setEnabled ( false ) ;
m_deleteAction - > setEnabled ( false ) ;
2017-04-05 22:37:40 +03:00
if ( m_bNetworkFileRegime )
QFile : : remove ( QString ( NETWORK_CACHE_FILE ) ) ;
2017-02-08 00:14:49 +03:00
m_bNetworkFileRegime = false ;
2017-05-02 23:21:15 +03:00
m_bOpenedCacheFile = false ;
setWindowTitle ( EASY_DEFAULT_WINDOW_TITLE ) ;
2017-02-08 00:14:49 +03:00
}
//////////////////////////////////////////////////////////////////////////
2018-01-28 20:52:17 +03:00
void MainWindow : : refreshDiagram ( )
2017-02-08 00:14:49 +03:00
{
2018-01-28 20:52:17 +03:00
static_cast < DiagramWidget * > ( m_graphicsView - > widget ( ) ) - > view ( ) - > scene ( ) - > update ( ) ;
2017-02-08 00:14:49 +03:00
}
//////////////////////////////////////////////////////////////////////////
2018-01-28 20:52:17 +03:00
void MainWindow : : onDeleteClicked ( bool )
2017-02-08 00:14:49 +03:00
{
2017-05-02 23:21:15 +03:00
int button = QMessageBox : : Yes ;
2017-04-05 22:37:40 +03:00
if ( m_bNetworkFileRegime )
2018-06-09 02:18:39 +03:00
button = Dialog : : question ( this , " Clear all profiled data "
, " All profiled data and network cache file \n are going to be deleted! \n Continue? "
, QMessageBox : : Yes | QMessageBox : : No ) ;
2017-04-05 22:37:40 +03:00
2017-02-08 00:14:49 +03:00
if ( button = = QMessageBox : : Yes )
clear ( ) ;
}
//////////////////////////////////////////////////////////////////////////
2018-01-28 20:52:17 +03:00
void MainWindow : : onExitClicked ( bool )
2017-02-08 00:14:49 +03:00
{
close ( ) ;
}
//////////////////////////////////////////////////////////////////////////
2018-01-28 20:52:17 +03:00
void MainWindow : : onEncodingChanged ( bool )
2017-02-08 00:14:49 +03:00
{
2017-11-23 22:01:44 +03:00
auto action = qobject_cast < QAction * > ( sender ( ) ) ;
if ( action = = nullptr )
return ;
const int mib = action - > data ( ) . toInt ( ) ;
auto codec = QTextCodec : : codecForMib ( mib ) ;
if ( codec ! = nullptr )
QTextCodec : : setCodecForLocale ( codec ) ;
2017-02-08 00:14:49 +03:00
}
2018-05-24 02:19:48 +03:00
void MainWindow : : onRulerTextPosChanged ( bool )
2017-02-08 00:14:49 +03:00
{
auto _sender = qobject_cast < QAction * > ( sender ( ) ) ;
2018-05-24 02:19:48 +03:00
EASY_GLOBALS . chrono_text_position = static_cast < profiler_gui : : RulerTextPosition > ( _sender - > data ( ) . toInt ( ) ) ;
2017-02-08 00:14:49 +03:00
refreshDiagram ( ) ;
}
2018-01-28 20:52:17 +03:00
void MainWindow : : onUnitsChanged ( bool )
2017-02-08 00:14:49 +03:00
{
auto _sender = qobject_cast < QAction * > ( sender ( ) ) ;
2018-04-22 03:34:26 +03:00
EASY_GLOBALS . time_units = static_cast < profiler_gui : : TimeUnits > ( _sender - > data ( ) . toInt ( ) ) ;
2017-02-08 00:14:49 +03:00
}
2018-01-28 20:52:17 +03:00
void MainWindow : : onEnableDisableStatistics ( bool _checked )
2017-02-08 00:14:49 +03:00
{
EASY_GLOBALS . enable_statistics = _checked ;
auto action = qobject_cast < QAction * > ( sender ( ) ) ;
if ( action ! = nullptr )
{
auto f = action - > font ( ) ;
f . setBold ( _checked ) ;
action - > setFont ( f ) ;
if ( _checked )
{
action - > setText ( " Statistics enabled " ) ;
2017-11-26 15:37:39 +03:00
action - > setIcon ( QIcon ( imagePath ( " stats " ) ) ) ;
2017-02-08 00:14:49 +03:00
}
else
{
action - > setText ( " Statistics disabled " ) ;
2017-11-26 15:37:39 +03:00
action - > setIcon ( QIcon ( imagePath ( " stats-off " ) ) ) ;
2017-02-08 00:14:49 +03:00
}
}
}
2018-01-28 20:52:17 +03:00
void MainWindow : : onCollapseItemsAfterCloseChanged ( bool _checked )
2017-02-08 00:14:49 +03:00
{
EASY_GLOBALS . collapse_items_on_tree_close = _checked ;
}
2018-01-28 20:52:17 +03:00
void MainWindow : : onAllItemsExpandedByDefaultChange ( bool _checked )
2017-02-08 00:14:49 +03:00
{
EASY_GLOBALS . all_items_expanded_by_default = _checked ;
}
2018-01-28 20:52:17 +03:00
void MainWindow : : onBindExpandStatusChange ( bool _checked )
2017-02-08 00:14:49 +03:00
{
EASY_GLOBALS . bind_scene_and_tree_expand_status = _checked ;
}
2019-10-20 16:12:37 +03:00
void MainWindow : : onDisplayRelevantStatsChange ( bool _checked )
{
EASY_GLOBALS . display_only_relevant_stats = _checked ;
}
2018-01-28 20:52:17 +03:00
void MainWindow : : onHierarchyFlagChange ( bool _checked )
2017-02-08 00:14:49 +03:00
{
EASY_GLOBALS . only_current_thread_hierarchy = _checked ;
emit EASY_GLOBALS . events . hierarchyFlagChanged ( _checked ) ;
}
//////////////////////////////////////////////////////////////////////////
2018-01-28 20:52:17 +03:00
void MainWindow : : onExpandAllClicked ( bool )
2017-02-08 00:14:49 +03:00
{
for ( auto & block : EASY_GLOBALS . gui_blocks )
block . expanded = true ;
emit EASY_GLOBALS . events . itemsExpandStateChanged ( ) ;
2018-01-28 20:52:17 +03:00
auto tree = static_cast < HierarchyWidget * > ( m_treeWidget - > widget ( ) ) - > tree ( ) ;
2017-02-08 00:14:49 +03:00
const QSignalBlocker b ( tree ) ;
tree - > expandAll ( ) ;
}
2018-01-28 20:52:17 +03:00
void MainWindow : : onCollapseAllClicked ( bool )
2017-02-08 00:14:49 +03:00
{
for ( auto & block : EASY_GLOBALS . gui_blocks )
block . expanded = false ;
emit EASY_GLOBALS . events . itemsExpandStateChanged ( ) ;
2018-01-28 20:52:17 +03:00
auto tree = static_cast < HierarchyWidget * > ( m_treeWidget - > widget ( ) ) - > tree ( ) ;
2017-02-08 00:14:49 +03:00
const QSignalBlocker b ( tree ) ;
tree - > collapseAll ( ) ;
}
2018-03-15 21:01:19 +03:00
void MainWindow : : onViewportInfoClicked ( bool )
{
const auto & size = EASY_GLOBALS . size ;
2018-04-02 01:50:53 +03:00
auto contents = QString ( " Device pixel ratio = %1 \n Font height = %2px \n Font line spacing = %3px \n Diagram row = %4px \n Diagram spacing = %5px \n Icon size = %6x%6 px " )
2018-03-26 21:38:41 +03:00
. arg ( size . pixelRatio ) . arg ( size . font_height ) . arg ( size . font_line_spacing )
. arg ( size . graphics_row_height ) . arg ( size . threads_row_spacing ) . arg ( size . icon_size ) ;
2018-03-15 21:01:19 +03:00
2018-06-09 02:18:39 +03:00
Dialog : : information ( this , " Viewport info " , contents ) ;
2018-03-15 21:01:19 +03:00
}
2017-02-08 00:14:49 +03:00
//////////////////////////////////////////////////////////////////////////
2018-01-28 20:52:17 +03:00
void MainWindow : : onSpacingChange ( int _value )
2017-02-08 00:14:49 +03:00
{
EASY_GLOBALS . blocks_spacing = _value ;
refreshDiagram ( ) ;
}
2018-01-28 20:52:17 +03:00
void MainWindow : : onMinSizeChange ( int _value )
2017-02-08 00:14:49 +03:00
{
EASY_GLOBALS . blocks_size_min = _value ;
refreshDiagram ( ) ;
}
2018-01-28 20:52:17 +03:00
void MainWindow : : onNarrowSizeChange ( int _value )
2017-02-08 00:14:49 +03:00
{
EASY_GLOBALS . blocks_narrow_size = _value ;
refreshDiagram ( ) ;
}
//////////////////////////////////////////////////////////////////////////
2018-01-28 20:52:17 +03:00
void MainWindow : : onFpsIntervalChange ( int _value )
2017-04-03 23:16:36 +03:00
{
EASY_GLOBALS . fps_timer_interval = _value ;
if ( m_fpsRequestTimer . isActive ( ) )
m_fpsRequestTimer . stop ( ) ;
if ( EASY_GLOBALS . connected )
m_fpsRequestTimer . start ( _value ) ;
}
2018-01-28 20:52:17 +03:00
void MainWindow : : onFpsHistoryChange ( int _value )
2017-04-03 23:16:36 +03:00
{
EASY_GLOBALS . max_fps_history = _value ;
}
2018-01-28 20:52:17 +03:00
void MainWindow : : onFpsMonitorLineWidthChange ( int _value )
2017-04-05 22:37:40 +03:00
{
EASY_GLOBALS . fps_widget_line_width = _value ;
}
2017-04-03 23:16:36 +03:00
//////////////////////////////////////////////////////////////////////////
2018-01-28 20:52:17 +03:00
void MainWindow : : onEditBlocksClicked ( bool )
2017-02-08 00:14:49 +03:00
{
2018-01-25 23:21:56 +03:00
if ( m_descTreeDialog . ptr ! = nullptr )
2017-02-08 00:14:49 +03:00
{
2019-10-20 16:12:37 +03:00
if ( m_descTreeDialog . ptr - > isMinimized ( ) )
{
m_descTreeDialog . ptr - > setWindowState ( ( m_descTreeDialog . ptr - > windowState ( ) & ~ Qt : : WindowMinimized ) | Qt : : WindowActive ) ;
}
2018-01-25 23:21:56 +03:00
m_descTreeDialog . ptr - > raise ( ) ;
2018-06-09 02:18:39 +03:00
m_descTreeDialog . ptr - > setFocus ( ) ;
2019-10-20 16:12:37 +03:00
2017-02-08 00:14:49 +03:00
return ;
}
2018-06-09 02:18:39 +03:00
m_dialogDescTree = new BlockDescriptorsWidget ( ) ;
m_descTreeDialog . create ( m_dialogDescTree ) ;
2018-01-25 23:21:56 +03:00
connect ( m_descTreeDialog . ptr , & QDialog : : finished , this , & This : : onDescTreeDialogClose ) ;
2017-02-08 00:14:49 +03:00
m_dialogDescTree - > build ( ) ;
2018-01-25 23:21:56 +03:00
m_descTreeDialog . restoreGeometry ( ) ;
m_descTreeDialog . ptr - > show ( ) ;
2018-06-09 02:18:39 +03:00
m_descTreeDialog . ptr - > setFocus ( ) ;
2017-02-08 00:14:49 +03:00
}
2018-01-28 20:52:17 +03:00
void MainWindow : : onDescTreeDialogClose ( int )
2017-02-08 00:14:49 +03:00
{
2018-01-25 23:21:56 +03:00
disconnect ( m_descTreeDialog . ptr , & QDialog : : finished , this , & This : : onDescTreeDialogClose ) ;
m_descTreeDialog . saveGeometry ( ) ;
2017-02-08 00:14:49 +03:00
m_dialogDescTree = nullptr ;
2018-01-25 23:21:56 +03:00
m_descTreeDialog . ptr = nullptr ;
2017-02-08 00:14:49 +03:00
}
//////////////////////////////////////////////////////////////////////////
2018-05-19 23:40:01 +03:00
void MainWindow : : validateLineEdits ( )
{
m_addressEdit - > setFixedWidth ( ( m_addressEdit - > fontMetrics ( ) . width ( QString ( " 255.255.255.255 " ) ) * 3 ) / 2 ) ;
m_portEdit - > setFixedWidth ( m_portEdit - > fontMetrics ( ) . width ( QString ( " 000000 " ) ) + 10 ) ;
m_frameTimeEdit - > setFixedWidth ( m_frameTimeEdit - > fontMetrics ( ) . width ( QString ( " 000000 " ) ) ) ;
}
//////////////////////////////////////////////////////////////////////////
void MainWindow : : showEvent ( QShowEvent * show_event )
{
Parent : : showEvent ( show_event ) ;
validateLineEdits ( ) ;
configureSizes ( ) ;
}
2018-01-28 20:52:17 +03:00
void MainWindow : : closeEvent ( QCloseEvent * close_event )
2017-02-08 00:14:49 +03:00
{
2018-06-14 02:57:12 +03:00
if ( ! m_bCloseAfterSave & & ( m_bNetworkFileRegime | | EASY_GLOBALS . has_local_changes ) )
2017-05-02 23:21:15 +03:00
{
// Warn user about unsaved network information and suggest to save
2018-06-09 02:18:39 +03:00
const auto result = Dialog : : question ( this , " Unsaved session "
, " You have unsaved data! \n Save before exit? " , QMessageBox : : Yes | QMessageBox : : No | QMessageBox : : Cancel ) ;
if ( result = = QMessageBox : : Yes )
2017-05-02 23:21:15 +03:00
{
onSaveFileClicked ( true ) ;
2018-06-14 02:57:12 +03:00
if ( m_reader . isSaving ( ) & & m_progress ! = nullptr )
{
// Wait until finish and close
m_bCloseAfterSave = true ;
close_event - > ignore ( ) ;
return ;
}
2017-05-02 23:21:15 +03:00
}
2018-06-09 02:18:39 +03:00
else if ( result = = QMessageBox : : Cancel )
{
close_event - > ignore ( ) ;
return ;
}
2017-05-02 23:21:15 +03:00
}
2018-03-14 00:31:07 +03:00
emit EASY_GLOBALS . events . closeEvent ( ) ;
2018-01-25 23:21:56 +03:00
if ( m_descTreeDialog . ptr ! = nullptr )
2017-02-08 00:14:49 +03:00
{
2018-01-25 23:21:56 +03:00
m_descTreeDialog . ptr - > reject ( ) ;
m_descTreeDialog . ptr = nullptr ;
2017-02-08 00:14:49 +03:00
m_dialogDescTree = nullptr ;
}
2018-01-25 23:21:56 +03:00
saveSettingsAndGeometry ( ) ;
2017-02-08 00:14:49 +03:00
Parent : : closeEvent ( close_event ) ;
}
2019-03-23 21:36:44 +03:00
void MainWindow : : changeEvent ( QEvent * event )
{
if ( event - > type ( ) = = QEvent : : ActivationChange )
{
emit activationChanged ( ) ;
}
}
2017-02-08 00:14:49 +03:00
//////////////////////////////////////////////////////////////////////////
2018-01-28 20:52:17 +03:00
void MainWindow : : loadSettings ( )
2017-02-08 00:14:49 +03:00
{
2018-04-22 03:34:26 +03:00
QSettings settings ( profiler_gui : : ORGANAZATION_NAME , profiler_gui : : APPLICATION_NAME ) ;
2017-02-08 00:14:49 +03:00
settings . beginGroup ( " main " ) ;
auto last_files = settings . value ( " last_files " ) ;
if ( ! last_files . isNull ( ) )
2018-02-20 22:11:43 +03:00
{
2017-02-08 00:14:49 +03:00
m_lastFiles = last_files . toStringList ( ) ;
2018-02-20 22:11:43 +03:00
validateLastDir ( ) ;
}
2017-02-08 00:14:49 +03:00
auto last_addr = settings . value ( " ip_address " ) ;
if ( ! last_addr . isNull ( ) )
m_lastAddress = last_addr . toString ( ) ;
auto last_port = settings . value ( " port " ) ;
if ( ! last_port . isNull ( ) )
m_lastPort = ( uint16_t ) last_port . toUInt ( ) ;
auto val = settings . value ( " chrono_text_position " ) ;
if ( ! val . isNull ( ) )
2018-05-24 02:19:48 +03:00
EASY_GLOBALS . chrono_text_position = static_cast < profiler_gui : : RulerTextPosition > ( val . toInt ( ) ) ;
2017-02-08 00:14:49 +03:00
val = settings . value ( " time_units " ) ;
if ( ! val . isNull ( ) )
2018-04-22 03:34:26 +03:00
EASY_GLOBALS . time_units = static_cast < profiler_gui : : TimeUnits > ( val . toInt ( ) ) ;
2017-02-08 00:14:49 +03:00
val = settings . value ( " frame_time " ) ;
if ( ! val . isNull ( ) )
EASY_GLOBALS . frame_time = val . toFloat ( ) ;
val = settings . value ( " blocks_spacing " ) ;
if ( ! val . isNull ( ) )
EASY_GLOBALS . blocks_spacing = val . toInt ( ) ;
val = settings . value ( " blocks_size_min " ) ;
if ( ! val . isNull ( ) )
EASY_GLOBALS . blocks_size_min = val . toInt ( ) ;
val = settings . value ( " blocks_narrow_size " ) ;
if ( ! val . isNull ( ) )
EASY_GLOBALS . blocks_narrow_size = val . toInt ( ) ;
auto flag = settings . value ( " draw_graphics_items_borders " ) ;
if ( ! flag . isNull ( ) )
EASY_GLOBALS . draw_graphics_items_borders = flag . toBool ( ) ;
flag = settings . value ( " hide_narrow_children " ) ;
if ( ! flag . isNull ( ) )
EASY_GLOBALS . hide_narrow_children = flag . toBool ( ) ;
flag = settings . value ( " hide_minsize_blocks " ) ;
if ( ! flag . isNull ( ) )
EASY_GLOBALS . hide_minsize_blocks = flag . toBool ( ) ;
flag = settings . value ( " collapse_items_on_tree_close " ) ;
if ( ! flag . isNull ( ) )
EASY_GLOBALS . collapse_items_on_tree_close = flag . toBool ( ) ;
flag = settings . value ( " all_items_expanded_by_default " ) ;
if ( ! flag . isNull ( ) )
EASY_GLOBALS . all_items_expanded_by_default = flag . toBool ( ) ;
flag = settings . value ( " only_current_thread_hierarchy " ) ;
if ( ! flag . isNull ( ) )
EASY_GLOBALS . only_current_thread_hierarchy = flag . toBool ( ) ;
flag = settings . value ( " enable_zero_length " ) ;
if ( ! flag . isNull ( ) )
EASY_GLOBALS . enable_zero_length = flag . toBool ( ) ;
flag = settings . value ( " add_zero_blocks_to_hierarchy " ) ;
if ( ! flag . isNull ( ) )
EASY_GLOBALS . add_zero_blocks_to_hierarchy = flag . toBool ( ) ;
flag = settings . value ( " highlight_blocks_with_same_id " ) ;
if ( ! flag . isNull ( ) )
EASY_GLOBALS . highlight_blocks_with_same_id = flag . toBool ( ) ;
flag = settings . value ( " bind_scene_and_tree_expand_status " ) ;
if ( ! flag . isNull ( ) )
EASY_GLOBALS . bind_scene_and_tree_expand_status = flag . toBool ( ) ;
2019-10-20 16:12:37 +03:00
flag = settings . value ( " display_only_relevant_stats " ) ;
if ( ! flag . isNull ( ) )
EASY_GLOBALS . display_only_relevant_stats = flag . toBool ( ) ;
2017-02-08 00:14:49 +03:00
flag = settings . value ( " selecting_block_changes_thread " ) ;
if ( ! flag . isNull ( ) )
EASY_GLOBALS . selecting_block_changes_thread = flag . toBool ( ) ;
flag = settings . value ( " enable_event_indicators " ) ;
if ( ! flag . isNull ( ) )
2017-03-13 20:30:57 +03:00
EASY_GLOBALS . enable_event_markers = flag . toBool ( ) ;
flag = settings . value ( " auto_adjust_histogram_height " ) ;
if ( ! flag . isNull ( ) )
EASY_GLOBALS . auto_adjust_histogram_height = flag . toBool ( ) ;
2017-02-08 00:14:49 +03:00
2018-01-21 19:37:44 +03:00
flag = settings . value ( " auto_adjust_chart_height " ) ;
if ( ! flag . isNull ( ) )
EASY_GLOBALS . auto_adjust_chart_height = flag . toBool ( ) ;
2017-06-07 02:08:53 +03:00
flag = settings . value ( " display_only_frames_on_histogram " ) ;
if ( ! flag . isNull ( ) )
EASY_GLOBALS . display_only_frames_on_histogram = flag . toBool ( ) ;
2017-02-08 00:14:49 +03:00
flag = settings . value ( " use_decorated_thread_name " ) ;
if ( ! flag . isNull ( ) )
EASY_GLOBALS . use_decorated_thread_name = flag . toBool ( ) ;
2017-06-05 21:26:10 +03:00
flag = settings . value ( " hex_thread_id " ) ;
if ( ! flag . isNull ( ) )
EASY_GLOBALS . hex_thread_id = flag . toBool ( ) ;
2017-04-03 23:16:36 +03:00
flag = settings . value ( " fps_timer_interval " ) ;
if ( ! flag . isNull ( ) )
EASY_GLOBALS . fps_timer_interval = flag . toInt ( ) ;
flag = settings . value ( " max_fps_history " ) ;
if ( ! flag . isNull ( ) )
EASY_GLOBALS . max_fps_history = flag . toInt ( ) ;
2017-04-05 22:37:40 +03:00
flag = settings . value ( " fps_widget_line_width " ) ;
if ( ! flag . isNull ( ) )
EASY_GLOBALS . fps_widget_line_width = flag . toInt ( ) ;
2017-02-08 00:14:49 +03:00
flag = settings . value ( " enable_statistics " ) ;
if ( ! flag . isNull ( ) )
EASY_GLOBALS . enable_statistics = flag . toBool ( ) ;
QString encoding = settings . value ( " encoding " , " UTF-8 " ) . toString ( ) ;
auto default_codec_mib = QTextCodec : : codecForName ( encoding . toStdString ( ) . c_str ( ) ) - > mibEnum ( ) ;
auto default_codec = QTextCodec : : codecForMib ( default_codec_mib ) ;
QTextCodec : : setCodecForLocale ( default_codec ) ;
2017-11-26 15:37:39 +03:00
auto theme = settings . value ( " theme " ) ;
if ( theme . isValid ( ) )
{
EASY_GLOBALS . theme = m_theme = theme . toString ( ) ;
}
else
{
m_theme = EASY_GLOBALS . theme ;
}
2018-06-09 02:18:39 +03:00
flag = settings . value ( " use_custom_window_header " ) ;
if ( ! flag . isNull ( ) )
EASY_GLOBALS . use_custom_window_header = flag . toBool ( ) ;
flag = settings . value ( " is_right_window_header_controls " ) ;
if ( ! flag . isNull ( ) )
EASY_GLOBALS . is_right_window_header_controls = flag . toBool ( ) ;
2017-02-08 00:14:49 +03:00
settings . endGroup ( ) ;
}
2018-01-28 20:52:17 +03:00
void MainWindow : : loadGeometry ( )
2017-02-08 00:14:49 +03:00
{
2018-04-22 03:34:26 +03:00
QSettings settings ( profiler_gui : : ORGANAZATION_NAME , profiler_gui : : APPLICATION_NAME ) ;
2017-02-08 00:14:49 +03:00
settings . beginGroup ( " main " ) ;
auto geometry = settings . value ( " geometry " ) . toByteArray ( ) ;
if ( ! geometry . isEmpty ( ) )
restoreGeometry ( geometry ) ;
2018-01-21 19:37:44 +03:00
geometry = settings . value ( " fpsGeometry " ) . toByteArray ( ) ;
if ( ! geometry . isEmpty ( ) )
m_fpsViewer - > restoreGeometry ( geometry ) ;
2018-01-25 23:21:56 +03:00
geometry = settings . value ( " descTreeDialogGeometry " ) . toByteArray ( ) ;
if ( ! geometry . isEmpty ( ) )
m_descTreeDialog . geometry . swap ( geometry ) ;
2018-01-21 19:37:44 +03:00
geometry = settings . value ( " diagramGeometry " ) . toByteArray ( ) ;
if ( ! geometry . isEmpty ( ) )
m_graphicsView - > restoreGeometry ( geometry ) ;
2018-01-28 20:52:17 +03:00
static_cast < DiagramWidget * > ( m_graphicsView - > widget ( ) ) - > restore ( settings ) ;
2018-01-21 19:37:44 +03:00
2017-02-08 00:14:49 +03:00
auto state = settings . value ( " windowState " ) . toByteArray ( ) ;
if ( ! state . isEmpty ( ) )
restoreState ( state ) ;
settings . endGroup ( ) ;
}
2018-01-28 20:52:17 +03:00
void MainWindow : : saveSettingsAndGeometry ( )
2017-02-08 00:14:49 +03:00
{
2018-04-22 03:34:26 +03:00
QSettings settings ( profiler_gui : : ORGANAZATION_NAME , profiler_gui : : APPLICATION_NAME ) ;
2017-02-08 00:14:49 +03:00
settings . beginGroup ( " main " ) ;
settings . setValue ( " geometry " , this - > saveGeometry ( ) ) ;
2018-01-21 19:37:44 +03:00
settings . setValue ( " fpsGeometry " , m_fpsViewer - > saveGeometry ( ) ) ;
2018-01-25 23:21:56 +03:00
settings . setValue ( " descTreeDialogGeometry " , m_descTreeDialog . geometry ) ;
2018-01-21 19:37:44 +03:00
settings . setValue ( " diagramGeometry " , m_graphicsView - > saveGeometry ( ) ) ;
2018-01-28 20:52:17 +03:00
static_cast < DiagramWidget * > ( m_graphicsView - > widget ( ) ) - > save ( settings ) ;
2018-01-21 19:37:44 +03:00
2017-02-08 00:14:49 +03:00
settings . setValue ( " windowState " , this - > saveState ( ) ) ;
2018-01-21 19:37:44 +03:00
2017-02-08 00:14:49 +03:00
settings . setValue ( " last_files " , m_lastFiles ) ;
settings . setValue ( " ip_address " , m_lastAddress ) ;
settings . setValue ( " port " , ( quint32 ) m_lastPort ) ;
settings . setValue ( " chrono_text_position " , static_cast < int > ( EASY_GLOBALS . chrono_text_position ) ) ;
settings . setValue ( " time_units " , static_cast < int > ( EASY_GLOBALS . time_units ) ) ;
settings . setValue ( " frame_time " , EASY_GLOBALS . frame_time ) ;
settings . setValue ( " blocks_spacing " , EASY_GLOBALS . blocks_spacing ) ;
settings . setValue ( " blocks_size_min " , EASY_GLOBALS . blocks_size_min ) ;
settings . setValue ( " blocks_narrow_size " , EASY_GLOBALS . blocks_narrow_size ) ;
settings . setValue ( " draw_graphics_items_borders " , EASY_GLOBALS . draw_graphics_items_borders ) ;
settings . setValue ( " hide_narrow_children " , EASY_GLOBALS . hide_narrow_children ) ;
settings . setValue ( " hide_minsize_blocks " , EASY_GLOBALS . hide_minsize_blocks ) ;
settings . setValue ( " collapse_items_on_tree_close " , EASY_GLOBALS . collapse_items_on_tree_close ) ;
settings . setValue ( " all_items_expanded_by_default " , EASY_GLOBALS . all_items_expanded_by_default ) ;
settings . setValue ( " only_current_thread_hierarchy " , EASY_GLOBALS . only_current_thread_hierarchy ) ;
settings . setValue ( " enable_zero_length " , EASY_GLOBALS . enable_zero_length ) ;
settings . setValue ( " add_zero_blocks_to_hierarchy " , EASY_GLOBALS . add_zero_blocks_to_hierarchy ) ;
settings . setValue ( " highlight_blocks_with_same_id " , EASY_GLOBALS . highlight_blocks_with_same_id ) ;
settings . setValue ( " bind_scene_and_tree_expand_status " , EASY_GLOBALS . bind_scene_and_tree_expand_status ) ;
2019-10-20 16:12:37 +03:00
settings . setValue ( " display_only_relevant_stats " , EASY_GLOBALS . display_only_relevant_stats ) ;
2017-02-08 00:14:49 +03:00
settings . setValue ( " selecting_block_changes_thread " , EASY_GLOBALS . selecting_block_changes_thread ) ;
2017-03-13 20:30:57 +03:00
settings . setValue ( " enable_event_indicators " , EASY_GLOBALS . enable_event_markers ) ;
settings . setValue ( " auto_adjust_histogram_height " , EASY_GLOBALS . auto_adjust_histogram_height ) ;
2018-01-21 19:37:44 +03:00
settings . setValue ( " auto_adjust_chart_height " , EASY_GLOBALS . auto_adjust_chart_height ) ;
2017-06-07 02:08:53 +03:00
settings . setValue ( " display_only_frames_on_histogram " , EASY_GLOBALS . display_only_frames_on_histogram ) ;
2017-02-08 00:14:49 +03:00
settings . setValue ( " use_decorated_thread_name " , EASY_GLOBALS . use_decorated_thread_name ) ;
2017-06-05 21:26:10 +03:00
settings . setValue ( " hex_thread_id " , EASY_GLOBALS . hex_thread_id ) ;
2017-02-08 00:14:49 +03:00
settings . setValue ( " enable_statistics " , EASY_GLOBALS . enable_statistics ) ;
2017-04-03 23:16:36 +03:00
settings . setValue ( " fps_timer_interval " , EASY_GLOBALS . fps_timer_interval ) ;
settings . setValue ( " max_fps_history " , EASY_GLOBALS . max_fps_history ) ;
2017-04-05 22:37:40 +03:00
settings . setValue ( " fps_widget_line_width " , EASY_GLOBALS . fps_widget_line_width ) ;
2018-06-09 02:18:39 +03:00
settings . setValue ( " use_custom_window_header " , EASY_GLOBALS . use_custom_window_header ) ;
settings . setValue ( " is_right_window_header_controls " , EASY_GLOBALS . is_right_window_header_controls ) ;
2017-02-08 00:14:49 +03:00
settings . setValue ( " encoding " , QTextCodec : : codecForLocale ( ) - > name ( ) ) ;
2017-11-26 15:37:39 +03:00
settings . setValue ( " theme " , m_theme ) ;
2017-02-08 00:14:49 +03:00
settings . endGroup ( ) ;
}
2018-01-28 20:52:17 +03:00
void MainWindow : : destroyProgressDialog ( )
2017-11-27 22:02:15 +03:00
{
if ( m_progress ! = nullptr )
{
m_progress - > setValue ( 100 ) ;
m_progress - > deleteLater ( ) ;
m_progress = nullptr ;
}
}
2018-01-28 20:52:17 +03:00
void MainWindow : : createProgressDialog ( const QString & text )
2017-11-27 22:02:15 +03:00
{
destroyProgressDialog ( ) ;
m_progress = new QProgressDialog ( text , QStringLiteral ( " Cancel " ) , 0 , 100 , this ) ;
connect ( m_progress , & QProgressDialog : : canceled , this , & This : : onFileReaderCancel ) ;
2018-06-13 21:43:16 +03:00
m_progress - > setFixedWidth ( px ( 300 ) ) ;
2017-11-27 22:02:15 +03:00
m_progress - > setWindowTitle ( EASY_DEFAULT_WINDOW_TITLE ) ;
m_progress - > setModal ( true ) ;
m_progress - > setValue ( 0 ) ;
m_progress - > show ( ) ;
}
2018-01-28 20:52:17 +03:00
void MainWindow : : setDisconnected ( bool _showMessage )
2017-02-08 00:14:49 +03:00
{
2017-04-03 23:16:36 +03:00
if ( m_fpsRequestTimer . isActive ( ) )
m_fpsRequestTimer . stop ( ) ;
2017-02-08 00:14:49 +03:00
if ( _showMessage )
2018-06-09 02:18:39 +03:00
Dialog : : warning ( this , " Warning " , " Connection was lost " , QMessageBox : : Close ) ;
2017-02-08 00:14:49 +03:00
EASY_GLOBALS . connected = false ;
m_captureAction - > setEnabled ( false ) ;
2017-11-26 15:37:39 +03:00
m_connectAction - > setIcon ( QIcon ( imagePath ( " connect " ) ) ) ;
2017-04-17 22:13:22 +03:00
m_connectAction - > setText ( tr ( " Connect " ) ) ;
2017-02-08 00:14:49 +03:00
m_eventTracingEnableAction - > setEnabled ( false ) ;
m_eventTracingPriorityAction - > setEnabled ( false ) ;
2017-06-09 09:15:56 +03:00
m_addressEdit - > setEnabled ( true ) ;
m_portEdit - > setEnabled ( true ) ;
2017-02-08 00:14:49 +03:00
emit EASY_GLOBALS . events . connectionChanged ( false ) ;
}
//////////////////////////////////////////////////////////////////////////
2018-01-28 20:52:17 +03:00
void MainWindow : : onFrameTimeRequestTimeout ( )
2017-04-03 23:16:36 +03:00
{
2018-01-28 20:52:17 +03:00
if ( EASY_GLOBALS . fps_enabled & & EASY_GLOBALS . connected & &
( m_listener . regime ( ) = = ListenerRegime : : Idle | | m_listener . regime ( ) = = ListenerRegime : : Capture ) )
2017-04-03 23:16:36 +03:00
{
if ( m_listener . requestFrameTime ( ) )
{
QTimer : : singleShot ( 100 , this , & This : : checkFrameTimeReady ) ;
}
2017-04-05 22:37:40 +03:00
else if ( ! m_listener . connected ( ) )
{
2017-10-04 22:37:46 +03:00
m_listener . closeSocket ( ) ;
2017-04-05 22:37:40 +03:00
setDisconnected ( ) ;
}
2017-04-03 23:16:36 +03:00
}
}
2018-01-28 20:52:17 +03:00
void MainWindow : : checkFrameTimeReady ( )
2017-04-03 23:16:36 +03:00
{
2018-01-28 20:52:17 +03:00
if ( EASY_GLOBALS . fps_enabled & & EASY_GLOBALS . connected & &
( m_listener . regime ( ) = = ListenerRegime : : Idle | | m_listener . regime ( ) = = ListenerRegime : : Capture ) )
2017-04-03 23:16:36 +03:00
{
uint32_t maxTime = 0 , avgTime = 0 ;
if ( m_listener . frameTime ( maxTime , avgTime ) )
{
2018-05-07 21:58:37 +03:00
static_cast < FpsWidget * > ( m_fpsViewer - > widget ( ) ) - > addPoint ( maxTime , avgTime ) ;
2017-04-03 23:16:36 +03:00
}
else if ( m_fpsRequestTimer . isActive ( ) )
{
QTimer : : singleShot ( 100 , this , & This : : checkFrameTimeReady ) ;
}
}
}
//////////////////////////////////////////////////////////////////////////
2018-01-28 20:52:17 +03:00
void MainWindow : : onListenerTimerTimeout ( )
2017-02-08 00:14:49 +03:00
{
if ( ! m_listener . connected ( ) )
2017-04-03 23:28:19 +03:00
{
2018-01-28 20:52:17 +03:00
if ( m_listener . regime ( ) = = ListenerRegime : : Capture_Receive )
2017-04-03 23:28:19 +03:00
m_listener . finalizeCapture ( ) ;
2017-09-18 13:05:45 +03:00
if ( m_listenerDialog )
m_listenerDialog - > reject ( ) ;
2017-04-03 23:28:19 +03:00
}
2018-01-28 20:52:17 +03:00
else if ( m_listener . regime ( ) = = ListenerRegime : : Capture_Receive )
2017-04-03 23:28:19 +03:00
{
if ( m_listener . captured ( ) )
{
if ( m_listenerTimer . isActive ( ) )
m_listenerTimer . stop ( ) ;
m_listener . finalizeCapture ( ) ;
2017-04-05 22:37:40 +03:00
m_listenerDialog - > accept ( ) ;
m_listenerDialog = nullptr ;
2017-04-03 23:28:19 +03:00
if ( m_listener . size ( ) ! = 0 )
{
readStream ( m_listener . data ( ) ) ;
m_listener . clearData ( ) ;
}
}
}
2017-02-08 00:14:49 +03:00
}
2018-01-28 20:52:17 +03:00
void MainWindow : : onListenerDialogClose ( int _result )
2017-02-08 00:14:49 +03:00
{
2018-01-28 20:52:17 +03:00
if ( m_listener . regime ( ) ! = ListenerRegime : : Capture_Receive | | ! m_listener . connected ( ) )
2017-04-03 23:28:19 +03:00
{
if ( m_listenerTimer . isActive ( ) )
m_listenerTimer . stop ( ) ;
}
2017-02-08 00:14:49 +03:00
disconnect ( m_listenerDialog , & QDialog : : finished , this , & This : : onListenerDialogClose ) ;
m_listenerDialog = nullptr ;
switch ( m_listener . regime ( ) )
{
2018-01-28 20:52:17 +03:00
case ListenerRegime : : Capture :
2017-02-08 00:14:49 +03:00
{
2018-06-09 02:18:39 +03:00
m_listenerDialog = new Dialog ( this , QMessageBox : : Information , " Receiving data... " ,
" This process may take some time. " , QMessageBox : : Cancel ) ;
2017-02-08 00:14:49 +03:00
m_listenerDialog - > setAttribute ( Qt : : WA_DeleteOnClose , true ) ;
m_listenerDialog - > show ( ) ;
m_listener . stopCapture ( ) ;
2018-01-28 20:52:17 +03:00
if ( m_listener . regime ( ) ! = ListenerRegime : : Capture_Receive )
2017-04-03 23:28:19 +03:00
{
m_listenerDialog - > reject ( ) ;
m_listenerDialog = nullptr ;
}
else
{
2017-04-05 22:37:40 +03:00
connect ( m_listenerDialog , & QDialog : : finished , this , & This : : onListenerDialogClose ) ;
2017-04-03 23:28:19 +03:00
m_listenerTimer . start ( 250 ) ;
}
break ;
}
2018-01-28 20:52:17 +03:00
case ListenerRegime : : Capture_Receive :
2017-04-03 23:28:19 +03:00
{
if ( ! m_listener . captured ( ) )
{
2017-04-05 22:37:40 +03:00
if ( _result = = QDialog : : Accepted )
{
2018-06-09 02:18:39 +03:00
m_listenerDialog = new Dialog ( this , QMessageBox : : Information , " Receiving data... " ,
" This process may take some time. " , QMessageBox : : Cancel ) ;
2017-04-05 22:37:40 +03:00
connect ( m_listenerDialog , & QDialog : : finished , this , & This : : onListenerDialogClose ) ;
m_listenerDialog - > setAttribute ( Qt : : WA_DeleteOnClose , true ) ;
m_listenerDialog - > show ( ) ;
}
else
{
m_listener . finalizeCapture ( ) ;
m_listener . clearData ( ) ;
if ( m_listener . connected ( ) )
{
// make reconnect to clear socket buffers
2017-10-04 22:37:46 +03:00
const std : : string address = m_listener . address ( ) ;
const auto port = m_listener . port ( ) ;
2017-04-05 22:37:40 +03:00
profiler : : net : : EasyProfilerStatus reply ( false , false , false ) ;
2017-10-04 22:37:46 +03:00
if ( m_listener . reconnect ( address . c_str ( ) , port , reply ) )
2017-04-05 22:37:40 +03:00
{
disconnect ( m_eventTracingEnableAction , & QAction : : triggered , this , & This : : onEventTracingEnableChange ) ;
disconnect ( m_eventTracingPriorityAction , & QAction : : triggered , this , & This : : onEventTracingPriorityChange ) ;
m_eventTracingEnableAction - > setChecked ( reply . isEventTracingEnabled ) ;
m_eventTracingPriorityAction - > setChecked ( reply . isLowPriorityEventTracing ) ;
connect ( m_eventTracingEnableAction , & QAction : : triggered , this , & This : : onEventTracingEnableChange ) ;
connect ( m_eventTracingPriorityAction , & QAction : : triggered , this , & This : : onEventTracingPriorityChange ) ;
if ( reply . isProfilerEnabled )
{
// Connected application is already profiling.
// Show capture dialog immediately
onCaptureClicked ( true ) ;
}
}
}
}
2017-04-03 23:28:19 +03:00
break ;
}
if ( m_listenerTimer . isActive ( ) )
m_listenerTimer . stop ( ) ;
m_listener . finalizeCapture ( ) ;
2017-02-08 00:14:49 +03:00
if ( m_listener . size ( ) ! = 0 )
{
readStream ( m_listener . data ( ) ) ;
m_listener . clearData ( ) ;
}
break ;
}
2018-01-28 20:52:17 +03:00
case ListenerRegime : : Descriptors :
2017-02-08 00:14:49 +03:00
{
break ;
}
default :
return ;
}
if ( ! m_listener . connected ( ) )
{
2017-10-04 22:37:46 +03:00
m_listener . closeSocket ( ) ;
2017-02-08 00:14:49 +03:00
setDisconnected ( ) ;
}
}
//////////////////////////////////////////////////////////////////////////
2018-04-22 03:34:26 +03:00
void MainWindow : : closeProgressDialogAndClearReader ( )
2017-02-08 00:14:49 +03:00
{
2018-04-22 03:34:26 +03:00
m_reader . interrupt ( ) ;
m_readerTimer . stop ( ) ;
destroyProgressDialog ( ) ;
}
void MainWindow : : onLoadingFinish ( profiler : : block_index_t & _nblocks )
{
_nblocks = m_reader . size ( ) ;
if ( _nblocks ! = 0 )
2017-02-08 00:14:49 +03:00
{
2018-04-22 03:34:26 +03:00
emit EASY_GLOBALS . events . allDataGoingToBeDeleted ( ) ;
2018-06-09 02:18:39 +03:00
EASY_GLOBALS . has_local_changes = false ;
2018-04-22 03:34:26 +03:00
profiler : : SerializedData serialized_blocks ;
profiler : : SerializedData serialized_descriptors ;
profiler : : descriptors_list_t descriptors ;
profiler : : blocks_t blocks ;
profiler : : thread_blocks_tree_t threads_map ;
2018-06-09 02:18:39 +03:00
profiler : : bookmarks_t bookmarks ;
profiler : : BeginEndTime beginEndTime ;
2018-04-22 03:34:26 +03:00
QString filename ;
uint32_t descriptorsNumberInFile = 0 ;
uint32_t version = 0 ;
profiler : : processid_t pid = 0 ;
m_reader . get ( serialized_blocks , serialized_descriptors , descriptors , blocks , threads_map ,
2018-06-09 02:18:39 +03:00
bookmarks , beginEndTime , descriptorsNumberInFile , version , pid , filename ) ;
2018-04-22 03:34:26 +03:00
if ( threads_map . size ( ) > 0xff )
2017-02-08 00:14:49 +03:00
{
2018-06-09 02:18:39 +03:00
QString message ;
2018-04-22 03:34:26 +03:00
if ( m_reader . isFile ( ) )
2018-06-09 02:18:39 +03:00
message = QString ( " File %1 contains %2 threads! " ) . arg ( filename ) . arg ( threads_map . size ( ) ) ;
2018-04-22 03:34:26 +03:00
else
2018-06-09 02:18:39 +03:00
message = QString ( " Input stream contains %1 threads! " ) . arg ( threads_map . size ( ) ) ;
Dialog : : warning ( this , " Warning " ,
QString ( " %1 \n Currently, maximum number of displayed threads is 255! "
" \n Some threads will not be displayed. " ) . arg ( message ) , QMessageBox : : Close ) ;
2018-04-22 03:34:26 +03:00
}
m_bNetworkFileRegime = ! m_reader . isFile ( ) ;
if ( ! m_bNetworkFileRegime )
{
2018-06-09 02:18:39 +03:00
addFileToList ( filename ) ;
2018-04-22 03:34:26 +03:00
}
else
{
m_bOpenedCacheFile = false ;
setWindowTitle ( EASY_DEFAULT_WINDOW_TITLE " - UNSAVED network cache " ) ;
}
2017-05-02 23:21:15 +03:00
2018-04-22 03:34:26 +03:00
m_serializedBlocks = std : : move ( serialized_blocks ) ;
m_serializedDescriptors = std : : move ( serialized_descriptors ) ;
m_descriptorsNumberInFile = descriptorsNumberInFile ;
2018-06-09 02:18:39 +03:00
m_beginEndTime = beginEndTime ;
2018-04-22 03:34:26 +03:00
EASY_GLOBALS . selected_thread = 0 ;
EASY_GLOBALS . version = version ;
EASY_GLOBALS . pid = pid ;
profiler_gui : : set_max ( EASY_GLOBALS . selected_block ) ;
profiler_gui : : set_max ( EASY_GLOBALS . selected_block_id ) ;
EASY_GLOBALS . profiler_blocks . swap ( threads_map ) ;
EASY_GLOBALS . descriptors . swap ( descriptors ) ;
2018-06-09 02:18:39 +03:00
EASY_GLOBALS . bookmarks . swap ( bookmarks ) ;
2018-04-22 03:34:26 +03:00
EASY_GLOBALS . gui_blocks . clear ( ) ;
EASY_GLOBALS . gui_blocks . resize ( _nblocks ) ;
memset ( EASY_GLOBALS . gui_blocks . data ( ) , 0 , sizeof ( profiler_gui : : EasyBlock ) * _nblocks ) ;
for ( std : : remove_reference < decltype ( _nblocks ) > : : type i = 0 ; i < _nblocks ; + + i )
{
auto & guiblock = EASY_GLOBALS . gui_blocks [ i ] ;
guiblock . tree = std : : move ( blocks [ i ] ) ;
2017-02-08 00:14:49 +03:00
}
2018-04-22 03:34:26 +03:00
m_saveAction - > setEnabled ( true ) ;
m_deleteAction - > setEnabled ( true ) ;
}
else
{
2018-06-09 02:18:39 +03:00
Dialog : : warning ( this , " Warning " , QString ( " Cannot read profiled blocks. \n \n Reason: \n %1 " )
2018-04-25 21:37:18 +03:00
. arg ( m_reader . getError ( ) ) , QMessageBox : : Close ) ;
2018-04-22 03:34:26 +03:00
if ( m_reader . isFile ( ) )
{
auto index = m_lastFiles . indexOf ( m_reader . filename ( ) , 0 ) ;
if ( index > = 0 )
2017-02-08 00:14:49 +03:00
{
2018-04-22 03:34:26 +03:00
// Remove unexisting file from list
m_lastFiles . removeAt ( index ) ;
auto action = m_loadActionMenu - > actions ( ) . at ( index ) ;
m_loadActionMenu - > removeAction ( action ) ;
delete action ;
validateLastDir ( ) ;
2017-02-08 00:14:49 +03:00
}
}
2018-04-22 03:34:26 +03:00
}
}
void MainWindow : : onSavingFinish ( )
{
2018-04-25 21:37:18 +03:00
const auto errorMessage = m_reader . getError ( ) ;
if ( ! errorMessage . isEmpty ( ) )
{
2018-06-09 02:18:39 +03:00
Dialog : : warning ( this , " Warning " , QString ( " Cannot save profiled blocks. \n \n Reason: \n %1 " )
2018-04-25 21:37:18 +03:00
. arg ( errorMessage ) , QMessageBox : : Close ) ;
}
2018-06-09 02:18:39 +03:00
else
{
2018-06-13 21:43:16 +03:00
if ( ! m_reader . isSnapshot ( ) )
EASY_GLOBALS . has_local_changes = false ;
2018-06-09 02:18:39 +03:00
addFileToList ( m_reader . filename ( ) , ! m_reader . isSnapshot ( ) ) ;
}
2018-04-22 03:34:26 +03:00
}
void MainWindow : : onFileReaderTimeout ( )
{
if ( m_reader . done ( ) )
{
if ( m_reader . isLoading ( ) )
{
profiler : : block_index_t nblocks = 0 ;
2017-02-08 00:14:49 +03:00
2018-04-22 03:34:26 +03:00
onLoadingFinish ( nblocks ) ;
closeProgressDialogAndClearReader ( ) ;
2017-02-08 00:14:49 +03:00
2018-04-22 03:34:26 +03:00
if ( nblocks ! = 0 )
{
emit EASY_GLOBALS . events . fileOpened ( ) ;
if ( EASY_GLOBALS . all_items_expanded_by_default )
onExpandAllClicked ( true ) ;
}
}
else if ( m_reader . isSaving ( ) )
2017-02-08 00:14:49 +03:00
{
2018-04-22 03:34:26 +03:00
onSavingFinish ( ) ;
closeProgressDialogAndClearReader ( ) ;
2018-06-14 02:57:12 +03:00
if ( m_bCloseAfterSave )
{
setEnabled ( false ) ;
QTimer : : singleShot ( 1500 , this , & This : : close ) ;
}
2018-04-22 03:34:26 +03:00
}
else
{
closeProgressDialogAndClearReader ( ) ;
2017-02-08 00:14:49 +03:00
}
}
2017-11-27 22:02:15 +03:00
else if ( m_progress ! = nullptr )
2017-02-08 00:14:49 +03:00
{
m_progress - > setValue ( m_reader . progress ( ) ) ;
}
}
2018-01-28 20:52:17 +03:00
void MainWindow : : onFileReaderCancel ( )
2017-02-08 00:14:49 +03:00
{
m_readerTimer . stop ( ) ;
m_reader . interrupt ( ) ;
2017-11-27 22:02:15 +03:00
destroyProgressDialog ( ) ;
2017-02-08 00:14:49 +03:00
}
//////////////////////////////////////////////////////////////////////////
2018-01-28 20:52:17 +03:00
FileReader : : FileReader ( )
2017-02-08 00:14:49 +03:00
{
}
2018-01-28 20:52:17 +03:00
FileReader : : ~ FileReader ( )
2017-02-08 00:14:49 +03:00
{
interrupt ( ) ;
}
2018-01-28 20:52:17 +03:00
const bool FileReader : : isFile ( ) const
2017-02-08 00:14:49 +03:00
{
return m_isFile ;
}
2018-04-22 03:34:26 +03:00
const bool FileReader : : isSaving ( ) const
{
return m_jobType = = JobType : : Saving ;
}
const bool FileReader : : isLoading ( ) const
{
return m_jobType = = JobType : : Loading ;
}
2018-06-09 02:18:39 +03:00
const bool FileReader : : isSnapshot ( ) const
{
return m_isSnapshot ;
}
2018-01-28 20:52:17 +03:00
bool FileReader : : done ( ) const
2017-02-08 00:14:49 +03:00
{
2018-01-28 20:52:17 +03:00
return m_bDone . load ( std : : memory_order_acquire ) ;
2017-02-08 00:14:49 +03:00
}
2018-01-28 20:52:17 +03:00
int FileReader : : progress ( ) const
2017-02-08 00:14:49 +03:00
{
2018-01-28 20:52:17 +03:00
return m_progress . load ( std : : memory_order_acquire ) ;
2017-02-08 00:14:49 +03:00
}
2018-01-28 20:52:17 +03:00
unsigned int FileReader : : size ( ) const
2017-02-08 00:14:49 +03:00
{
2018-01-28 20:52:17 +03:00
return m_size . load ( std : : memory_order_acquire ) ;
2017-02-08 00:14:49 +03:00
}
2018-01-28 20:52:17 +03:00
const QString & FileReader : : filename ( ) const
2017-02-08 00:14:49 +03:00
{
return m_filename ;
}
2018-01-28 20:52:17 +03:00
void FileReader : : load ( const QString & _filename )
2017-02-08 00:14:49 +03:00
{
interrupt ( ) ;
2018-04-22 03:34:26 +03:00
m_jobType = JobType : : Loading ;
2017-02-08 00:14:49 +03:00
m_isFile = true ;
2018-06-09 02:18:39 +03:00
m_isSnapshot = false ;
2017-02-08 00:14:49 +03:00
m_filename = _filename ;
2018-04-22 03:34:26 +03:00
m_thread = std : : thread ( [ this ] ( bool _enableStatistics )
{
2018-06-09 02:18:39 +03:00
m_size . store ( fillTreesFromFile ( m_progress , m_filename . toStdString ( ) . c_str ( ) , m_beginEndTime , m_serializedBlocks ,
2018-04-22 03:34:26 +03:00
m_serializedDescriptors , m_descriptors , m_blocks , m_blocksTree ,
2018-06-09 02:18:39 +03:00
m_bookmarks , m_descriptorsNumberInFile , m_version , m_pid ,
_enableStatistics , m_errorMessage ) , std : : memory_order_release ) ;
2018-04-22 03:34:26 +03:00
2018-01-28 20:52:17 +03:00
m_progress . store ( 100 , std : : memory_order_release ) ;
m_bDone . store ( true , std : : memory_order_release ) ;
2018-04-22 03:34:26 +03:00
2017-02-08 00:14:49 +03:00
} , EASY_GLOBALS . enable_statistics ) ;
}
2018-01-28 20:52:17 +03:00
void FileReader : : load ( std : : stringstream & _stream )
2017-02-08 00:14:49 +03:00
{
interrupt ( ) ;
2018-04-22 03:34:26 +03:00
m_jobType = JobType : : Loading ;
2017-02-08 00:14:49 +03:00
m_isFile = false ;
2018-06-09 02:18:39 +03:00
m_isSnapshot = false ;
2017-02-08 00:14:49 +03:00
m_filename . clear ( ) ;
# if defined(__GNUC__) && __GNUC__ < 5 && !defined(__llvm__)
// gcc 4 has a known bug which has been solved in gcc 5:
// std::stringstream has no swap() method :(
// have to copy all contents... Use gcc 5 or higher!
# pragma message "Warning: in gcc 4 and lower std::stringstream has no swap()! Memory consumption may increase! Better use gcc 5 or higher instead."
m_stream . str ( _stream . str ( ) ) ;
# else
m_stream . swap ( _stream ) ;
# endif
2018-04-22 03:34:26 +03:00
m_thread = std : : thread ( [ this ] ( bool _enableStatistics )
{
2018-01-28 20:52:17 +03:00
std : : ofstream cache_file ( NETWORK_CACHE_FILE , std : : fstream : : binary ) ;
2018-04-22 03:34:26 +03:00
if ( cache_file . is_open ( ) )
{
2017-02-08 00:14:49 +03:00
cache_file < < m_stream . str ( ) ;
cache_file . close ( ) ;
}
2018-04-22 03:34:26 +03:00
2018-06-09 02:18:39 +03:00
m_size . store ( fillTreesFromStream ( m_progress , m_stream , m_beginEndTime , m_serializedBlocks , m_serializedDescriptors ,
m_descriptors , m_blocks , m_blocksTree , m_bookmarks , m_descriptorsNumberInFile ,
2018-04-22 03:34:26 +03:00
m_version , m_pid , _enableStatistics , m_errorMessage ) , std : : memory_order_release ) ;
2018-01-28 20:52:17 +03:00
m_progress . store ( 100 , std : : memory_order_release ) ;
m_bDone . store ( true , std : : memory_order_release ) ;
2018-04-22 03:34:26 +03:00
2017-02-08 00:14:49 +03:00
} , EASY_GLOBALS . enable_statistics ) ;
}
2018-04-22 03:34:26 +03:00
void FileReader : : save ( const QString & _filename , profiler : : timestamp_t _beginTime , profiler : : timestamp_t _endTime ,
2018-04-25 21:37:18 +03:00
const profiler : : SerializedData & _serializedDescriptors ,
const profiler : : descriptors_list_t & _descriptors , profiler : : block_id_t descriptors_count ,
2018-06-09 02:18:39 +03:00
const profiler : : thread_blocks_tree_t & _trees , const profiler : : bookmarks_t & bookmarks ,
profiler : : block_getter_fn block_getter , profiler : : processid_t _pid , bool snapshotMode )
2018-04-22 03:34:26 +03:00
{
interrupt ( ) ;
m_jobType = JobType : : Saving ;
m_isFile = true ;
2018-06-09 02:18:39 +03:00
m_isSnapshot = snapshotMode ;
2018-04-22 03:34:26 +03:00
m_filename = _filename ;
auto serializedDescriptors = std : : ref ( _serializedDescriptors ) ;
2018-04-25 21:37:18 +03:00
auto descriptors = std : : ref ( _descriptors ) ;
2018-04-22 03:34:26 +03:00
auto trees = std : : ref ( _trees ) ;
2018-06-09 02:18:39 +03:00
auto bookmarksRef = std : : ref ( bookmarks ) ;
2018-04-22 03:34:26 +03:00
2018-04-25 21:37:18 +03:00
m_thread = std : : thread ( [ = ] ( profiler : : block_getter_fn getter )
{
const QString tmpFile = m_filename + " .tmp " ;
const auto result = writeTreesToFile ( m_progress , tmpFile . toStdString ( ) . c_str ( ) , serializedDescriptors ,
2018-06-09 02:18:39 +03:00
descriptors , descriptors_count , trees , bookmarksRef , getter ,
_beginTime , _endTime , _pid , m_errorMessage ) ;
2018-04-25 21:37:18 +03:00
if ( result = = 0 | | ! m_errorMessage . str ( ) . empty ( ) )
{
// Remove temporary file in case of error
QFile : : remove ( tmpFile ) ;
}
else
{
// Remove old file if exists
{
QFile out ( m_filename ) ;
if ( out . exists ( ) )
out . remove ( ) ;
}
QFile : : rename ( tmpFile , m_filename ) ;
}
2018-04-22 03:34:26 +03:00
m_progress . store ( 100 , std : : memory_order_release ) ;
m_bDone . store ( true , std : : memory_order_release ) ;
2018-04-25 21:37:18 +03:00
2018-04-22 03:34:26 +03:00
} , std : : move ( block_getter ) ) ;
}
2018-01-28 20:52:17 +03:00
void FileReader : : interrupt ( )
2017-02-08 00:14:49 +03:00
{
2018-01-25 23:21:56 +03:00
join ( ) ;
2017-02-08 00:14:49 +03:00
2018-01-28 20:52:17 +03:00
m_bDone . store ( false , std : : memory_order_release ) ;
m_size . store ( 0 , std : : memory_order_release ) ;
2017-02-08 00:14:49 +03:00
m_serializedBlocks . clear ( ) ;
m_serializedDescriptors . clear ( ) ;
m_descriptors . clear ( ) ;
m_blocks . clear ( ) ;
m_blocksTree . clear ( ) ;
2018-06-09 02:18:39 +03:00
m_bookmarks . clear ( ) ;
2017-02-08 00:14:49 +03:00
m_descriptorsNumberInFile = 0 ;
2017-06-06 20:46:06 +03:00
m_version = 0 ;
2018-04-22 03:34:26 +03:00
m_pid = 0 ;
m_jobType = JobType : : Idle ;
2018-06-09 02:18:39 +03:00
m_isSnapshot = false ;
2017-02-08 00:14:49 +03:00
clear_stream ( m_stream ) ;
clear_stream ( m_errorMessage ) ;
}
2018-04-22 03:34:26 +03:00
void FileReader : : get ( profiler : : SerializedData & _serializedBlocks , profiler : : SerializedData & _serializedDescriptors ,
profiler : : descriptors_list_t & _descriptors , profiler : : blocks_t & _blocks ,
2018-06-09 02:18:39 +03:00
profiler : : thread_blocks_tree_t & _trees , profiler : : bookmarks_t & bookmarks ,
profiler : : BeginEndTime & beginEndTime , uint32_t & _descriptorsNumberInFile , uint32_t & _version ,
2018-04-22 03:34:26 +03:00
profiler : : processid_t & _pid , QString & _filename )
2017-02-08 00:14:49 +03:00
{
if ( done ( ) )
{
m_serializedBlocks . swap ( _serializedBlocks ) ;
m_serializedDescriptors . swap ( _serializedDescriptors ) ;
2018-04-22 03:34:26 +03:00
profiler : : descriptors_list_t ( std : : move ( m_descriptors ) ) . swap ( _descriptors ) ;
2017-02-08 00:14:49 +03:00
m_blocks . swap ( _blocks ) ;
2018-04-22 03:34:26 +03:00
m_blocksTree . swap ( _trees ) ;
2018-06-09 02:18:39 +03:00
m_bookmarks . swap ( bookmarks ) ;
2017-02-08 00:14:49 +03:00
m_filename . swap ( _filename ) ;
2018-06-09 02:18:39 +03:00
beginEndTime = m_beginEndTime ;
2017-02-08 00:14:49 +03:00
_descriptorsNumberInFile = m_descriptorsNumberInFile ;
2017-06-06 20:46:06 +03:00
_version = m_version ;
2018-04-22 03:34:26 +03:00
_pid = m_pid ;
2017-02-08 00:14:49 +03:00
}
}
2018-01-28 20:52:17 +03:00
void FileReader : : join ( )
2018-01-25 23:21:56 +03:00
{
2018-01-28 20:52:17 +03:00
m_progress . store ( - 100 , std : : memory_order_release ) ;
2018-01-25 23:21:56 +03:00
if ( m_thread . joinable ( ) )
m_thread . join ( ) ;
2018-01-28 20:52:17 +03:00
m_progress . store ( 0 , std : : memory_order_release ) ;
2018-01-25 23:21:56 +03:00
}
2018-01-28 20:52:17 +03:00
QString FileReader : : getError ( )
2017-02-08 00:14:49 +03:00
{
return QString ( m_errorMessage . str ( ) . c_str ( ) ) ;
}
//////////////////////////////////////////////////////////////////////////
2018-01-28 20:52:17 +03:00
void MainWindow : : onEventTracingPriorityChange ( bool _checked )
2017-02-08 00:14:49 +03:00
{
if ( EASY_GLOBALS . connected )
2017-11-09 23:12:54 +03:00
m_listener . send ( profiler : : net : : BoolMessage ( profiler : : net : : MessageType : : Change_Event_Tracing_Priority , _checked ) ) ;
2017-02-08 00:14:49 +03:00
}
2018-01-28 20:52:17 +03:00
void MainWindow : : onEventTracingEnableChange ( bool _checked )
2017-02-08 00:14:49 +03:00
{
if ( EASY_GLOBALS . connected )
2017-11-09 23:12:54 +03:00
m_listener . send ( profiler : : net : : BoolMessage ( profiler : : net : : MessageType : : Change_Event_Tracing_Status , _checked ) ) ;
2017-02-08 00:14:49 +03:00
}
//////////////////////////////////////////////////////////////////////////
2018-01-28 20:52:17 +03:00
void MainWindow : : onFrameTimeEditFinish ( )
2017-02-08 00:14:49 +03:00
{
auto text = m_frameTimeEdit - > text ( ) ;
if ( text . contains ( QChar ( ' , ' ) ) )
{
text . remove ( QChar ( ' . ' ) ) . replace ( QChar ( ' , ' ) , QChar ( ' . ' ) ) ;
m_frameTimeEdit - > setText ( text ) ;
}
EASY_GLOBALS . frame_time = text . toFloat ( ) * 1e3 f ;
2017-03-07 01:09:27 +03:00
2018-04-22 03:34:26 +03:00
disconnect ( & EASY_GLOBALS . events , & profiler_gui : : GlobalSignals : : expectedFrameTimeChanged ,
2017-11-09 23:12:54 +03:00
this , & This : : onFrameTimeChanged ) ;
2017-03-13 20:30:57 +03:00
emit EASY_GLOBALS . events . expectedFrameTimeChanged ( ) ;
2017-11-09 23:12:54 +03:00
2018-04-22 03:34:26 +03:00
connect ( & EASY_GLOBALS . events , & profiler_gui : : GlobalSignals : : expectedFrameTimeChanged ,
2017-11-09 23:12:54 +03:00
this , & This : : onFrameTimeChanged ) ;
2017-03-07 01:09:27 +03:00
}
2018-01-28 20:52:17 +03:00
void MainWindow : : onFrameTimeChanged ( )
2017-03-07 01:09:27 +03:00
{
m_frameTimeEdit - > setText ( QString : : number ( EASY_GLOBALS . frame_time * 1e-3 ) ) ;
2017-02-08 00:14:49 +03:00
}
//////////////////////////////////////////////////////////////////////////
2018-04-22 16:15:10 +03:00
void MainWindow : : onSnapshotClicked ( bool )
2018-04-22 03:34:26 +03:00
{
profiler : : timestamp_t beginTime = 0 , endTime = 0 ;
const bool hasSelection = static_cast < DiagramWidget * > ( m_graphicsView - > widget ( ) ) - > view ( ) - > getSelectionRegionForSaving ( beginTime , endTime ) ;
if ( ! hasSelection )
return ;
QString lastFile = m_lastFiles . empty ( ) ? QString ( ) : m_lastFiles . front ( ) ;
const auto i = lastFile . lastIndexOf ( QChar ( ' / ' ) ) ;
const auto j = lastFile . lastIndexOf ( QChar ( ' \\ ' ) ) ;
auto k = std : : max ( i , j ) ;
QString dir ;
if ( k > 0 )
dir = lastFile . mid ( 0 , + + k ) ;
auto filename = QFileDialog : : getSaveFileName ( this , " Save cropped area to EasyProfiler File " , dir ,
" EasyProfiler File (*.prof);;All Files (*.*) " ) ;
if ( filename . isEmpty ( ) )
return ;
createProgressDialog ( tr ( " Saving selected region... " ) ) ;
m_readerTimer . start ( ) ;
2018-04-25 21:37:18 +03:00
m_reader . save ( filename , beginTime , endTime , m_serializedDescriptors , EASY_GLOBALS . descriptors ,
2018-06-09 02:18:39 +03:00
m_descriptorsNumberInFile , EASY_GLOBALS . profiler_blocks , EASY_GLOBALS . bookmarks ,
easyBlocksTree , EASY_GLOBALS . pid , true ) ;
}
//////////////////////////////////////////////////////////////////////////
void MainWindow : : onCustomWindowHeaderTriggered ( bool _checked )
{
EASY_GLOBALS . use_custom_window_header = _checked ;
emit EASY_GLOBALS . events . customWindowHeaderChanged ( ) ;
}
void MainWindow : : onRightWindowHeaderPosition ( bool _checked )
{
if ( ! _checked )
return ;
EASY_GLOBALS . is_right_window_header_controls = true ;
emit EASY_GLOBALS . events . windowHeaderPositionChanged ( ) ;
}
void MainWindow : : onLeftWindowHeaderPosition ( bool _checked )
{
if ( ! _checked )
return ;
EASY_GLOBALS . is_right_window_header_controls = false ;
emit EASY_GLOBALS . events . windowHeaderPositionChanged ( ) ;
2018-04-22 03:34:26 +03:00
}
//////////////////////////////////////////////////////////////////////////
2018-01-28 20:52:17 +03:00
void MainWindow : : onConnectClicked ( bool )
2017-02-08 00:14:49 +03:00
{
if ( EASY_GLOBALS . connected )
{
2017-06-09 09:15:56 +03:00
// Disconnect if already connected
m_listener . disconnect ( ) ;
setDisconnected ( false ) ;
return ;
2017-02-08 00:14:49 +03:00
}
2017-06-09 09:15:56 +03:00
QString address = m_addressEdit - > text ( ) ;
const decltype ( m_lastPort ) port = m_portEdit - > text ( ) . toUShort ( ) ;
2017-11-09 23:12:54 +03:00
const bool isSameAddress = ( EASY_GLOBALS . connected & & m_listener . port ( ) = = port & &
address . toStdString ( ) = = m_listener . address ( ) ) ;
2017-06-09 09:15:56 +03:00
2017-02-08 00:14:49 +03:00
profiler : : net : : EasyProfilerStatus reply ( false , false , false ) ;
if ( ! m_listener . connect ( address . toStdString ( ) . c_str ( ) , port , reply ) )
{
2018-06-09 02:18:39 +03:00
Dialog : : warning ( this , " Warning " , QString ( " Cannot connect to %1 " ) . arg ( address ) , QMessageBox : : Close ) ;
2019-03-27 00:07:58 +03:00
// we need to close socket everytime on failed connection
m_listener . closeSocket ( ) ;
setDisconnected ( false ) ;
2017-02-08 00:14:49 +03:00
2017-11-09 23:12:54 +03:00
if ( ! isSameAddress )
{
2018-01-28 20:52:17 +03:00
m_lastAddress = std : : move ( address ) ;
2017-11-09 23:12:54 +03:00
m_lastPort = port ;
2017-02-08 00:14:49 +03:00
}
return ;
}
2018-01-28 20:52:17 +03:00
m_lastAddress = std : : move ( address ) ;
2017-02-08 00:14:49 +03:00
m_lastPort = port ;
qInfo ( ) < < " Connected successfully " ;
EASY_GLOBALS . connected = true ;
m_captureAction - > setEnabled ( true ) ;
2017-11-26 15:37:39 +03:00
m_connectAction - > setIcon ( QIcon ( imagePath ( " connected " ) ) ) ;
2017-04-17 22:13:22 +03:00
m_connectAction - > setText ( tr ( " Disconnect " ) ) ;
if ( m_fpsViewer - > isVisible ( ) )
2018-05-07 21:58:37 +03:00
static_cast < FpsWidget * > ( m_fpsViewer - > widget ( ) ) - > clear ( ) ;
2017-02-08 00:14:49 +03:00
2017-04-03 23:16:36 +03:00
if ( ! m_fpsRequestTimer . isActive ( ) )
m_fpsRequestTimer . start ( EASY_GLOBALS . fps_timer_interval ) ;
2017-02-08 00:14:49 +03:00
disconnect ( m_eventTracingEnableAction , & QAction : : triggered , this , & This : : onEventTracingEnableChange ) ;
disconnect ( m_eventTracingPriorityAction , & QAction : : triggered , this , & This : : onEventTracingPriorityChange ) ;
m_eventTracingEnableAction - > setEnabled ( true ) ;
m_eventTracingPriorityAction - > setEnabled ( true ) ;
m_eventTracingEnableAction - > setChecked ( reply . isEventTracingEnabled ) ;
m_eventTracingPriorityAction - > setChecked ( reply . isLowPriorityEventTracing ) ;
connect ( m_eventTracingEnableAction , & QAction : : triggered , this , & This : : onEventTracingEnableChange ) ;
connect ( m_eventTracingPriorityAction , & QAction : : triggered , this , & This : : onEventTracingPriorityChange ) ;
2017-06-09 09:15:56 +03:00
m_addressEdit - > setEnabled ( false ) ;
m_portEdit - > setEnabled ( false ) ;
2017-02-08 00:14:49 +03:00
emit EASY_GLOBALS . events . connectionChanged ( true ) ;
2017-03-30 06:48:58 +03:00
if ( reply . isProfilerEnabled )
{
// Connected application is already profiling.
// Show capture dialog immediately
onCaptureClicked ( true ) ;
}
2017-02-08 00:14:49 +03:00
}
2018-01-28 20:52:17 +03:00
void MainWindow : : onCaptureClicked ( bool )
2017-02-08 00:14:49 +03:00
{
if ( ! EASY_GLOBALS . connected )
{
2018-06-09 02:18:39 +03:00
Dialog : : warning ( this , " Warning " , " No connection with profiling app " , QMessageBox : : Close ) ;
2017-02-08 00:14:49 +03:00
return ;
}
2018-01-28 20:52:17 +03:00
if ( m_listener . regime ( ) ! = ListenerRegime : : Idle )
2017-02-08 00:14:49 +03:00
{
2018-01-28 20:52:17 +03:00
if ( m_listener . regime ( ) = = ListenerRegime : : Capture | | m_listener . regime ( ) = = ListenerRegime : : Capture_Receive )
{
2018-06-09 02:18:39 +03:00
Dialog : : warning ( this , " Warning " ,
2018-01-28 20:52:17 +03:00
" Already capturing frames. \n Finish old capturing session first. " , QMessageBox : : Close ) ;
}
2017-02-08 00:14:49 +03:00
else
2018-01-28 20:52:17 +03:00
{
2018-06-09 02:18:39 +03:00
Dialog : : warning ( this , " Warning " ,
2018-01-28 20:52:17 +03:00
" Capturing blocks description. \n Finish old capturing session first. " , QMessageBox : : Close ) ;
}
2017-02-08 00:14:49 +03:00
return ;
}
if ( ! m_listener . startCapture ( ) )
{
// Connection lost. Try to restore connection.
profiler : : net : : EasyProfilerStatus reply ( false , false , false ) ;
if ( ! m_listener . connect ( m_lastAddress . toStdString ( ) . c_str ( ) , m_lastPort , reply ) )
{
2017-10-04 22:37:46 +03:00
m_listener . closeSocket ( ) ;
2017-02-08 00:14:49 +03:00
setDisconnected ( ) ;
return ;
}
if ( ! m_listener . startCapture ( ) )
{
2017-10-04 22:37:46 +03:00
m_listener . closeSocket ( ) ;
2017-02-08 00:14:49 +03:00
setDisconnected ( ) ;
return ;
}
}
m_listenerTimer . start ( 250 ) ;
2018-06-09 02:18:39 +03:00
m_listenerDialog = new Dialog ( this , QMessageBox : : Information , " Capturing frames... "
, " Close this dialog to stop capturing. " , QMessageBox : : NoButton ) ;
2017-02-08 00:14:49 +03:00
auto button = new QToolButton ( m_listenerDialog ) ;
button - > setAutoRaise ( true ) ;
button - > setToolButtonStyle ( Qt : : ToolButtonTextBesideIcon ) ;
2018-02-01 23:17:01 +03:00
button - > setIconSize ( applicationIconsSize ( ) ) ;
2017-11-26 15:37:39 +03:00
button - > setIcon ( QIcon ( imagePath ( " stop " ) ) ) ;
2017-02-08 00:14:49 +03:00
button - > setText ( " Stop " ) ;
m_listenerDialog - > addButton ( button , QMessageBox : : AcceptRole ) ;
m_listenerDialog - > setAttribute ( Qt : : WA_DeleteOnClose , true ) ;
connect ( m_listenerDialog , & QDialog : : finished , this , & This : : onListenerDialogClose ) ;
m_listenerDialog - > show ( ) ;
}
2018-01-28 20:52:17 +03:00
void MainWindow : : onGetBlockDescriptionsClicked ( bool )
2017-02-08 00:14:49 +03:00
{
if ( ! EASY_GLOBALS . connected )
{
2018-06-09 02:18:39 +03:00
Dialog : : warning ( this , " Warning " , " No connection with profiling app " , QMessageBox : : Close ) ;
2017-02-08 00:14:49 +03:00
return ;
}
2018-01-28 20:52:17 +03:00
if ( m_listener . regime ( ) ! = ListenerRegime : : Idle )
2017-02-08 00:14:49 +03:00
{
2018-01-28 20:52:17 +03:00
if ( m_listener . regime ( ) = = ListenerRegime : : Descriptors )
{
2018-06-09 02:18:39 +03:00
Dialog : : warning ( this , " Warning " ,
2018-01-28 20:52:17 +03:00
" Already capturing blocks description. \n Finish old capturing session first. " , QMessageBox : : Close ) ;
}
2017-02-08 00:14:49 +03:00
else
2018-01-28 20:52:17 +03:00
{
2018-06-09 02:18:39 +03:00
Dialog : : warning ( this , " Warning " ,
2018-01-28 20:52:17 +03:00
" Already capturing frames. \n Finish old capturing session first. " , QMessageBox : : Close ) ;
}
2017-02-08 00:14:49 +03:00
return ;
}
2018-06-09 02:18:39 +03:00
m_listenerDialog = new Dialog ( this , QMessageBox : : Information , " Waiting for blocks... " ,
" This may take some time. " , QMessageBox : : NoButton ) ;
2017-02-08 00:14:49 +03:00
m_listenerDialog - > setAttribute ( Qt : : WA_DeleteOnClose , true ) ;
m_listenerDialog - > show ( ) ;
m_listener . requestBlocksDescription ( ) ;
m_listenerDialog - > reject ( ) ;
m_listenerDialog = nullptr ;
if ( m_listener . size ( ) ! = 0 )
{
// Read descriptions from stream
decltype ( EASY_GLOBALS . descriptors ) descriptors ;
decltype ( m_serializedDescriptors ) serializedDescriptors ;
2018-01-28 20:52:17 +03:00
std : : stringstream errorMessage ;
2017-02-08 00:14:49 +03:00
if ( readDescriptionsFromStream ( m_listener . data ( ) , serializedDescriptors , descriptors , errorMessage ) )
{
// Merge old and new descriptions
bool cancel = false ;
const bool doFlush = m_descriptorsNumberInFile > descriptors . size ( ) ;
if ( doFlush & & ! m_serializedBlocks . empty ( ) )
{
2018-06-09 02:18:39 +03:00
auto button = Dialog : : question ( this , " Information " ,
2017-02-08 00:14:49 +03:00
QString ( " New blocks description number = %1 \n is less than the old one = %2. \n To avoid possible conflicts \n all profiled data will be deleted. \n Continue? " )
. arg ( descriptors . size ( ) )
. arg ( m_descriptorsNumberInFile ) ,
2018-06-09 02:18:39 +03:00
QMessageBox : : Yes | QMessageBox : : No ) ;
2017-02-08 00:14:49 +03:00
if ( button = = QMessageBox : : Yes )
clear ( ) ; // Clear all contents because new descriptors list conflicts with old one
else
cancel = true ;
}
if ( ! cancel )
{
if ( ! doFlush & & m_descriptorsNumberInFile < EASY_GLOBALS . descriptors . size ( ) )
{
// There are dynamically added descriptors, add them to the new list too
auto newnumber = static_cast < decltype ( m_descriptorsNumberInFile ) > ( descriptors . size ( ) ) ;
auto size = static_cast < decltype ( m_descriptorsNumberInFile ) > ( EASY_GLOBALS . descriptors . size ( ) ) ;
auto diff = newnumber - size ;
decltype ( newnumber ) failnumber = 0 ;
descriptors . reserve ( descriptors . size ( ) + EASY_GLOBALS . descriptors . size ( ) - m_descriptorsNumberInFile ) ;
for ( auto i = m_descriptorsNumberInFile ; i < size ; + + i )
{
auto id = EASY_GLOBALS . descriptors [ i ] - > id ( ) ;
if ( id < newnumber )
descriptors . push_back ( descriptors [ id ] ) ;
else
+ + failnumber ;
}
if ( failnumber ! = 0 )
{
// There are some errors...
// revert changes
descriptors . resize ( newnumber ) ;
// clear all profiled data to avoid conflicts
2018-06-09 02:18:39 +03:00
auto button = Dialog : : question ( this , " Information " ,
2017-02-08 00:14:49 +03:00
" There are errors while merging block descriptions lists. \n To avoid possible conflicts \n all profiled data will be deleted. \n Continue? " ,
2018-06-09 02:18:39 +03:00
QMessageBox : : Yes | QMessageBox : : No ) ;
2017-02-08 00:14:49 +03:00
if ( button = = QMessageBox : : Yes )
clear ( ) ; // Clear all contents because new descriptors list conflicts with old one
else
cancel = true ;
}
if ( ! cancel & & diff ! = 0 )
{
for ( auto & b : EASY_GLOBALS . gui_blocks )
{
if ( b . tree . node - > id ( ) > = m_descriptorsNumberInFile )
b . tree . node - > setId ( b . tree . node - > id ( ) + diff ) ;
}
m_descriptorsNumberInFile = newnumber ;
}
}
if ( ! cancel )
{
EASY_GLOBALS . descriptors . swap ( descriptors ) ;
m_serializedDescriptors . swap ( serializedDescriptors ) ;
m_descriptorsNumberInFile = static_cast < uint32_t > ( EASY_GLOBALS . descriptors . size ( ) ) ;
2018-01-25 23:21:56 +03:00
if ( m_descTreeDialog . ptr ! = nullptr )
2017-02-08 00:14:49 +03:00
{
# if EASY_GUI_USE_DESCRIPTORS_DOCK_WINDOW != 0
2018-01-28 20:52:17 +03:00
static_cast < BlockDescriptorsWidget * > ( m_descTreeWidget - > widget ( ) ) - > build ( ) ;
2017-02-08 00:14:49 +03:00
# endif
m_dialogDescTree - > build ( ) ;
2018-01-25 23:21:56 +03:00
m_descTreeDialog . ptr - > raise ( ) ;
2018-06-09 02:18:39 +03:00
m_descTreeDialog . ptr - > setFocus ( ) ;
2017-02-08 00:14:49 +03:00
}
else
{
onEditBlocksClicked ( true ) ;
}
}
}
}
else
{
2018-06-09 02:18:39 +03:00
Dialog : : warning ( this , " Warning " ,
QString ( " Cannot read blocks description from stream. \n \n Reason: \n %1 " )
. arg ( errorMessage . str ( ) . c_str ( ) ) , QMessageBox : : Close ) ;
2017-02-08 00:14:49 +03:00
}
m_listener . clearData ( ) ;
}
if ( ! m_listener . connected ( ) )
{
2017-10-04 22:37:46 +03:00
m_listener . closeSocket ( ) ;
2017-02-08 00:14:49 +03:00
setDisconnected ( ) ;
}
}
//////////////////////////////////////////////////////////////////////////
2018-04-22 03:34:26 +03:00
void MainWindow : : onBlockStatusChange ( profiler : : block_id_t _id , profiler : : EasyBlockStatus _status )
2017-02-08 00:14:49 +03:00
{
if ( EASY_GLOBALS . connected )
m_listener . send ( profiler : : net : : BlockStatusMessage ( _id , static_cast < uint8_t > ( _status ) ) ) ;
}
2018-03-13 01:28:58 +03:00
void MainWindow : : onSelectValue ( profiler : : thread_id_t _thread_id , uint32_t _value_index , const profiler : : ArbitraryValue & _value )
2018-03-12 01:47:20 +03:00
{
onEditBlocksClicked ( true ) ;
2018-03-13 01:28:58 +03:00
m_dialogDescTree - > dataViewer ( ) - > rebuild ( _thread_id , _value_index , _value . id ( ) ) ;
2018-03-12 01:47:20 +03:00
}
2018-06-09 02:18:39 +03:00
void DialogWithGeometry : : create ( QWidget * content , QWidget * parent )
2018-01-25 23:21:56 +03:00
{
2019-10-20 16:12:37 +03:00
ptr = new Dialog ( parent , EASY_DEFAULT_WINDOW_TITLE , content , WindowHeader : : AllButtons , QMessageBox : : NoButton ) ;
2018-06-09 02:18:39 +03:00
ptr - > setProperty ( " stayVisible " , true ) ;
2018-01-25 23:21:56 +03:00
ptr - > setAttribute ( Qt : : WA_DeleteOnClose , true ) ;
}
void DialogWithGeometry : : saveGeometry ( )
{
geometry = ptr - > saveGeometry ( ) ;
}
void DialogWithGeometry : : restoreGeometry ( )
{
if ( ! geometry . isEmpty ( ) )
ptr - > restoreGeometry ( geometry ) ;
}
2017-02-08 00:14:49 +03:00
//////////////////////////////////////////////////////////////////////////
2018-02-01 23:17:01 +03:00
SocketListener : : SocketListener ( ) : m_receivedSize ( 0 ) , m_port ( 0 ) , m_regime ( ListenerRegime : : Idle )
2017-02-08 00:14:49 +03:00
{
2018-09-18 22:41:58 +03:00
m_bInterrupt = false ;
m_bConnected = false ;
m_bStopReceive = false ;
m_bFrameTimeReady = false ;
m_bCaptureReady = false ;
m_frameMax = 0 ;
m_frameAvg = 0 ;
2017-02-08 00:14:49 +03:00
}
2018-02-01 23:17:01 +03:00
SocketListener : : ~ SocketListener ( )
2017-02-08 00:14:49 +03:00
{
2018-01-28 20:52:17 +03:00
m_bInterrupt . store ( true , std : : memory_order_release ) ;
2017-02-08 00:14:49 +03:00
if ( m_thread . joinable ( ) )
m_thread . join ( ) ;
}
2018-02-01 23:17:01 +03:00
bool SocketListener : : connected ( ) const
2017-02-08 00:14:49 +03:00
{
2018-01-28 20:52:17 +03:00
return m_bConnected . load ( std : : memory_order_acquire ) ;
2017-02-08 00:14:49 +03:00
}
2018-02-01 23:17:01 +03:00
bool SocketListener : : captured ( ) const
2017-04-03 23:28:19 +03:00
{
2018-01-28 20:52:17 +03:00
return m_bCaptureReady . load ( std : : memory_order_acquire ) ;
2017-04-03 23:28:19 +03:00
}
2018-02-01 23:17:01 +03:00
ListenerRegime SocketListener : : regime ( ) const
2017-02-08 00:14:49 +03:00
{
return m_regime ;
}
2018-02-01 23:17:01 +03:00
uint64_t SocketListener : : size ( ) const
2017-02-08 00:14:49 +03:00
{
return m_receivedSize ;
}
2018-02-01 23:17:01 +03:00
std : : stringstream & SocketListener : : data ( )
2017-02-08 00:14:49 +03:00
{
return m_receivedData ;
}
2018-02-01 23:17:01 +03:00
const std : : string & SocketListener : : address ( ) const
2016-12-08 22:22:09 +03:00
{
return m_address ;
}
2018-02-01 23:17:01 +03:00
uint16_t SocketListener : : port ( ) const
2017-02-08 00:14:49 +03:00
{
return m_port ;
}
2018-02-01 23:17:01 +03:00
void SocketListener : : clearData ( )
2017-02-08 00:14:49 +03:00
{
clear_stream ( m_receivedData ) ;
m_receivedSize = 0 ;
}
2018-02-01 23:17:01 +03:00
void SocketListener : : disconnect ( )
2017-04-17 22:13:22 +03:00
{
if ( connected ( ) )
{
2018-01-28 20:52:17 +03:00
m_bInterrupt . store ( true , std : : memory_order_release ) ;
2017-04-17 22:13:22 +03:00
if ( m_thread . joinable ( ) )
m_thread . join ( ) ;
2018-01-28 20:52:17 +03:00
m_bConnected . store ( false , std : : memory_order_release ) ;
m_bInterrupt . store ( false , std : : memory_order_release ) ;
m_bCaptureReady . store ( false , std : : memory_order_release ) ;
m_bStopReceive . store ( false , std : : memory_order_release ) ;
2017-04-17 22:13:22 +03:00
}
m_address . clear ( ) ;
m_port = 0 ;
2017-10-04 22:37:46 +03:00
closeSocket ( ) ;
}
2018-02-01 23:17:01 +03:00
void SocketListener : : closeSocket ( )
2017-10-04 22:37:46 +03:00
{
2017-04-17 22:13:22 +03:00
m_easySocket . flush ( ) ;
m_easySocket . init ( ) ;
}
2018-02-01 23:17:01 +03:00
bool SocketListener : : connect ( const char * _ipaddress , uint16_t _port , profiler : : net : : EasyProfilerStatus & _reply , bool _disconnectFirst )
2017-02-08 00:14:49 +03:00
{
if ( connected ( ) )
{
2018-01-28 20:52:17 +03:00
m_bInterrupt . store ( true , std : : memory_order_release ) ;
2017-02-08 00:14:49 +03:00
if ( m_thread . joinable ( ) )
m_thread . join ( ) ;
2018-01-28 20:52:17 +03:00
m_bConnected . store ( false , std : : memory_order_release ) ;
m_bInterrupt . store ( false , std : : memory_order_release ) ;
m_bCaptureReady . store ( false , std : : memory_order_release ) ;
m_bStopReceive . store ( false , std : : memory_order_release ) ;
2017-02-08 00:14:49 +03:00
}
m_address . clear ( ) ;
m_port = 0 ;
2017-10-04 22:37:46 +03:00
if ( _disconnectFirst )
closeSocket ( ) ;
2017-02-08 00:14:49 +03:00
int res = m_easySocket . setAddress ( _ipaddress , _port ) ;
res = m_easySocket . connect ( ) ;
const bool isConnected = res = = 0 ;
if ( isConnected )
{
static const size_t buffer_size = sizeof ( profiler : : net : : EasyProfilerStatus ) < < 1 ;
char buffer [ buffer_size ] = { } ;
int bytes = 0 ;
while ( true )
{
bytes = m_easySocket . receive ( buffer , buffer_size ) ;
if ( bytes = = - 1 )
{
if ( m_easySocket . isDisconnected ( ) )
return false ;
bytes = 0 ;
continue ;
}
break ;
}
if ( bytes = = 0 )
{
m_address = _ipaddress ;
m_port = _port ;
2018-01-28 20:52:17 +03:00
m_bConnected . store ( isConnected , std : : memory_order_release ) ;
2017-02-08 00:14:49 +03:00
return isConnected ;
}
size_t seek = bytes ;
while ( seek < sizeof ( profiler : : net : : EasyProfilerStatus ) )
{
bytes = m_easySocket . receive ( buffer + seek , buffer_size - seek ) ;
if ( bytes = = - 1 )
{
if ( m_easySocket . isDisconnected ( ) )
return false ;
break ;
}
seek + = bytes ;
}
2018-04-22 03:34:26 +03:00
auto message = reinterpret_cast < const profiler : : net : : EasyProfilerStatus * > ( buffer ) ;
2017-11-09 23:12:54 +03:00
if ( message - > isEasyNetMessage ( ) & & message - > type = = profiler : : net : : MessageType : : Connection_Accepted )
2017-02-08 00:14:49 +03:00
_reply = * message ;
m_address = _ipaddress ;
m_port = _port ;
}
2018-01-28 20:52:17 +03:00
m_bConnected . store ( isConnected , std : : memory_order_release ) ;
2017-02-08 00:14:49 +03:00
return isConnected ;
}
2018-04-22 03:34:26 +03:00
bool SocketListener : : reconnect ( const char * _ipaddress , uint16_t _port , profiler : : net : : EasyProfilerStatus & _reply )
2017-10-04 22:37:46 +03:00
{
return connect ( _ipaddress , _port , _reply , true ) ;
}
2018-02-01 23:17:01 +03:00
bool SocketListener : : startCapture ( )
2017-02-08 00:14:49 +03:00
{
2017-04-03 23:28:19 +03:00
//if (m_thread.joinable())
//{
2018-01-28 20:52:17 +03:00
// m_bInterrupt.store(true, std::memory_order_release);
2017-04-03 23:28:19 +03:00
// m_thread.join();
2018-01-28 20:52:17 +03:00
// m_bInterrupt.store(false, std::memory_order_release);
2017-04-03 23:28:19 +03:00
//}
2017-04-03 23:16:36 +03:00
2017-02-08 00:14:49 +03:00
clearData ( ) ;
2017-11-09 23:12:54 +03:00
profiler : : net : : Message request ( profiler : : net : : MessageType : : Request_Start_Capture ) ;
2017-02-08 00:14:49 +03:00
m_easySocket . send ( & request , sizeof ( request ) ) ;
if ( m_easySocket . isDisconnected ( ) ) {
2018-01-28 20:52:17 +03:00
m_bConnected . store ( false , std : : memory_order_release ) ;
2017-02-08 00:14:49 +03:00
return false ;
}
2018-01-28 20:52:17 +03:00
m_regime = ListenerRegime : : Capture ;
m_bCaptureReady . store ( false , std : : memory_order_release ) ;
2018-02-01 23:17:01 +03:00
//m_thread = std::thread(&SocketListener::listenCapture, this);
2017-02-08 00:14:49 +03:00
return true ;
}
2018-02-01 23:17:01 +03:00
void SocketListener : : stopCapture ( )
2017-02-08 00:14:49 +03:00
{
2018-01-28 20:52:17 +03:00
//if (!m_thread.joinable() || m_regime != ListenerRegime::Capture)
2017-04-03 23:28:19 +03:00
// return;
2017-02-08 00:14:49 +03:00
2018-01-28 20:52:17 +03:00
if ( m_regime ! = ListenerRegime : : Capture )
2017-04-03 23:28:19 +03:00
return ;
2017-02-08 00:14:49 +03:00
2018-01-28 20:52:17 +03:00
//m_bStopReceive.store(true, std::memory_order_release);
2017-11-09 23:12:54 +03:00
profiler : : net : : Message request ( profiler : : net : : MessageType : : Request_Stop_Capture ) ;
2017-04-03 23:28:19 +03:00
m_easySocket . send ( & request , sizeof ( request ) ) ;
2017-02-08 00:14:49 +03:00
2017-04-03 23:28:19 +03:00
//m_thread.join();
2017-02-08 00:14:49 +03:00
2017-04-03 23:28:19 +03:00
if ( m_easySocket . isDisconnected ( ) ) {
2018-01-28 20:52:17 +03:00
m_bConnected . store ( false , std : : memory_order_release ) ;
m_bStopReceive . store ( false , std : : memory_order_release ) ;
m_regime = ListenerRegime : : Idle ;
m_bCaptureReady . store ( true , std : : memory_order_release ) ;
2017-04-03 23:28:19 +03:00
return ;
}
2018-01-28 20:52:17 +03:00
m_regime = ListenerRegime : : Capture_Receive ;
2017-04-03 23:28:19 +03:00
if ( m_thread . joinable ( ) )
{
2018-01-28 20:52:17 +03:00
m_bInterrupt . store ( true , std : : memory_order_release ) ;
2017-04-03 23:28:19 +03:00
m_thread . join ( ) ;
2018-01-28 20:52:17 +03:00
m_bInterrupt . store ( false , std : : memory_order_release ) ;
2017-04-03 23:28:19 +03:00
}
2018-02-01 23:17:01 +03:00
m_thread = std : : thread ( & SocketListener : : listenCapture , this ) ;
2017-04-03 23:28:19 +03:00
2018-01-28 20:52:17 +03:00
//m_regime = ListenerRegime::Idle;
//m_bStopReceive.store(false, std::memory_order_release);
2017-04-03 23:28:19 +03:00
}
2018-02-01 23:17:01 +03:00
void SocketListener : : finalizeCapture ( )
2017-04-03 23:28:19 +03:00
{
if ( m_thread . joinable ( ) )
{
2018-01-28 20:52:17 +03:00
m_bInterrupt . store ( true , std : : memory_order_release ) ;
2017-04-03 23:28:19 +03:00
m_thread . join ( ) ;
2018-01-28 20:52:17 +03:00
m_bInterrupt . store ( false , std : : memory_order_release ) ;
2017-04-03 23:28:19 +03:00
}
2017-02-08 00:14:49 +03:00
2018-01-28 20:52:17 +03:00
m_regime = ListenerRegime : : Idle ;
m_bCaptureReady . store ( false , std : : memory_order_release ) ;
m_bStopReceive . store ( false , std : : memory_order_release ) ;
2017-02-08 00:14:49 +03:00
}
2018-02-01 23:17:01 +03:00
void SocketListener : : requestBlocksDescription ( )
2017-02-08 00:14:49 +03:00
{
2017-04-03 23:16:36 +03:00
if ( m_thread . joinable ( ) )
{
2018-01-28 20:52:17 +03:00
m_bInterrupt . store ( true , std : : memory_order_release ) ;
2017-04-03 23:16:36 +03:00
m_thread . join ( ) ;
2018-01-28 20:52:17 +03:00
m_bInterrupt . store ( false , std : : memory_order_release ) ;
2017-04-03 23:16:36 +03:00
}
2017-02-08 00:14:49 +03:00
clearData ( ) ;
2017-11-09 23:12:54 +03:00
profiler : : net : : Message request ( profiler : : net : : MessageType : : Request_Blocks_Description ) ;
2017-02-08 00:14:49 +03:00
m_easySocket . send ( & request , sizeof ( request ) ) ;
if ( m_easySocket . isDisconnected ( ) ) {
2018-01-28 20:52:17 +03:00
m_bConnected . store ( false , std : : memory_order_release ) ;
2017-02-08 00:14:49 +03:00
}
2018-01-28 20:52:17 +03:00
m_regime = ListenerRegime : : Descriptors ;
2017-02-08 00:14:49 +03:00
listenDescription ( ) ;
2018-01-28 20:52:17 +03:00
m_regime = ListenerRegime : : Idle ;
2017-02-08 00:14:49 +03:00
}
2018-02-01 23:17:01 +03:00
bool SocketListener : : frameTime ( uint32_t & _maxTime , uint32_t & _avgTime )
2017-04-03 23:16:36 +03:00
{
2018-01-28 20:52:17 +03:00
if ( m_bFrameTimeReady . exchange ( false , std : : memory_order_acquire ) )
2017-04-03 23:16:36 +03:00
{
2018-01-28 20:52:17 +03:00
_maxTime = m_frameMax . load ( std : : memory_order_acquire ) ;
_avgTime = m_frameAvg . load ( std : : memory_order_acquire ) ;
2017-04-03 23:16:36 +03:00
return true ;
}
return false ;
}
2018-02-01 23:17:01 +03:00
bool SocketListener : : requestFrameTime ( )
2017-04-03 23:16:36 +03:00
{
2018-01-28 20:52:17 +03:00
if ( m_regime ! = ListenerRegime : : Idle & & m_regime ! = ListenerRegime : : Capture )
2017-04-03 23:16:36 +03:00
return false ;
if ( m_thread . joinable ( ) )
{
2018-01-28 20:52:17 +03:00
m_bInterrupt . store ( true , std : : memory_order_release ) ;
2017-04-03 23:16:36 +03:00
m_thread . join ( ) ;
2018-01-28 20:52:17 +03:00
m_bInterrupt . store ( false , std : : memory_order_release ) ;
2017-04-03 23:16:36 +03:00
}
2017-11-09 23:12:54 +03:00
profiler : : net : : Message request ( profiler : : net : : MessageType : : Request_MainThread_FPS ) ;
2017-04-03 23:16:36 +03:00
m_easySocket . send ( & request , sizeof ( request ) ) ;
if ( m_easySocket . isDisconnected ( ) )
{
2018-01-28 20:52:17 +03:00
m_bConnected . store ( false , std : : memory_order_release ) ;
2017-04-03 23:16:36 +03:00
return false ;
}
2018-01-28 20:52:17 +03:00
m_bFrameTimeReady . store ( false , std : : memory_order_release ) ;
2018-02-01 23:17:01 +03:00
m_thread = std : : thread ( & SocketListener : : listenFrameTime , this ) ;
2017-04-03 23:16:36 +03:00
return true ;
}
2017-02-08 00:14:49 +03:00
//////////////////////////////////////////////////////////////////////////
2018-02-01 23:17:01 +03:00
void SocketListener : : listenCapture ( )
2017-02-08 00:14:49 +03:00
{
2017-11-09 23:12:54 +03:00
EASY_STATIC_CONSTEXPR int buffer_size = 8 * 1024 * 1024 ;
2017-02-08 00:14:49 +03:00
char * buffer = new char [ buffer_size ] ;
int seek = 0 , bytes = 0 ;
2018-01-28 20:52:17 +03:00
auto timeBegin = std : : chrono : : system_clock : : now ( ) ;
2017-02-08 00:14:49 +03:00
bool isListen = true , disconnected = false ;
2018-01-28 20:52:17 +03:00
while ( isListen & & ! m_bInterrupt . load ( std : : memory_order_acquire ) )
2017-02-08 00:14:49 +03:00
{
2018-01-28 20:52:17 +03:00
if ( m_bStopReceive . load ( std : : memory_order_acquire ) )
2017-02-08 00:14:49 +03:00
{
2017-11-09 23:12:54 +03:00
profiler : : net : : Message request ( profiler : : net : : MessageType : : Request_Stop_Capture ) ;
2017-02-08 00:14:49 +03:00
m_easySocket . send ( & request , sizeof ( request ) ) ;
2018-01-28 20:52:17 +03:00
m_bStopReceive . store ( false , std : : memory_order_release ) ;
2017-02-08 00:14:49 +03:00
}
if ( ( bytes - seek ) = = 0 )
{
bytes = m_easySocket . receive ( buffer , buffer_size ) ;
if ( bytes = = - 1 )
{
if ( m_easySocket . isDisconnected ( ) )
{
2018-01-28 20:52:17 +03:00
m_bConnected . store ( false , std : : memory_order_release ) ;
2017-02-08 00:14:49 +03:00
isListen = false ;
disconnected = true ;
}
seek = 0 ;
bytes = 0 ;
continue ;
}
seek = 0 ;
}
if ( bytes = = 0 )
{
isListen = false ;
break ;
}
char * buf = buffer + seek ;
if ( bytes > 0 )
{
2018-04-22 03:34:26 +03:00
auto message = reinterpret_cast < const profiler : : net : : Message * > ( buf ) ;
2017-02-08 00:14:49 +03:00
if ( ! message - > isEasyNetMessage ( ) )
continue ;
switch ( message - > type )
{
2017-11-09 23:12:54 +03:00
case profiler : : net : : MessageType : : Connection_Accepted :
2017-02-08 00:14:49 +03:00
{
2017-11-09 23:12:54 +03:00
qInfo ( ) < < " Receive MessageType::Connection_Accepted " ;
2017-02-08 00:14:49 +03:00
//m_easySocket.send(&request, sizeof(request));
seek + = sizeof ( profiler : : net : : Message ) ;
break ;
}
2017-11-09 23:12:54 +03:00
case profiler : : net : : MessageType : : Reply_Capturing_Started :
2017-02-08 00:14:49 +03:00
{
2017-11-09 23:12:54 +03:00
qInfo ( ) < < " Receive MessageType::Reply_Capturing_Started " ;
2017-02-08 00:14:49 +03:00
seek + = sizeof ( profiler : : net : : Message ) ;
break ;
}
2017-11-09 23:12:54 +03:00
case profiler : : net : : MessageType : : Reply_Blocks_End :
2017-02-08 00:14:49 +03:00
{
2017-11-09 23:12:54 +03:00
qInfo ( ) < < " Receive MessageType::Reply_Blocks_End " ;
2017-02-08 00:14:49 +03:00
seek + = sizeof ( profiler : : net : : Message ) ;
2018-01-28 20:52:17 +03:00
const auto dt = std : : chrono : : duration_cast < std : : chrono : : milliseconds > ( std : : chrono : : system_clock : : now ( ) - timeBegin ) ;
2017-02-08 00:14:49 +03:00
const auto bytesNumber = m_receivedData . str ( ) . size ( ) ;
2018-10-04 13:10:42 +03:00
qInfo ( ) < < " received " < < bytesNumber < < " bytes, " < < dt . count ( ) < < " ms, average speed = " < < double ( bytesNumber ) * 1e3 / double ( dt . count ( ) ) / 1024. < < " kBytes/sec " ;
2017-02-08 00:14:49 +03:00
seek = 0 ;
bytes = 0 ;
isListen = false ;
break ;
}
2017-11-09 23:12:54 +03:00
case profiler : : net : : MessageType : : Reply_Blocks :
2017-02-08 00:14:49 +03:00
{
2017-11-09 23:12:54 +03:00
qInfo ( ) < < " Receive MessageType::Reply_Blocks " ;
2017-02-08 00:14:49 +03:00
seek + = sizeof ( profiler : : net : : DataMessage ) ;
2017-11-09 23:12:54 +03:00
auto dm = ( profiler : : net : : DataMessage * ) message ;
2017-02-08 00:14:49 +03:00
timeBegin = std : : chrono : : system_clock : : now ( ) ;
int neededSize = dm - > size ;
buf = buffer + seek ;
2018-01-28 20:52:17 +03:00
auto bytesNumber = std : : min ( ( int ) dm - > size , bytes - seek ) ;
2017-02-08 00:14:49 +03:00
m_receivedSize + = bytesNumber ;
m_receivedData . write ( buf , bytesNumber ) ;
neededSize - = bytesNumber ;
if ( neededSize = = 0 )
seek + = bytesNumber ;
else
{
seek = 0 ;
bytes = 0 ;
}
int loaded = 0 ;
while ( neededSize > 0 )
{
bytes = m_easySocket . receive ( buffer , buffer_size ) ;
if ( bytes = = - 1 )
{
if ( m_easySocket . isDisconnected ( ) )
{
2018-01-28 20:52:17 +03:00
m_bConnected . store ( false , std : : memory_order_release ) ;
2017-02-08 00:14:49 +03:00
isListen = false ;
disconnected = true ;
neededSize = 0 ;
}
break ;
}
buf = buffer ;
2018-01-28 20:52:17 +03:00
int toWrite = std : : min ( bytes , neededSize ) ;
2017-02-08 00:14:49 +03:00
m_receivedSize + = toWrite ;
m_receivedData . write ( buf , toWrite ) ;
neededSize - = toWrite ;
loaded + = toWrite ;
seek = toWrite ;
}
2018-01-28 20:52:17 +03:00
if ( m_bStopReceive . load ( std : : memory_order_acquire ) )
2017-02-08 00:14:49 +03:00
{
2017-11-09 23:12:54 +03:00
profiler : : net : : Message request ( profiler : : net : : MessageType : : Request_Stop_Capture ) ;
2017-02-08 00:14:49 +03:00
m_easySocket . send ( & request , sizeof ( request ) ) ;
2018-01-28 20:52:17 +03:00
m_bStopReceive . store ( false , std : : memory_order_release ) ;
2017-02-08 00:14:49 +03:00
}
break ;
}
default :
//qInfo() << "Receive unknown " << message->type;
break ;
}
}
}
if ( disconnected )
clearData ( ) ;
delete [ ] buffer ;
2017-04-03 23:28:19 +03:00
2018-01-28 20:52:17 +03:00
m_bCaptureReady . store ( true , std : : memory_order_release ) ;
2017-02-08 00:14:49 +03:00
}
2018-02-01 23:17:01 +03:00
void SocketListener : : listenDescription ( )
2017-02-08 00:14:49 +03:00
{
2017-11-09 23:12:54 +03:00
EASY_STATIC_CONSTEXPR int buffer_size = 8 * 1024 * 1024 ;
2017-02-08 00:14:49 +03:00
char * buffer = new char [ buffer_size ] ;
int seek = 0 , bytes = 0 ;
bool isListen = true , disconnected = false ;
2018-01-28 20:52:17 +03:00
while ( isListen & & ! m_bInterrupt . load ( std : : memory_order_acquire ) )
2017-02-08 00:14:49 +03:00
{
if ( ( bytes - seek ) = = 0 )
{
bytes = m_easySocket . receive ( buffer , buffer_size ) ;
if ( bytes = = - 1 )
{
if ( m_easySocket . isDisconnected ( ) )
{
2018-01-28 20:52:17 +03:00
m_bConnected . store ( false , std : : memory_order_release ) ;
2017-02-08 00:14:49 +03:00
isListen = false ;
disconnected = true ;
}
seek = 0 ;
bytes = 0 ;
continue ;
}
seek = 0 ;
}
if ( bytes = = 0 )
{
isListen = false ;
break ;
}
char * buf = buffer + seek ;
if ( bytes > 0 )
{
2018-04-22 03:34:26 +03:00
auto message = reinterpret_cast < const profiler : : net : : Message * > ( buf ) ;
2017-02-08 00:14:49 +03:00
if ( ! message - > isEasyNetMessage ( ) )
continue ;
switch ( message - > type )
{
2017-11-09 23:12:54 +03:00
case profiler : : net : : MessageType : : Connection_Accepted :
2017-02-08 00:14:49 +03:00
{
2017-11-09 23:12:54 +03:00
qInfo ( ) < < " Receive MessageType::Connection_Accepted " ;
2017-02-08 00:14:49 +03:00
seek + = sizeof ( profiler : : net : : Message ) ;
break ;
}
2017-11-09 23:12:54 +03:00
case profiler : : net : : MessageType : : Reply_Blocks_Description_End :
2017-02-08 00:14:49 +03:00
{
2017-11-09 23:12:54 +03:00
qInfo ( ) < < " Receive MessageType::Reply_Blocks_Description_End " ;
2017-02-08 00:14:49 +03:00
seek + = sizeof ( profiler : : net : : Message ) ;
seek = 0 ;
bytes = 0 ;
isListen = false ;
break ;
}
2017-11-09 23:12:54 +03:00
case profiler : : net : : MessageType : : Reply_Blocks_Description :
2017-02-08 00:14:49 +03:00
{
2017-11-09 23:12:54 +03:00
qInfo ( ) < < " Receive MessageType::Reply_Blocks_Description " ;
2017-02-08 00:14:49 +03:00
seek + = sizeof ( profiler : : net : : DataMessage ) ;
2017-11-09 23:12:54 +03:00
auto dm = ( profiler : : net : : DataMessage * ) message ;
2017-02-08 00:14:49 +03:00
int neededSize = dm - > size ;
buf = buffer + seek ;
2018-01-28 20:52:17 +03:00
auto bytesNumber = std : : min ( ( int ) dm - > size , bytes - seek ) ;
2017-02-08 00:14:49 +03:00
m_receivedSize + = bytesNumber ;
m_receivedData . write ( buf , bytesNumber ) ;
neededSize - = bytesNumber ;
if ( neededSize = = 0 )
seek + = bytesNumber ;
else {
seek = 0 ;
bytes = 0 ;
}
int loaded = 0 ;
while ( neededSize > 0 )
{
bytes = m_easySocket . receive ( buffer , buffer_size ) ;
if ( bytes = = - 1 )
{
if ( m_easySocket . isDisconnected ( ) )
{
2018-01-28 20:52:17 +03:00
m_bConnected . store ( false , std : : memory_order_release ) ;
2017-02-08 00:14:49 +03:00
isListen = false ;
disconnected = true ;
neededSize = 0 ;
}
break ;
}
buf = buffer ;
2018-01-28 20:52:17 +03:00
int toWrite = std : : min ( bytes , neededSize ) ;
2017-02-08 00:14:49 +03:00
m_receivedSize + = toWrite ;
m_receivedData . write ( buf , toWrite ) ;
neededSize - = toWrite ;
loaded + = toWrite ;
seek = toWrite ;
}
break ;
}
default :
break ;
}
}
}
if ( disconnected )
clearData ( ) ;
delete [ ] buffer ;
}
2018-02-01 23:17:01 +03:00
void SocketListener : : listenFrameTime ( )
2017-04-03 23:16:36 +03:00
{
2018-04-22 03:34:26 +03:00
EASY_STATIC_CONSTEXPR size_t buffer_size = sizeof ( profiler : : net : : TimestampMessage ) < < 2 ;
2017-04-03 23:16:36 +03:00
char buffer [ buffer_size ] = { } ;
int seek = 0 , bytes = 0 ;
bool isListen = true ;
2018-01-28 20:52:17 +03:00
while ( isListen & & ! m_bInterrupt . load ( std : : memory_order_acquire ) )
2017-04-03 23:16:36 +03:00
{
if ( ( bytes - seek ) = = 0 )
{
bytes = m_easySocket . receive ( buffer , buffer_size ) ;
if ( bytes = = - 1 )
{
if ( m_easySocket . isDisconnected ( ) )
{
2018-01-28 20:52:17 +03:00
m_bConnected . store ( false , std : : memory_order_release ) ;
2017-04-03 23:16:36 +03:00
isListen = false ;
}
seek = 0 ;
bytes = 0 ;
continue ;
}
seek = 0 ;
}
if ( bytes = = 0 )
{
isListen = false ;
break ;
}
char * buf = buffer + seek ;
if ( bytes > 0 )
{
2018-04-22 03:34:26 +03:00
auto message = reinterpret_cast < const profiler : : net : : Message * > ( buf ) ;
2017-04-03 23:16:36 +03:00
if ( ! message - > isEasyNetMessage ( ) )
continue ;
switch ( message - > type )
{
2017-11-09 23:12:54 +03:00
case profiler : : net : : MessageType : : Connection_Accepted :
case profiler : : net : : MessageType : : Reply_Capturing_Started :
2017-04-03 23:16:36 +03:00
{
seek + = sizeof ( profiler : : net : : Message ) ;
break ;
}
2017-11-09 23:12:54 +03:00
case profiler : : net : : MessageType : : Reply_MainThread_FPS :
2017-04-03 23:16:36 +03:00
{
2017-11-09 23:12:54 +03:00
//qInfo() << "Receive MessageType::Reply_MainThread_FPS";
2017-04-03 23:16:36 +03:00
seek + = sizeof ( profiler : : net : : TimestampMessage ) ;
if ( seek < = buffer_size )
{
2017-11-09 23:12:54 +03:00
auto timestampMessage = ( profiler : : net : : TimestampMessage * ) message ;
2018-01-28 20:52:17 +03:00
m_frameMax . store ( timestampMessage - > maxValue , std : : memory_order_release ) ;
m_frameAvg . store ( timestampMessage - > avgValue , std : : memory_order_release ) ;
m_bFrameTimeReady . store ( true , std : : memory_order_release ) ;
2017-04-03 23:16:36 +03:00
}
isListen = false ;
break ;
}
default :
break ;
}
}
}
}
2017-02-08 00:14:49 +03:00
//////////////////////////////////////////////////////////////////////////