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 .
* :
* : * 2016 / 06 / 27 Victor Zarubkin : Passing blocks number to EasyTreeWidget : : setTree ( ) .
* :
* : * 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 + +
2017-03-30 06:55:15 +03:00
* : Copyright ( C ) 2016 - 2017 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>
# include <QStatusBar>
# include <QFileDialog>
# include <QAction>
# include <QMenu>
# include <QMenuBar>
2017-11-16 22:32:28 +03:00
# include <QPushButton>
2017-02-08 00:14:49 +03:00
# include <QCloseEvent>
# include <QSettings>
# include <QTextCodec>
# include <QFont>
# include <QProgressDialog>
# include <QSignalBlocker>
# include <QDebug>
# include <QToolBar>
# include <QToolButton>
# include <QWidgetAction>
# include <QSpinBox>
# include <QMessageBox>
# include <QLineEdit>
# include <QLabel>
# include <QDialog>
# include <QVBoxLayout>
# include <QFile>
2017-05-02 23:21:15 +03:00
# include <QFileInfo>
2017-02-08 00:14:49 +03:00
# include <QDragEnterEvent>
# include <QDragMoveEvent>
# include <QDragLeaveEvent>
# include <QDropEvent>
# include <QMimeData>
2017-05-02 23:21:15 +03:00
# include <QDateTime>
2017-02-08 00:14:49 +03:00
# include "main_window.h"
# include "blocks_tree_widget.h"
# include "blocks_graphics_view.h"
# include "descriptors_tree_widget.h"
2017-04-03 23:16:36 +03:00
# include "easy_frame_rate_viewer.h"
2017-02-08 00:14:49 +03:00
# include "globals.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>
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 " ;
//////////////////////////////////////////////////////////////////////////
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
}
//////////////////////////////////////////////////////////////////////////
2017-11-16 22:32:28 +03:00
EasyDockWidget : : EasyDockWidget ( const QString & title , QWidget * parent ) : QDockWidget ( title , parent )
{
auto floatingButton = new QPushButton ( ) ;
floatingButton - > setObjectName ( " EasyDockWidgetFloatButton " ) ;
2017-11-17 21:22:53 +03:00
floatingButton - > setProperty ( " floating " , isFloating ( ) ) ;
connect ( floatingButton , & QPushButton : : clicked , [ this , floatingButton ] {
2017-11-16 22:32:28 +03:00
setFloating ( ! isFloating ( ) ) ;
2017-11-17 21:22:53 +03:00
floatingButton - > setProperty ( " floating " , isFloating ( ) ) ;
floatingButton - > style ( ) - > unpolish ( floatingButton ) ;
floatingButton - > style ( ) - > polish ( floatingButton ) ;
floatingButton - > update ( ) ;
2017-11-16 22:32:28 +03:00
} ) ;
auto closeButton = new QPushButton ( ) ;
closeButton - > setObjectName ( " EasyDockWidgetCloseButton " ) ;
connect ( closeButton , & QPushButton : : clicked , [ this ] {
close ( ) ;
} ) ;
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 ) ;
lay - > addWidget ( floatingButton ) ;
lay - > addWidget ( closeButton ) ;
setTitleBarWidget ( caption ) ;
}
EasyDockWidget : : ~ EasyDockWidget ( )
{
}
2017-02-08 00:14:49 +03:00
EasyMainWindow : : EasyMainWindow ( ) : Parent ( ) , m_lastAddress ( " localhost " ) , m_lastPort ( : : profiler : : DEFAULT_PORT )
{
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 ) ;
resize ( 800 , 600 ) ;
2017-02-15 21:45:14 +03:00
setStatusBar ( nullptr ) ;
2017-02-08 00:14:49 +03:00
2017-11-16 22:32:28 +03:00
m_graphicsView = new EasyDockWidget ( " Diagram " , this ) ;
2017-02-08 00:14:49 +03:00
m_graphicsView - > setObjectName ( " ProfilerGUI_Diagram " ) ;
m_graphicsView - > setMinimumHeight ( 50 ) ;
m_graphicsView - > setAllowedAreas ( Qt : : AllDockWidgetAreas ) ;
auto graphicsView = new EasyGraphicsViewWidget ( this ) ;
m_graphicsView - > setWidget ( graphicsView ) ;
2017-11-16 22:32:28 +03:00
m_treeWidget = new EasyDockWidget ( " Hierarchy " , this ) ;
2017-02-08 00:14:49 +03:00
m_treeWidget - > setObjectName ( " ProfilerGUI_Hierarchy " ) ;
m_treeWidget - > setMinimumHeight ( 50 ) ;
m_treeWidget - > setAllowedAreas ( Qt : : AllDockWidgetAreas ) ;
auto treeWidget = new EasyHierarchyWidget ( this ) ;
m_treeWidget - > setWidget ( treeWidget ) ;
2017-11-16 22:32:28 +03:00
m_fpsViewer = new EasyDockWidget ( " FPS Monitor " , this ) ;
2017-04-03 23:16:36 +03:00
m_fpsViewer - > setObjectName ( " ProfilerGUI_FPS " ) ;
m_fpsViewer - > setWidget ( new EasyFrameRateViewer ( this ) ) ;
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
auto descTree = new EasyDescWidget ( ) ;
2017-11-16 22:32:28 +03:00
m_descTreeWidget = new EasyDockWidget ( " Blocks " ) ;
2017-02-08 00:14:49 +03:00
m_descTreeWidget - > setObjectName ( " ProfilerGUI_Blocks " ) ;
m_descTreeWidget - > setMinimumHeight ( 50 ) ;
m_descTreeWidget - > setAllowedAreas ( Qt : : AllDockWidgetAreas ) ;
m_descTreeWidget - > setWidget ( descTree ) ;
addDockWidget ( Qt : : BottomDockWidgetArea , m_descTreeWidget ) ;
# endif
loadSettings ( ) ;
auto toolbar = addToolBar ( " FileToolbar " ) ;
toolbar - > setIconSize ( : : profiler_gui : : ICONS_SIZE ) ;
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-20 23:34:45 +03:00
action - > setIcon ( QIcon ( " :/images/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-20 23:34:45 +03:00
m_saveAction = toolbar - > addAction ( QIcon ( " :/images/save " ) , tr ( " Save " ) , this , SLOT ( onSaveFileClicked ( bool ) ) ) ;
m_deleteAction = toolbar - > addAction ( QIcon ( " :/images/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 " ) ;
toolbar - > setIconSize ( : : profiler_gui : : ICONS_SIZE ) ;
toolbar - > setObjectName ( " ProfilerGUI_ProfileToolbar " ) ;
toolbar - > setContentsMargins ( 1 , 0 , 1 , 0 ) ;
2017-11-20 23:34:45 +03:00
toolbar - > addAction ( QIcon ( " :/images/list " ) , tr ( " Blocks " ) , this , SLOT ( onEditBlocksClicked ( bool ) ) ) ;
m_captureAction = toolbar - > addAction ( QIcon ( " :/images/start " ) , tr ( " Capture " ) , this , SLOT ( onCaptureClicked ( bool ) ) ) ;
2017-02-08 00:14:49 +03:00
m_captureAction - > setEnabled ( false ) ;
toolbar - > addSeparator ( ) ;
2017-11-20 23:34:45 +03:00
m_connectAction = toolbar - > addAction ( QIcon ( " :/images/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 ) ;
connect ( m_addressEdit , & QLineEdit : : returnPressed , [ this ] ( ) { onConnectClicked ( true ) ; } ) ;
connect ( m_portEdit , & QLineEdit : : returnPressed , [ this ] ( ) { onConnectClicked ( true ) ; } ) ;
toolbar = addToolBar ( " SetupToolbar " ) ;
toolbar - > setIconSize ( : : profiler_gui : : ICONS_SIZE ) ;
toolbar - > setObjectName ( " ProfilerGUI_SetupToolbar " ) ;
toolbar - > setContentsMargins ( 1 , 0 , 1 , 0 ) ;
2017-11-20 23:34:45 +03:00
toolbar - > addAction ( QIcon ( " :/images/expand " ) , " Expand all " , this , SLOT ( onExpandAllClicked ( bool ) ) ) ;
toolbar - > addAction ( QIcon ( " :/images/collapse " ) , " Collapse all " , this , SLOT ( onCollapseAllClicked ( bool ) ) ) ;
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 ) ;
2017-02-08 00:14:49 +03:00
QToolButton * toolButton = new QToolButton ( toolbar ) ;
2017-11-20 23:34:45 +03:00
toolButton - > setIcon ( QIcon ( " :/images/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-20 23:34:45 +03:00
action - > setIcon ( QIcon ( " :/images/stats " ) ) ;
2017-02-08 00:14:49 +03:00
}
else
{
action - > setText ( " Statistics disabled " ) ;
2017-11-20 23:34:45 +03:00
action - > setIcon ( QIcon ( " :/images/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 ) ;
action = submenu - > addAction ( " Draw items' borders " ) ;
action - > setToolTip ( " Draw borders for blocks on diagram. \n This reduces performance. " ) ;
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 ) ;
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
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 ) ;
action = new QAction ( " Chrono text at top " , actionGroup ) ;
action - > setToolTip ( " Draw duration of selected interval \n at the top of the screen. " ) ;
action - > setCheckable ( true ) ;
action - > setData ( static_cast < int > ( : : profiler_gui : : ChronoTextPosition_Top ) ) ;
if ( EASY_GLOBALS . chrono_text_position = = : : profiler_gui : : ChronoTextPosition_Top )
action - > setChecked ( true ) ;
submenu - > addAction ( action ) ;
connect ( action , & QAction : : triggered , this , & This : : onChronoTextPosChanged ) ;
action = new QAction ( " Chrono text at center " , actionGroup ) ;
action - > setToolTip ( " Draw duration of selected interval \n at the center of the screen. " ) ;
action - > setCheckable ( true ) ;
action - > setData ( static_cast < int > ( : : profiler_gui : : ChronoTextPosition_Center ) ) ;
if ( EASY_GLOBALS . chrono_text_position = = : : profiler_gui : : ChronoTextPosition_Center )
action - > setChecked ( true ) ;
submenu - > addAction ( action ) ;
connect ( action , & QAction : : triggered , this , & This : : onChronoTextPosChanged ) ;
action = new QAction ( " Chrono text at bottom " , actionGroup ) ;
action - > setToolTip ( " Draw duration of selected interval \n at the bottom of the screen. " ) ;
action - > setCheckable ( true ) ;
action - > setData ( static_cast < int > ( : : profiler_gui : : ChronoTextPosition_Bottom ) ) ;
if ( EASY_GLOBALS . chrono_text_position = = : : profiler_gui : : ChronoTextPosition_Bottom )
action - > setChecked ( true ) ;
submenu - > addAction ( action ) ;
connect ( action , & QAction : : triggered , this , & This : : onChronoTextPosChanged ) ;
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 ) ;
2017-11-16 22:32:28 +03:00
spinbox - > setFixedWidth ( 70 ) ;
2017-02-08 00:14:49 +03:00
connect ( spinbox , SIGNAL ( valueChanged ( int ) ) , this , SLOT ( onSpacingChange ( int ) ) ) ;
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 ) ;
2017-11-16 22:32:28 +03:00
spinbox - > setFixedWidth ( 70 ) ;
2017-02-08 00:14:49 +03:00
connect ( spinbox , SIGNAL ( valueChanged ( int ) ) , this , SLOT ( onMinSizeChange ( int ) ) ) ;
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 ) ;
2017-11-16 22:32:28 +03:00
spinbox - > setFixedWidth ( 70 ) ;
2017-02-08 00:14:49 +03:00
connect ( spinbox , SIGNAL ( valueChanged ( int ) ) , this , SLOT ( onNarrowSizeChange ( int ) ) ) ;
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 ) ;
2017-11-16 22:32:28 +03:00
spinbox - > setFixedWidth ( 70 ) ;
2017-04-03 23:16:36 +03:00
connect ( spinbox , SIGNAL ( valueChanged ( int ) ) , this , SLOT ( onFpsIntervalChange ( int ) ) ) ;
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 ) ;
2017-11-16 22:32:28 +03:00
spinbox - > setFixedWidth ( 70 ) ;
2017-04-03 23:16:36 +03:00
connect ( spinbox , SIGNAL ( valueChanged ( int ) ) , this , SLOT ( onFpsHistoryChange ( int ) ) ) ;
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 ) ;
2017-11-16 22:32:28 +03:00
spinbox - > setFixedWidth ( 70 ) ;
2017-04-05 22:37:40 +03:00
connect ( spinbox , SIGNAL ( valueChanged ( int ) ) , this , SLOT ( onFpsMonitorLineWidthChange ( int ) ) ) ;
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 ) ;
action - > setData ( static_cast < int > ( : : profiler_gui : : TimeUnits_auto ) ) ;
if ( EASY_GLOBALS . time_units = = : : profiler_gui : : TimeUnits_auto )
action - > setChecked ( true ) ;
submenu - > addAction ( action ) ;
connect ( action , & QAction : : triggered , this , & This : : onUnitsChanged ) ;
action = new QAction ( " Milliseconds " , actionGroup ) ;
action - > setCheckable ( true ) ;
action - > setData ( static_cast < int > ( : : profiler_gui : : TimeUnits_ms ) ) ;
if ( EASY_GLOBALS . time_units = = : : profiler_gui : : TimeUnits_ms )
action - > setChecked ( true ) ;
submenu - > addAction ( action ) ;
connect ( action , & QAction : : triggered , this , & This : : onUnitsChanged ) ;
action = new QAction ( " Microseconds " , actionGroup ) ;
action - > setCheckable ( true ) ;
action - > setData ( static_cast < int > ( : : profiler_gui : : TimeUnits_us ) ) ;
if ( EASY_GLOBALS . time_units = = : : profiler_gui : : TimeUnits_us )
action - > setChecked ( true ) ;
submenu - > addAction ( action ) ;
connect ( action , & QAction : : triggered , this , & This : : onUnitsChanged ) ;
action = new QAction ( " Nanoseconds " , actionGroup ) ;
action - > setCheckable ( true ) ;
action - > setData ( static_cast < int > ( : : profiler_gui : : TimeUnits_ns ) ) ;
if ( EASY_GLOBALS . time_units = = : : profiler_gui : : TimeUnits_ns )
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 ( ) ;
foreach ( int mib , QTextCodec : : availableMibs ( ) )
{
auto codec = QTextCodec : : codecForMib ( mib ) - > name ( ) ;
action = new QAction ( codec , actionGroup ) ;
action - > setCheckable ( true ) ;
if ( mib = = default_codec_mib )
action - > setChecked ( true ) ;
submenu - > addAction ( action ) ;
connect ( action , & QAction : : triggered , this , & This : : onEncodingChanged ) ;
}
auto tb_height = toolbar - > height ( ) + 4 ;
toolbar = addToolBar ( " FrameToolbar " ) ;
toolbar - > setIconSize ( : : profiler_gui : : ICONS_SIZE ) ;
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 ( ) ;
m_frameTimeEdit - > setFixedWidth ( 70 ) ;
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 ) ;
2017-03-13 20:30:57 +03:00
connect ( & EASY_GLOBALS . events , & : : profiler_gui : : EasyGlobalSignals : : 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 ) ;
connect ( graphicsView - > view ( ) , & EasyGraphicsView : : intervalChanged , treeWidget - > tree ( ) , & EasyTreeWidget : : setTreeBlocks ) ;
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
m_progress = new QProgressDialog ( " Loading file... " , " Cancel " , 0 , 100 , this ) ;
m_progress - > setFixedWidth ( 300 ) ;
2017-05-02 23:21:15 +03:00
m_progress - > setWindowTitle ( EASY_DEFAULT_WINDOW_TITLE ) ;
2017-02-08 00:14:49 +03:00
m_progress - > setModal ( true ) ;
m_progress - > setValue ( 100 ) ;
//m_progress->hide();
connect ( m_progress , & QProgressDialog : : canceled , this , & This : : onFileReaderCancel ) ;
loadGeometry ( ) ;
if ( QCoreApplication : : arguments ( ) . size ( ) > 1 )
{
auto opened_filename = QCoreApplication : : arguments ( ) . at ( 1 ) ;
loadFile ( opened_filename ) ;
}
connect ( & EASY_GLOBALS . events , & : : profiler_gui : : EasyGlobalSignals : : blockStatusChanged , this , & This : : onBlockStatusChange ) ;
connect ( & EASY_GLOBALS . events , & : : profiler_gui : : EasyGlobalSignals : : blocksRefreshRequired , this , & This : : onGetBlockDescriptionsClicked ) ;
}
EasyMainWindow : : ~ EasyMainWindow ( )
{
delete m_progress ;
}
//////////////////////////////////////////////////////////////////////////
void EasyMainWindow : : dragEnterEvent ( QDragEnterEvent * drag_event )
{
if ( drag_event - > mimeData ( ) - > hasUrls ( ) )
drag_event - > acceptProposedAction ( ) ;
}
void EasyMainWindow : : dragMoveEvent ( QDragMoveEvent * drag_event )
{
if ( drag_event - > mimeData ( ) - > hasUrls ( ) )
drag_event - > acceptProposedAction ( ) ;
}
void EasyMainWindow : : dragLeaveEvent ( QDragLeaveEvent * drag_event )
{
drag_event - > accept ( ) ;
}
void EasyMainWindow : : dropEvent ( QDropEvent * drop_event )
{
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
auto result = QMessageBox : : question ( this , " Unsaved session " , " You have unsaved data! \n Save before opening new file? " , QMessageBox : : Yes , QMessageBox : : No , QMessageBox : : Cancel ) ;
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
}
//////////////////////////////////////////////////////////////////////////
void EasyMainWindow : : onOpenFileClicked ( bool )
{
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
auto result = QMessageBox : : question ( this , " Unsaved session " , " You have unsaved data! \n Save before opening new file? " , QMessageBox : : Yes , QMessageBox : : No , QMessageBox : : Cancel ) ;
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
}
}
//////////////////////////////////////////////////////////////////////////
void EasyMainWindow : : addFileToList ( const QString & filename )
{
m_lastFiles . push_front ( filename ) ;
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 ) ;
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
}
void EasyMainWindow : : loadFile ( const QString & filename )
{
const auto i = filename . lastIndexOf ( QChar ( ' / ' ) ) ;
const auto j = filename . lastIndexOf ( QChar ( ' \\ ' ) ) ;
m_progress - > setLabelText ( QString ( " Loading %1... " ) . arg ( filename . mid ( : : std : : max ( i , j ) + 1 ) ) ) ;
m_progress - > setValue ( 0 ) ;
m_progress - > show ( ) ;
m_readerTimer . start ( LOADER_TIMER_INTERVAL ) ;
m_reader . load ( filename ) ;
}
void EasyMainWindow : : readStream ( : : std : : stringstream & data )
{
m_progress - > setLabelText ( tr ( " Reading from stream... " ) ) ;
m_progress - > setValue ( 0 ) ;
m_progress - > show ( ) ;
m_readerTimer . start ( LOADER_TIMER_INTERVAL ) ;
m_reader . load ( data ) ;
}
//////////////////////////////////////////////////////////////////////////
void EasyMainWindow : : onSaveFileClicked ( bool )
{
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 ( ' \\ ' ) ) ;
auto k = : : std : : max ( i , j ) ;
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!
2017-07-19 00:30:34 +08:00
QMessageBox : : 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 ;
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 (*.*) " ) ;
2017-02-08 00:14:49 +03:00
if ( ! filename . isEmpty ( ) )
{
2017-05-02 23:21:15 +03:00
// 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 )
{
// Selected the same file - do nothing
return ;
}
}
2017-02-08 00:14:49 +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 ( ) )
{
: : std : : this_thread : : sleep_for ( : : std : : chrono : : milliseconds ( 500 ) ) ;
continue ;
}
inOk = true ;
int8_t retry2 = - 1 ;
while ( + + retry2 < 4 )
{
: : std : : ofstream outFile ( filename . toStdString ( ) , : : std : : fstream : : binary ) ;
if ( ! outFile . is_open ( ) )
{
: : std : : this_thread : : sleep_for ( : : std : : chrono : : milliseconds ( 500 ) ) ;
continue ;
}
outFile < < inFile . rdbuf ( ) ;
outOk = true ;
break ;
}
break ;
}
if ( outOk )
{
if ( m_bNetworkFileRegime )
2017-05-02 23:21:15 +03:00
{
// Remove temporary network cahche file
2017-02-08 00:14:49 +03:00
QFile : : remove ( QString ( NETWORK_CACHE_FILE ) ) ;
2017-05-02 23:21:15 +03:00
}
else if ( m_bOpenedCacheFile )
{
// Remove old temporary network cahche file
QFile : : remove ( lastFile . toStdString ( ) . c_str ( ) ) ;
m_lastFiles . pop_front ( ) ;
auto action = m_loadActionMenu - > actions ( ) . front ( ) ;
m_loadActionMenu - > removeAction ( action ) ;
delete action ;
}
2017-02-08 00:14:49 +03:00
addFileToList ( filename ) ;
2017-05-02 23:21:15 +03:00
2017-02-08 00:14:49 +03:00
m_bNetworkFileRegime = false ;
}
else if ( inOk )
{
2017-07-19 00:30:34 +08:00
QMessageBox : : warning ( this , " Warning " , " Cannot open destination file. \n Saving incomplete. " , QMessageBox : : Close ) ;
2017-02-08 00:14:49 +03:00
}
else
{
if ( m_bNetworkFileRegime )
2017-07-19 00:30:34 +08:00
QMessageBox : : warning ( this , " Warning " , " Cannot open network cache file. \n Saving incomplete. " , QMessageBox : : Close ) ;
2017-02-08 00:14:49 +03:00
else
2017-07-19 00:30:34 +08:00
QMessageBox : : warning ( this , " Warning " , " Cannot open source file. \n Saving incomplete. " , QMessageBox : : Close ) ;
2017-02-08 00:14:49 +03:00
}
}
}
//////////////////////////////////////////////////////////////////////////
void EasyMainWindow : : clear ( )
{
static_cast < EasyHierarchyWidget * > ( m_treeWidget - > widget ( ) ) - > clear ( true ) ;
static_cast < EasyGraphicsViewWidget * > ( m_graphicsView - > widget ( ) ) - > clear ( ) ;
# if EASY_GUI_USE_DESCRIPTORS_DOCK_WINDOW != 0
static_cast < EasyDescWidget * > ( m_descTreeWidget - > widget ( ) ) - > clear ( ) ;
# endif
if ( m_dialogDescTree ! = nullptr )
m_dialogDescTree - > clear ( ) ;
EASY_GLOBALS . selected_thread = 0 ;
: : profiler_gui : : set_max ( EASY_GLOBALS . selected_block ) ;
: : profiler_gui : : set_max ( EASY_GLOBALS . selected_block_id ) ;
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
}
//////////////////////////////////////////////////////////////////////////
void EasyMainWindow : : refreshDiagram ( )
{
static_cast < EasyGraphicsViewWidget * > ( m_graphicsView - > widget ( ) ) - > view ( ) - > scene ( ) - > update ( ) ;
}
//////////////////////////////////////////////////////////////////////////
void EasyMainWindow : : onDeleteClicked ( bool )
{
2017-05-02 23:21:15 +03:00
int button = QMessageBox : : Yes ;
2017-04-05 22:37:40 +03:00
if ( m_bNetworkFileRegime )
button = QMessageBox : : 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-02-08 00:14:49 +03:00
if ( button = = QMessageBox : : Yes )
clear ( ) ;
}
//////////////////////////////////////////////////////////////////////////
void EasyMainWindow : : onExitClicked ( bool )
{
close ( ) ;
}
//////////////////////////////////////////////////////////////////////////
void EasyMainWindow : : onEncodingChanged ( bool )
{
auto _sender = qobject_cast < QAction * > ( sender ( ) ) ;
auto name = _sender - > text ( ) ;
QTextCodec * codec = QTextCodec : : codecForName ( name . toStdString ( ) . c_str ( ) ) ;
QTextCodec : : setCodecForLocale ( codec ) ;
}
void EasyMainWindow : : onChronoTextPosChanged ( bool )
{
auto _sender = qobject_cast < QAction * > ( sender ( ) ) ;
EASY_GLOBALS . chrono_text_position = static_cast < : : profiler_gui : : ChronometerTextPosition > ( _sender - > data ( ) . toInt ( ) ) ;
refreshDiagram ( ) ;
}
void EasyMainWindow : : onUnitsChanged ( bool )
{
auto _sender = qobject_cast < QAction * > ( sender ( ) ) ;
EASY_GLOBALS . time_units = static_cast < : : profiler_gui : : TimeUnits > ( _sender - > data ( ) . toInt ( ) ) ;
}
void EasyMainWindow : : onEnableDisableStatistics ( bool _checked )
{
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-20 23:34:45 +03:00
action - > setIcon ( QIcon ( " :/images/stats " ) ) ;
2017-02-08 00:14:49 +03:00
}
else
{
action - > setText ( " Statistics disabled " ) ;
2017-11-20 23:34:45 +03:00
action - > setIcon ( QIcon ( " :/images/stats-off " ) ) ;
2017-02-08 00:14:49 +03:00
}
}
}
void EasyMainWindow : : onCollapseItemsAfterCloseChanged ( bool _checked )
{
EASY_GLOBALS . collapse_items_on_tree_close = _checked ;
}
void EasyMainWindow : : onAllItemsExpandedByDefaultChange ( bool _checked )
{
EASY_GLOBALS . all_items_expanded_by_default = _checked ;
}
void EasyMainWindow : : onBindExpandStatusChange ( bool _checked )
{
EASY_GLOBALS . bind_scene_and_tree_expand_status = _checked ;
}
void EasyMainWindow : : onHierarchyFlagChange ( bool _checked )
{
EASY_GLOBALS . only_current_thread_hierarchy = _checked ;
emit EASY_GLOBALS . events . hierarchyFlagChanged ( _checked ) ;
}
//////////////////////////////////////////////////////////////////////////
void EasyMainWindow : : onExpandAllClicked ( bool )
{
for ( auto & block : EASY_GLOBALS . gui_blocks )
block . expanded = true ;
emit EASY_GLOBALS . events . itemsExpandStateChanged ( ) ;
auto tree = static_cast < EasyHierarchyWidget * > ( m_treeWidget - > widget ( ) ) - > tree ( ) ;
const QSignalBlocker b ( tree ) ;
tree - > expandAll ( ) ;
}
void EasyMainWindow : : onCollapseAllClicked ( bool )
{
for ( auto & block : EASY_GLOBALS . gui_blocks )
block . expanded = false ;
emit EASY_GLOBALS . events . itemsExpandStateChanged ( ) ;
auto tree = static_cast < EasyHierarchyWidget * > ( m_treeWidget - > widget ( ) ) - > tree ( ) ;
const QSignalBlocker b ( tree ) ;
tree - > collapseAll ( ) ;
}
//////////////////////////////////////////////////////////////////////////
void EasyMainWindow : : onSpacingChange ( int _value )
{
EASY_GLOBALS . blocks_spacing = _value ;
refreshDiagram ( ) ;
}
void EasyMainWindow : : onMinSizeChange ( int _value )
{
EASY_GLOBALS . blocks_size_min = _value ;
refreshDiagram ( ) ;
}
void EasyMainWindow : : onNarrowSizeChange ( int _value )
{
EASY_GLOBALS . blocks_narrow_size = _value ;
refreshDiagram ( ) ;
}
//////////////////////////////////////////////////////////////////////////
2017-04-03 23:16:36 +03:00
void EasyMainWindow : : onFpsIntervalChange ( int _value )
{
EASY_GLOBALS . fps_timer_interval = _value ;
if ( m_fpsRequestTimer . isActive ( ) )
m_fpsRequestTimer . stop ( ) ;
if ( EASY_GLOBALS . connected )
m_fpsRequestTimer . start ( _value ) ;
}
void EasyMainWindow : : onFpsHistoryChange ( int _value )
{
EASY_GLOBALS . max_fps_history = _value ;
}
2017-04-05 22:37:40 +03:00
void EasyMainWindow : : onFpsMonitorLineWidthChange ( int _value )
{
EASY_GLOBALS . fps_widget_line_width = _value ;
}
2017-04-03 23:16:36 +03:00
//////////////////////////////////////////////////////////////////////////
2017-02-08 00:14:49 +03:00
void EasyMainWindow : : onEditBlocksClicked ( bool )
{
if ( m_descTreeDialog ! = nullptr )
{
m_descTreeDialog - > raise ( ) ;
return ;
}
m_descTreeDialog = new QDialog ( ) ;
m_descTreeDialog - > setAttribute ( Qt : : WA_DeleteOnClose , true ) ;
2017-05-02 23:21:15 +03:00
m_descTreeDialog - > setWindowTitle ( EASY_DEFAULT_WINDOW_TITLE ) ;
2017-02-08 00:14:49 +03:00
m_descTreeDialog - > resize ( 800 , 600 ) ;
connect ( m_descTreeDialog , & QDialog : : finished , this , & This : : onDescTreeDialogClose ) ;
auto l = new QVBoxLayout ( m_descTreeDialog ) ;
m_dialogDescTree = new EasyDescWidget ( m_descTreeDialog ) ;
l - > addWidget ( m_dialogDescTree ) ;
m_descTreeDialog - > setLayout ( l ) ;
m_dialogDescTree - > build ( ) ;
m_descTreeDialog - > show ( ) ;
}
void EasyMainWindow : : onDescTreeDialogClose ( int )
{
disconnect ( m_descTreeDialog , & QDialog : : finished , this , & This : : onDescTreeDialogClose ) ;
m_dialogDescTree = nullptr ;
m_descTreeDialog = nullptr ;
}
//////////////////////////////////////////////////////////////////////////
void EasyMainWindow : : closeEvent ( QCloseEvent * close_event )
{
2017-05-02 23:21:15 +03:00
if ( m_bNetworkFileRegime )
{
// Warn user about unsaved network information and suggest to save
2017-08-16 08:04:24 +08:00
if ( QMessageBox : : Yes = = QMessageBox : : question ( this , " Unsaved session " , " You have unsaved data! \n Save before exit? " , QMessageBox : : Yes , QMessageBox : : No ) )
2017-05-02 23:21:15 +03:00
{
onSaveFileClicked ( true ) ;
}
}
2017-02-08 00:14:49 +03:00
saveSettingsAndGeometry ( ) ;
if ( m_descTreeDialog ! = nullptr )
{
m_descTreeDialog - > reject ( ) ;
m_descTreeDialog = nullptr ;
m_dialogDescTree = nullptr ;
}
Parent : : closeEvent ( close_event ) ;
}
//////////////////////////////////////////////////////////////////////////
void EasyMainWindow : : loadSettings ( )
{
QSettings settings ( : : profiler_gui : : ORGANAZATION_NAME , : : profiler_gui : : APPLICATION_NAME ) ;
settings . beginGroup ( " main " ) ;
auto last_files = settings . value ( " last_files " ) ;
if ( ! last_files . isNull ( ) )
m_lastFiles = last_files . toStringList ( ) ;
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 ( ) )
EASY_GLOBALS . chrono_text_position = static_cast < : : profiler_gui : : ChronometerTextPosition > ( val . toInt ( ) ) ;
val = settings . value ( " time_units " ) ;
if ( ! val . isNull ( ) )
EASY_GLOBALS . time_units = static_cast < : : profiler_gui : : TimeUnits > ( val . toInt ( ) ) ;
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 ( ) ;
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
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 ) ;
settings . endGroup ( ) ;
}
void EasyMainWindow : : loadGeometry ( )
{
QSettings settings ( : : profiler_gui : : ORGANAZATION_NAME , : : profiler_gui : : APPLICATION_NAME ) ;
settings . beginGroup ( " main " ) ;
auto geometry = settings . value ( " geometry " ) . toByteArray ( ) ;
if ( ! geometry . isEmpty ( ) )
restoreGeometry ( geometry ) ;
auto state = settings . value ( " windowState " ) . toByteArray ( ) ;
if ( ! state . isEmpty ( ) )
restoreState ( state ) ;
settings . endGroup ( ) ;
}
void EasyMainWindow : : saveSettingsAndGeometry ( )
{
QSettings settings ( : : profiler_gui : : ORGANAZATION_NAME , : : profiler_gui : : APPLICATION_NAME ) ;
settings . beginGroup ( " main " ) ;
settings . setValue ( " geometry " , this - > saveGeometry ( ) ) ;
settings . setValue ( " windowState " , this - > saveState ( ) ) ;
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 ) ;
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 ) ;
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 ) ;
2017-02-08 00:14:49 +03:00
settings . setValue ( " encoding " , QTextCodec : : codecForLocale ( ) - > name ( ) ) ;
settings . endGroup ( ) ;
}
void EasyMainWindow : : setDisconnected ( bool _showMessage )
{
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 )
2017-07-19 00:30:34 +08:00
QMessageBox : : 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-20 23:34:45 +03:00
m_connectAction - > setIcon ( QIcon ( " :/images/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 ) ;
}
//////////////////////////////////////////////////////////////////////////
2017-04-03 23:16:36 +03:00
void EasyMainWindow : : onFrameTimeRequestTimeout ( )
{
2017-04-03 23:28:19 +03:00
if ( EASY_GLOBALS . fps_enabled & & EASY_GLOBALS . connected & & ( m_listener . regime ( ) = = LISTENER_IDLE | | m_listener . regime ( ) = = LISTENER_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
}
}
void EasyMainWindow : : checkFrameTimeReady ( )
{
2017-04-03 23:28:19 +03:00
if ( EASY_GLOBALS . fps_enabled & & EASY_GLOBALS . connected & & ( m_listener . regime ( ) = = LISTENER_IDLE | | m_listener . regime ( ) = = LISTENER_CAPTURE ) )
2017-04-03 23:16:36 +03:00
{
uint32_t maxTime = 0 , avgTime = 0 ;
if ( m_listener . frameTime ( maxTime , avgTime ) )
{
static_cast < EasyFrameRateViewer * > ( m_fpsViewer - > widget ( ) ) - > addPoint ( maxTime , avgTime ) ;
}
else if ( m_fpsRequestTimer . isActive ( ) )
{
QTimer : : singleShot ( 100 , this , & This : : checkFrameTimeReady ) ;
}
}
}
//////////////////////////////////////////////////////////////////////////
2017-02-08 00:14:49 +03:00
void EasyMainWindow : : onListenerTimerTimeout ( )
{
if ( ! m_listener . connected ( ) )
2017-04-03 23:28:19 +03:00
{
if ( m_listener . regime ( ) = = LISTENER_CAPTURE_RECEIVE )
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
}
else if ( m_listener . regime ( ) = = LISTENER_CAPTURE_RECEIVE )
{
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
}
2017-04-05 22:37:40 +03:00
void EasyMainWindow : : onListenerDialogClose ( int _result )
2017-02-08 00:14:49 +03:00
{
2017-04-03 23:28:19 +03:00
if ( m_listener . regime ( ) ! = LISTENER_CAPTURE_RECEIVE | | ! m_listener . connected ( ) )
{
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 ( ) )
{
case LISTENER_CAPTURE :
{
2017-04-05 22:37:40 +03:00
m_listenerDialog = new QMessageBox ( QMessageBox : : Information , " Receiving data... " , " This process may take some time. " , QMessageBox : : Cancel , this ) ;
2017-02-08 00:14:49 +03:00
m_listenerDialog - > setAttribute ( Qt : : WA_DeleteOnClose , true ) ;
m_listenerDialog - > show ( ) ;
m_listener . stopCapture ( ) ;
2017-04-03 23:28:19 +03:00
if ( m_listener . regime ( ) ! = LISTENER_CAPTURE_RECEIVE )
{
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 ;
}
case LISTENER_CAPTURE_RECEIVE :
{
if ( ! m_listener . captured ( ) )
{
2017-04-05 22:37:40 +03:00
if ( _result = = QDialog : : Accepted )
{
m_listenerDialog = new QMessageBox ( QMessageBox : : Information , " Receiving data... " , " This process may take some time. " , QMessageBox : : Cancel , this ) ;
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 ;
}
case LISTENER_DESCRIBE :
{
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 ( ) ;
}
}
//////////////////////////////////////////////////////////////////////////
void EasyMainWindow : : onFileReaderTimeout ( )
{
if ( m_reader . done ( ) )
{
auto nblocks = m_reader . size ( ) ;
if ( nblocks ! = 0 )
{
static_cast < EasyHierarchyWidget * > ( m_treeWidget - > widget ( ) ) - > clear ( true ) ;
: : profiler : : SerializedData serialized_blocks ;
: : profiler : : SerializedData serialized_descriptors ;
: : profiler : : descriptors_list_t descriptors ;
: : profiler : : blocks_t blocks ;
: : profiler : : thread_blocks_tree_t threads_map ;
QString filename ;
uint32_t descriptorsNumberInFile = 0 ;
2017-06-06 20:46:06 +03:00
uint32_t version = 0 ;
m_reader . get ( serialized_blocks , serialized_descriptors , descriptors , blocks , threads_map , descriptorsNumberInFile , version , filename ) ;
2017-02-08 00:14:49 +03:00
if ( threads_map . size ( ) > 0xff )
{
if ( m_reader . isFile ( ) )
qWarning ( ) < < " Warning: file " < < filename < < " contains " < < threads_map . size ( ) < < " threads! " ;
else
qWarning ( ) < < " Warning: input stream contains " < < threads_map . size ( ) < < " threads! " ;
qWarning ( ) < < " Warning: Currently, maximum number of displayed threads is 255! Some threads will not be displayed. " ;
}
m_bNetworkFileRegime = ! m_reader . isFile ( ) ;
if ( ! m_bNetworkFileRegime )
{
auto index = m_lastFiles . indexOf ( filename , 0 ) ;
if ( index = = - 1 )
{
// This file is totally new. Add it to the list.
addFileToList ( filename ) ;
}
2017-05-02 23:21:15 +03:00
else
2017-02-08 00:14:49 +03:00
{
2017-05-02 23:21:15 +03:00
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 ) ;
}
m_bOpenedCacheFile = filename . contains ( NETWORK_CACHE_FILE ) ;
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 ) ) ;
2017-02-08 00:14:49 +03:00
}
}
2017-05-02 23:21:15 +03:00
else
{
m_bOpenedCacheFile = false ;
setWindowTitle ( EASY_DEFAULT_WINDOW_TITLE " - UNSAVED network cache " ) ;
}
2017-02-08 00:14:49 +03:00
m_serializedBlocks = : : std : : move ( serialized_blocks ) ;
m_serializedDescriptors = : : std : : move ( serialized_descriptors ) ;
m_descriptorsNumberInFile = descriptorsNumberInFile ;
EASY_GLOBALS . selected_thread = 0 ;
2017-06-06 20:46:06 +03:00
EASY_GLOBALS . version = version ;
2017-02-08 00:14:49 +03:00
: : 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 ) ;
EASY_GLOBALS . gui_blocks . clear ( ) ;
EASY_GLOBALS . gui_blocks . resize ( nblocks ) ;
memset ( EASY_GLOBALS . gui_blocks . data ( ) , 0 , sizeof ( : : profiler_gui : : EasyBlock ) * nblocks ) ;
for ( decltype ( nblocks ) i = 0 ; i < nblocks ; + + i ) {
auto & guiblock = EASY_GLOBALS . gui_blocks [ i ] ;
guiblock . tree = : : std : : move ( blocks [ i ] ) ;
# ifdef EASY_TREE_WIDGET__USE_VECTOR
: : profiler_gui : : set_max ( guiblock . tree_item ) ;
# endif
}
static_cast < EasyGraphicsViewWidget * > ( m_graphicsView - > widget ( ) ) - > view ( ) - > setTree ( EASY_GLOBALS . profiler_blocks ) ;
# if EASY_GUI_USE_DESCRIPTORS_DOCK_WINDOW != 0
static_cast < EasyDescWidget * > ( m_descTreeWidget - > widget ( ) ) - > build ( ) ;
# endif
if ( m_dialogDescTree ! = nullptr )
m_dialogDescTree - > build ( ) ;
m_saveAction - > setEnabled ( true ) ;
m_deleteAction - > setEnabled ( true ) ;
}
else
{
2017-07-19 00:30:34 +08:00
QMessageBox : : warning ( this , " Warning " , QString ( " Cannot read profiled blocks. \n \n Reason: \n %1 " ) . arg ( m_reader . getError ( ) ) , QMessageBox : : Close ) ;
2017-02-08 00:14:49 +03:00
if ( m_reader . isFile ( ) )
{
auto index = m_lastFiles . indexOf ( m_reader . filename ( ) , 0 ) ;
if ( index > = 0 )
{
// Remove unexisting file from list
m_lastFiles . removeAt ( index ) ;
auto action = m_loadActionMenu - > actions ( ) . at ( index ) ;
m_loadActionMenu - > removeAction ( action ) ;
delete action ;
}
}
}
m_reader . interrupt ( ) ;
m_readerTimer . stop ( ) ;
m_progress - > setValue ( 100 ) ;
//m_progress->hide();
if ( EASY_GLOBALS . all_items_expanded_by_default )
{
onExpandAllClicked ( true ) ;
}
}
else
{
m_progress - > setValue ( m_reader . progress ( ) ) ;
}
}
void EasyMainWindow : : onFileReaderCancel ( )
{
m_readerTimer . stop ( ) ;
m_reader . interrupt ( ) ;
m_progress - > setValue ( 100 ) ;
//m_progress->hide();
}
//////////////////////////////////////////////////////////////////////////
EasyFileReader : : EasyFileReader ( )
{
}
EasyFileReader : : ~ EasyFileReader ( )
{
interrupt ( ) ;
}
const bool EasyFileReader : : isFile ( ) const
{
return m_isFile ;
}
bool EasyFileReader : : done ( ) const
{
return m_bDone . load ( : : std : : memory_order_acquire ) ;
}
int EasyFileReader : : progress ( ) const
{
return m_progress . load ( : : std : : memory_order_acquire ) ;
}
unsigned int EasyFileReader : : size ( ) const
{
return m_size . load ( : : std : : memory_order_acquire ) ;
}
const QString & EasyFileReader : : filename ( ) const
{
return m_filename ;
}
void EasyFileReader : : load ( const QString & _filename )
{
interrupt ( ) ;
m_isFile = true ;
m_filename = _filename ;
m_thread = : : std : : thread ( [ this ] ( bool _enableStatistics ) {
m_size . store ( fillTreesFromFile ( m_progress , m_filename . toStdString ( ) . c_str ( ) , m_serializedBlocks , m_serializedDescriptors ,
2017-06-06 20:46:06 +03:00
m_descriptors , m_blocks , m_blocksTree , m_descriptorsNumberInFile , m_version , _enableStatistics , m_errorMessage ) , : : std : : memory_order_release ) ;
2017-02-08 00:14:49 +03:00
m_progress . store ( 100 , : : std : : memory_order_release ) ;
m_bDone . store ( true , : : std : : memory_order_release ) ;
} , EASY_GLOBALS . enable_statistics ) ;
}
void EasyFileReader : : load ( : : std : : stringstream & _stream )
{
interrupt ( ) ;
m_isFile = false ;
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
m_thread = : : std : : thread ( [ this ] ( bool _enableStatistics ) {
: : std : : ofstream cache_file ( NETWORK_CACHE_FILE , : : std : : fstream : : binary ) ;
if ( cache_file . is_open ( ) ) {
cache_file < < m_stream . str ( ) ;
cache_file . close ( ) ;
}
m_size . store ( fillTreesFromStream ( m_progress , m_stream , m_serializedBlocks , m_serializedDescriptors , m_descriptors ,
2017-06-06 20:46:06 +03:00
m_blocks , m_blocksTree , m_descriptorsNumberInFile , m_version , _enableStatistics , m_errorMessage ) , : : std : : memory_order_release ) ;
2017-02-08 00:14:49 +03:00
m_progress . store ( 100 , : : std : : memory_order_release ) ;
m_bDone . store ( true , : : std : : memory_order_release ) ;
} , EASY_GLOBALS . enable_statistics ) ;
}
void EasyFileReader : : interrupt ( )
{
m_progress . store ( - 100 , : : std : : memory_order_release ) ;
if ( m_thread . joinable ( ) )
m_thread . join ( ) ;
m_bDone . store ( false , : : std : : memory_order_release ) ;
m_progress . store ( 0 , : : std : : memory_order_release ) ;
m_size . store ( 0 , : : std : : memory_order_release ) ;
m_serializedBlocks . clear ( ) ;
m_serializedDescriptors . clear ( ) ;
m_descriptors . clear ( ) ;
m_blocks . clear ( ) ;
m_blocksTree . clear ( ) ;
m_descriptorsNumberInFile = 0 ;
2017-06-06 20:46:06 +03:00
m_version = 0 ;
2017-02-08 00:14:49 +03:00
clear_stream ( m_stream ) ;
clear_stream ( m_errorMessage ) ;
}
void EasyFileReader : : get ( : : profiler : : SerializedData & _serializedBlocks , : : profiler : : SerializedData & _serializedDescriptors ,
: : profiler : : descriptors_list_t & _descriptors , : : profiler : : blocks_t & _blocks ,
2017-06-06 20:46:06 +03:00
: : profiler : : thread_blocks_tree_t & _tree , uint32_t & _descriptorsNumberInFile , uint32_t & _version , QString & _filename )
2017-02-08 00:14:49 +03:00
{
if ( done ( ) )
{
m_serializedBlocks . swap ( _serializedBlocks ) ;
m_serializedDescriptors . swap ( _serializedDescriptors ) ;
: : profiler : : descriptors_list_t ( : : std : : move ( m_descriptors ) ) . swap ( _descriptors ) ;
m_blocks . swap ( _blocks ) ;
m_blocksTree . swap ( _tree ) ;
m_filename . swap ( _filename ) ;
_descriptorsNumberInFile = m_descriptorsNumberInFile ;
2017-06-06 20:46:06 +03:00
_version = m_version ;
2017-02-08 00:14:49 +03:00
}
}
QString EasyFileReader : : getError ( )
{
return QString ( m_errorMessage . str ( ) . c_str ( ) ) ;
}
//////////////////////////////////////////////////////////////////////////
void EasyMainWindow : : onEventTracingPriorityChange ( bool _checked )
{
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
}
void EasyMainWindow : : onEventTracingEnableChange ( bool _checked )
{
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
}
//////////////////////////////////////////////////////////////////////////
void EasyMainWindow : : onFrameTimeEditFinish ( )
{
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
2017-11-09 23:12:54 +03:00
disconnect ( & EASY_GLOBALS . events , & : : profiler_gui : : EasyGlobalSignals : : expectedFrameTimeChanged ,
this , & This : : onFrameTimeChanged ) ;
2017-03-13 20:30:57 +03:00
emit EASY_GLOBALS . events . expectedFrameTimeChanged ( ) ;
2017-11-09 23:12:54 +03:00
connect ( & EASY_GLOBALS . events , & : : profiler_gui : : EasyGlobalSignals : : expectedFrameTimeChanged ,
this , & This : : onFrameTimeChanged ) ;
2017-03-07 01:09:27 +03:00
}
void EasyMainWindow : : onFrameTimeChanged ( )
{
m_frameTimeEdit - > setText ( QString : : number ( EASY_GLOBALS . frame_time * 1e-3 ) ) ;
2017-02-08 00:14:49 +03:00
}
//////////////////////////////////////////////////////////////////////////
void EasyMainWindow : : onConnectClicked ( bool )
{
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 ) )
{
2017-11-09 23:12:54 +03:00
QMessageBox : : warning ( this , " Warning " , QString ( " Cannot connect to %1 " ) . arg ( address ) , QMessageBox : : Close ) ;
if ( EASY_GLOBALS . connected )
2017-02-08 00:14:49 +03:00
{
2017-11-09 23:12:54 +03:00
m_listener . closeSocket ( ) ;
setDisconnected ( false ) ;
2017-02-08 00:14:49 +03:00
}
2017-11-09 23:12:54 +03:00
if ( ! isSameAddress )
{
m_lastAddress = : : std : : move ( address ) ;
m_lastPort = port ;
2017-02-08 00:14:49 +03:00
}
return ;
}
m_lastAddress = : : std : : move ( address ) ;
m_lastPort = port ;
qInfo ( ) < < " Connected successfully " ;
EASY_GLOBALS . connected = true ;
m_captureAction - > setEnabled ( true ) ;
2017-11-20 23:34:45 +03:00
m_connectAction - > setIcon ( QIcon ( " :/images/connected " ) ) ;
2017-04-17 22:13:22 +03:00
m_connectAction - > setText ( tr ( " Disconnect " ) ) ;
if ( m_fpsViewer - > isVisible ( ) )
static_cast < EasyFrameRateViewer * > ( 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
}
void EasyMainWindow : : onCaptureClicked ( bool )
{
if ( ! EASY_GLOBALS . connected )
{
QMessageBox : : warning ( this , " Warning " , " No connection with profiling app " , QMessageBox : : Close ) ;
return ;
}
if ( m_listener . regime ( ) ! = LISTENER_IDLE )
{
2017-04-03 23:28:19 +03:00
if ( m_listener . regime ( ) = = LISTENER_CAPTURE | | m_listener . regime ( ) = = LISTENER_CAPTURE_RECEIVE )
2017-02-08 00:14:49 +03:00
QMessageBox : : warning ( this , " Warning " , " Already capturing frames. \n Finish old capturing session first. " , QMessageBox : : Close ) ;
else
QMessageBox : : warning ( this , " Warning " , " Capturing blocks description. \n Finish old capturing session first. " , QMessageBox : : Close ) ;
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 ) ;
m_listenerDialog = new QMessageBox ( QMessageBox : : Information , " Capturing frames... " , " Close this dialog to stop capturing. " , QMessageBox : : NoButton , this ) ;
auto button = new QToolButton ( m_listenerDialog ) ;
button - > setAutoRaise ( true ) ;
button - > setToolButtonStyle ( Qt : : ToolButtonTextBesideIcon ) ;
button - > setIconSize ( : : profiler_gui : : ICONS_SIZE ) ;
2017-11-20 23:34:45 +03:00
button - > setIcon ( QIcon ( " :/images/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 ( ) ;
}
void EasyMainWindow : : onGetBlockDescriptionsClicked ( bool )
{
if ( ! EASY_GLOBALS . connected )
{
QMessageBox : : warning ( this , " Warning " , " No connection with profiling app " , QMessageBox : : Close ) ;
return ;
}
if ( m_listener . regime ( ) ! = LISTENER_IDLE )
{
if ( m_listener . regime ( ) = = LISTENER_DESCRIBE )
QMessageBox : : warning ( this , " Warning " , " Already capturing blocks description. \n Finish old capturing session first. " , QMessageBox : : Close ) ;
else
2017-07-19 00:30:34 +08:00
QMessageBox : : warning ( this , " Warning " , " Already capturing frames. \n Finish old capturing session first. " , QMessageBox : : Close ) ;
2017-02-08 00:14:49 +03:00
return ;
}
m_listenerDialog = new QMessageBox ( QMessageBox : : Information , " Waiting for blocks... " , " This may take some time. " , QMessageBox : : NoButton , this ) ;
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 ;
: : std : : stringstream errorMessage ;
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 ( ) )
{
auto button = QMessageBox : : question ( this , " Information " ,
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 ) ,
QMessageBox : : Yes , QMessageBox : : No ) ;
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
auto button = QMessageBox : : question ( this , " Information " ,
" There are errors while merging block descriptions lists. \n To avoid possible conflicts \n all profiled data will be deleted. \n Continue? " ,
QMessageBox : : Yes , QMessageBox : : No ) ;
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 ( ) ) ;
if ( m_descTreeDialog ! = nullptr )
{
# if EASY_GUI_USE_DESCRIPTORS_DOCK_WINDOW != 0
static_cast < EasyDescWidget * > ( m_descTreeWidget - > widget ( ) ) - > build ( ) ;
# endif
m_dialogDescTree - > build ( ) ;
m_descTreeDialog - > raise ( ) ;
}
else
{
onEditBlocksClicked ( true ) ;
}
}
}
}
else
{
2017-07-19 00:30:34 +08:00
QMessageBox : : 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 ( ) ;
}
}
//////////////////////////////////////////////////////////////////////////
void EasyMainWindow : : onBlockStatusChange ( : : profiler : : block_id_t _id , : : profiler : : EasyBlockStatus _status )
{
if ( EASY_GLOBALS . connected )
m_listener . send ( profiler : : net : : BlockStatusMessage ( _id , static_cast < uint8_t > ( _status ) ) ) ;
}
//////////////////////////////////////////////////////////////////////////
EasySocketListener : : EasySocketListener ( ) : m_receivedSize ( 0 ) , m_port ( 0 ) , m_regime ( LISTENER_IDLE )
{
m_bInterrupt = ATOMIC_VAR_INIT ( false ) ;
m_bConnected = ATOMIC_VAR_INIT ( false ) ;
m_bStopReceive = ATOMIC_VAR_INIT ( false ) ;
2017-04-03 23:16:36 +03:00
m_bFrameTimeReady = ATOMIC_VAR_INIT ( false ) ;
2017-04-03 23:28:19 +03:00
m_bCaptureReady = ATOMIC_VAR_INIT ( false ) ;
2017-04-03 23:16:36 +03:00
m_frameMax = ATOMIC_VAR_INIT ( 0 ) ;
m_frameAvg = ATOMIC_VAR_INIT ( 0 ) ;
2017-02-08 00:14:49 +03:00
}
EasySocketListener : : ~ EasySocketListener ( )
{
m_bInterrupt . store ( true , : : std : : memory_order_release ) ;
if ( m_thread . joinable ( ) )
m_thread . join ( ) ;
}
bool EasySocketListener : : connected ( ) const
{
return m_bConnected . load ( : : std : : memory_order_acquire ) ;
}
2017-04-03 23:28:19 +03:00
bool EasySocketListener : : captured ( ) const
{
return m_bCaptureReady . load ( : : std : : memory_order_acquire ) ;
}
2017-02-08 00:14:49 +03:00
EasyListenerRegime EasySocketListener : : regime ( ) const
{
return m_regime ;
}
uint64_t EasySocketListener : : size ( ) const
{
return m_receivedSize ;
}
: : std : : stringstream & EasySocketListener : : data ( )
{
return m_receivedData ;
}
2016-12-08 22:22:09 +03:00
const : : std : : string & EasySocketListener : : address ( ) const
{
return m_address ;
}
2017-02-08 00:14:49 +03:00
uint16_t EasySocketListener : : port ( ) const
{
return m_port ;
}
void EasySocketListener : : clearData ( )
{
clear_stream ( m_receivedData ) ;
m_receivedSize = 0 ;
}
2017-04-17 22:13:22 +03:00
void EasySocketListener : : disconnect ( )
{
if ( connected ( ) )
{
m_bInterrupt . store ( true , : : std : : memory_order_release ) ;
if ( m_thread . joinable ( ) )
m_thread . join ( ) ;
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 ) ;
}
m_address . clear ( ) ;
m_port = 0 ;
2017-10-04 22:37:46 +03:00
closeSocket ( ) ;
}
void EasySocketListener : : closeSocket ( )
{
2017-04-17 22:13:22 +03:00
m_easySocket . flush ( ) ;
m_easySocket . init ( ) ;
}
2017-10-04 22:37:46 +03:00
bool EasySocketListener : : connect ( const char * _ipaddress , uint16_t _port , profiler : : net : : EasyProfilerStatus & _reply , bool _disconnectFirst )
2017-02-08 00:14:49 +03:00
{
if ( connected ( ) )
{
m_bInterrupt . store ( true , : : std : : memory_order_release ) ;
if ( m_thread . joinable ( ) )
m_thread . join ( ) ;
m_bConnected . store ( false , : : std : : memory_order_release ) ;
m_bInterrupt . store ( false , : : std : : memory_order_release ) ;
2017-04-05 22:37:40 +03:00
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 ;
m_bConnected . store ( isConnected , : : std : : memory_order_release ) ;
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 ;
}
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 ;
}
m_bConnected . store ( isConnected , : : std : : memory_order_release ) ;
return isConnected ;
}
2017-10-04 22:37:46 +03:00
bool EasySocketListener : : reconnect ( const char * _ipaddress , uint16_t _port , : : profiler : : net : : EasyProfilerStatus & _reply )
{
return connect ( _ipaddress , _port , _reply , true ) ;
}
2017-02-08 00:14:49 +03:00
bool EasySocketListener : : startCapture ( )
{
2017-04-03 23:28:19 +03:00
//if (m_thread.joinable())
//{
// m_bInterrupt.store(true, ::std::memory_order_release);
// m_thread.join();
// 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_Start_Capture ) ;
2017-02-08 00:14:49 +03:00
m_easySocket . send ( & request , sizeof ( request ) ) ;
if ( m_easySocket . isDisconnected ( ) ) {
m_bConnected . store ( false , : : std : : memory_order_release ) ;
return false ;
}
m_regime = LISTENER_CAPTURE ;
2017-04-03 23:28:19 +03:00
m_bCaptureReady . store ( false , : : std : : memory_order_release ) ;
//m_thread = ::std::thread(&EasySocketListener::listenCapture, this);
2017-02-08 00:14:49 +03:00
return true ;
}
void EasySocketListener : : stopCapture ( )
{
2017-04-03 23:28:19 +03:00
//if (!m_thread.joinable() || m_regime != LISTENER_CAPTURE)
// return;
2017-02-08 00:14:49 +03:00
2017-04-03 23:28:19 +03:00
if ( m_regime ! = LISTENER_CAPTURE )
return ;
2017-02-08 00:14:49 +03:00
2017-04-03 23:28:19 +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 ( ) ) {
2017-02-08 00:14:49 +03:00
m_bConnected . store ( false , : : std : : memory_order_release ) ;
2017-04-03 23:28:19 +03:00
m_bStopReceive . store ( false , : : std : : memory_order_release ) ;
m_regime = LISTENER_IDLE ;
m_bCaptureReady . store ( true , : : std : : memory_order_release ) ;
return ;
}
m_regime = LISTENER_CAPTURE_RECEIVE ;
if ( m_thread . joinable ( ) )
{
m_bInterrupt . store ( true , : : std : : memory_order_release ) ;
m_thread . join ( ) ;
m_bInterrupt . store ( false , : : std : : memory_order_release ) ;
}
m_thread = : : std : : thread ( & EasySocketListener : : listenCapture , this ) ;
//m_regime = LISTENER_IDLE;
//m_bStopReceive.store(false, ::std::memory_order_release);
}
void EasySocketListener : : finalizeCapture ( )
{
if ( m_thread . joinable ( ) )
{
m_bInterrupt . store ( true , : : std : : memory_order_release ) ;
m_thread . join ( ) ;
m_bInterrupt . store ( false , : : std : : memory_order_release ) ;
}
2017-02-08 00:14:49 +03:00
m_regime = LISTENER_IDLE ;
2017-04-03 23:28:19 +03:00
m_bCaptureReady . store ( false , : : std : : memory_order_release ) ;
2017-02-08 00:14:49 +03:00
m_bStopReceive . store ( false , : : std : : memory_order_release ) ;
}
void EasySocketListener : : requestBlocksDescription ( )
{
2017-04-03 23:16:36 +03:00
if ( m_thread . joinable ( ) )
{
m_bInterrupt . store ( true , : : std : : memory_order_release ) ;
m_thread . join ( ) ;
m_bInterrupt . store ( false , : : std : : memory_order_release ) ;
}
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 ( ) ) {
m_bConnected . store ( false , : : std : : memory_order_release ) ;
}
m_regime = LISTENER_DESCRIBE ;
listenDescription ( ) ;
m_regime = LISTENER_IDLE ;
}
2017-04-03 23:16:36 +03:00
bool EasySocketListener : : frameTime ( uint32_t & _maxTime , uint32_t & _avgTime )
{
if ( m_bFrameTimeReady . exchange ( false , : : std : : memory_order_acquire ) )
{
_maxTime = m_frameMax . load ( : : std : : memory_order_acquire ) ;
_avgTime = m_frameAvg . load ( : : std : : memory_order_acquire ) ;
return true ;
}
return false ;
}
bool EasySocketListener : : requestFrameTime ( )
{
2017-04-03 23:28:19 +03:00
if ( m_regime ! = LISTENER_IDLE & & m_regime ! = LISTENER_CAPTURE )
2017-04-03 23:16:36 +03:00
return false ;
if ( m_thread . joinable ( ) )
{
m_bInterrupt . store ( true , : : std : : memory_order_release ) ;
m_thread . join ( ) ;
m_bInterrupt . store ( false , : : std : : memory_order_release ) ;
}
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 ( ) )
{
m_bConnected . store ( false , : : std : : memory_order_release ) ;
return false ;
}
m_bFrameTimeReady . store ( false , : : std : : memory_order_release ) ;
m_thread = : : std : : thread ( & EasySocketListener : : listenFrameTime , this ) ;
return true ;
}
2017-02-08 00:14:49 +03:00
//////////////////////////////////////////////////////////////////////////
void EasySocketListener : : listenCapture ( )
{
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 ;
auto timeBegin = : : std : : chrono : : system_clock : : now ( ) ;
bool isListen = true , disconnected = false ;
while ( isListen & & ! m_bInterrupt . load ( : : std : : memory_order_acquire ) )
{
if ( m_bStopReceive . load ( : : std : : memory_order_acquire ) )
{
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 ) ) ;
m_bStopReceive . store ( false , : : std : : memory_order_release ) ;
}
if ( ( bytes - seek ) = = 0 )
{
bytes = m_easySocket . receive ( buffer , buffer_size ) ;
if ( bytes = = - 1 )
{
if ( m_easySocket . isDisconnected ( ) )
{
m_bConnected . store ( false , : : std : : memory_order_release ) ;
isListen = false ;
disconnected = true ;
}
seek = 0 ;
bytes = 0 ;
continue ;
}
seek = 0 ;
}
if ( bytes = = 0 )
{
isListen = false ;
break ;
}
char * buf = buffer + seek ;
if ( bytes > 0 )
{
auto message = reinterpret_cast < const : : profiler : : net : : Message * > ( buf ) ;
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 ) ;
const auto dt = : : std : : chrono : : duration_cast < std : : chrono : : milliseconds > ( : : std : : chrono : : system_clock : : now ( ) - timeBegin ) ;
const auto bytesNumber = m_receivedData . str ( ) . size ( ) ;
qInfo ( ) < < " recieved " < < bytesNumber < < " bytes, " < < dt . count ( ) < < " ms, average speed = " < < double ( bytesNumber ) * 1e3 / double ( dt . count ( ) ) / 1024. < < " kBytes/sec " ;
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 ;
auto bytesNumber = : : std : : min ( ( int ) dm - > size , bytes - seek ) ;
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 ( ) )
{
m_bConnected . store ( false , : : std : : memory_order_release ) ;
isListen = false ;
disconnected = true ;
neededSize = 0 ;
}
break ;
}
buf = buffer ;
int toWrite = : : std : : min ( bytes , neededSize ) ;
m_receivedSize + = toWrite ;
m_receivedData . write ( buf , toWrite ) ;
neededSize - = toWrite ;
loaded + = toWrite ;
seek = toWrite ;
}
if ( m_bStopReceive . load ( : : std : : memory_order_acquire ) )
{
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 ) ) ;
m_bStopReceive . store ( false , : : std : : memory_order_release ) ;
}
break ;
}
default :
//qInfo() << "Receive unknown " << message->type;
break ;
}
}
}
if ( disconnected )
clearData ( ) ;
delete [ ] buffer ;
2017-04-03 23:28:19 +03:00
m_bCaptureReady . store ( true , : : std : : memory_order_release ) ;
2017-02-08 00:14:49 +03:00
}
void EasySocketListener : : listenDescription ( )
{
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 ;
while ( isListen & & ! m_bInterrupt . load ( : : std : : memory_order_acquire ) )
{
if ( ( bytes - seek ) = = 0 )
{
bytes = m_easySocket . receive ( buffer , buffer_size ) ;
if ( bytes = = - 1 )
{
if ( m_easySocket . isDisconnected ( ) )
{
m_bConnected . store ( false , : : std : : memory_order_release ) ;
isListen = false ;
disconnected = true ;
}
seek = 0 ;
bytes = 0 ;
continue ;
}
seek = 0 ;
}
if ( bytes = = 0 )
{
isListen = false ;
break ;
}
char * buf = buffer + seek ;
if ( bytes > 0 )
{
auto message = reinterpret_cast < const : : profiler : : net : : Message * > ( buf ) ;
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 ;
auto bytesNumber = : : std : : min ( ( int ) dm - > size , bytes - seek ) ;
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 ( ) )
{
m_bConnected . store ( false , : : std : : memory_order_release ) ;
isListen = false ;
disconnected = true ;
neededSize = 0 ;
}
break ;
}
buf = buffer ;
int toWrite = : : std : : min ( bytes , neededSize ) ;
m_receivedSize + = toWrite ;
m_receivedData . write ( buf , toWrite ) ;
neededSize - = toWrite ;
loaded + = toWrite ;
seek = toWrite ;
}
break ;
}
default :
break ;
}
}
}
if ( disconnected )
clearData ( ) ;
delete [ ] buffer ;
}
2017-04-03 23:16:36 +03:00
void EasySocketListener : : listenFrameTime ( )
{
2017-11-09 23:12:54 +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 ;
while ( isListen & & ! m_bInterrupt . load ( : : std : : memory_order_acquire ) )
{
if ( ( bytes - seek ) = = 0 )
{
bytes = m_easySocket . receive ( buffer , buffer_size ) ;
if ( bytes = = - 1 )
{
if ( m_easySocket . isDisconnected ( ) )
{
m_bConnected . store ( false , : : std : : memory_order_release ) ;
isListen = false ;
}
seek = 0 ;
bytes = 0 ;
continue ;
}
seek = 0 ;
}
if ( bytes = = 0 )
{
isListen = false ;
break ;
}
char * buf = buffer + seek ;
if ( bytes > 0 )
{
auto message = reinterpret_cast < const : : profiler : : net : : Message * > ( buf ) ;
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 ;
2017-04-03 23:16:36 +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 ) ;
}
isListen = false ;
break ;
}
default :
break ;
}
}
}
}
2017-02-08 00:14:49 +03:00
//////////////////////////////////////////////////////////////////////////