1
/* ---------------------------------------------------------------------
2
* Implementation of MainWindow main_window.cpp
3
* Application's top-level window
4
* ---------------------------------------------------------------------
5
* This file is part of Valkyrie, a front-end for Valgrind
6
* Copyright (C) 2000-2008, OpenWorks LLP <info@open-works.co.uk>
7
* This program is released under the terms of the GNU GPL v.2
8
* See the file COPYING for the full license details.
11
#include <qapplication.h>
14
#include <qpopupmenu.h>
15
#include <qstatusbar.h>
18
#include <qobjectlist.h>
20
#include "main_window.h"
21
#include "tool_object.h"
22
#include "valkyrie_object.h"
23
#include "valkyrie_xpm.h"
24
#include "tb_mainwin_icons.h"
25
#include "vk_config.h"
27
#include "vk_messages.h"
28
#include "context_help.h"
29
#include "html_urls.h"
46
Cachegrind: SHIFT+Key_C
52
/* class MainWindow ---------------------------------------------------- */
53
MainWindow::~MainWindow()
55
/* Write window attributes to config on exit.
56
Want to ignore any outstanding dirty config vals, but vkConfig
57
doesn't hold originals... simplest just to use a clean vkConfig... */
60
if ( cfg.initCfg( m_valkyrie ) ) {
61
cfg.wrInt( this->height(), "height", "MainWin" );
62
cfg.wrInt( this->width(), "width", "MainWin" );
63
cfg.wrInt( this->x(), "x-pos", "MainWin" );
64
cfg.wrInt( this->y(), "y-pos", "MainWin" );
66
// save opts to disk... too bad if it fails
67
cfg.sync( m_valkyrie );
71
MainWindow::MainWindow( Valkyrie* vk ) : QMainWindow( 0, "mainWindow" )
75
setCaption( vkConfig->vkName() );
76
setIcon( QPixmap(valkyrie_xpm) );
77
statusBar()->setSizeGripEnabled( false );
79
m_viewStack = new ToolViewStack( this, "view_stack" );
80
m_viewStack->setMargin( 0 );
81
m_viewStack->setLineWidth( 0 );
83
setCentralWidget( m_viewStack );
85
/* handbook: init before menubar / toolbar */
86
m_handBook = new HandBook();
88
/* create menubar, status bar + flags widget */
92
/* en/disable tooltips */
93
m_showToolTips = !vkConfig->rdBool("show-tooltips", "valkyrie");
96
/* init the options dialog */
97
m_optionsWin = new OptionsWindow( this );
98
/* let the flags widget know that flags may have been modified */
99
connect( m_optionsWin, SIGNAL(flagsChanged()),
100
this, SLOT(updateVgFlags()) );
104
void MainWindow::showToolView( int tvid )
106
if ( m_viewStack->visible() != 0 ) {
107
/* already loaded and visible */
108
if ( m_viewStack->id( m_viewStack->visible() ) == tvid ) {
113
/* set up next view */
114
ToolObject* nextTool = valkyrie()->valgrind()->toolObj( tvid );
115
vk_assert( nextTool != 0 );
117
/* view already created and on stack? */
118
ToolView* nextView = m_viewStack->view( tvid );
119
if ( nextView == 0 ) {
121
nextView = nextTool->createView( m_viewStack );
122
vk_assert( nextView != 0 );
124
m_viewStack->addView( nextView, tvid );
126
connect( nextTool, SIGNAL(running(bool)),
127
this, SLOT(updateButtons(bool)) );
128
connect( nextTool, SIGNAL(message(QString)),
129
this, SLOT(setStatus(QString)) );
130
connect( this, SIGNAL(toolbarLabelsToggled(bool)),
131
nextView, SLOT(toggleToolbarLabels(bool)) );
133
/* view starts tool processes via this signal */
134
connect( nextView, SIGNAL(run(VkRunState::State)),
135
this, SLOT(run(VkRunState::State)) );
139
m_viewStack->raiseView( tvid );
145
void MainWindow::stop()
147
/* don't come in here if there's no current view */
148
if ( m_viewStack->visible() == 0 )
151
valkyrie()->stopTool( m_viewStack->visibleId() );
154
/* start appropriate process for given runState */
155
void MainWindow::run( VkRunState::State runState )
157
vk_assert( runState != VkRunState::STOPPED );
159
/* don't come in here if there's no current view */
160
if ( m_viewStack->visible() == 0 )
163
/* last process might not be done ... */
164
if ( !valkyrie()->queryToolDone( m_viewStack->visibleId() ) )
167
/* if running valgrind, make sure there's a valid binary
168
just 'cos it made it into the config doesn't mean it's valid */
169
if( runState == VkRunState::VALGRIND ) {
170
int errval = PARSED_OK;
171
QString bin = vkConfig->rdEntry( "binary", "valkyrie" );
172
binaryCheck( &errval, bin );
173
if ( errval != PARSED_OK ) {
174
vkError( this, "Run Tool", "Invalid Binary: Please set a valid binary in Options::Valkyrie." );
179
if ( !valkyrie()->runTool( m_viewStack->visibleId(), runState ) ) {
180
vkError( this, "Run Tool",
181
"Failed to complete execution." );
185
/* run valgrind --tool=<current_tool> + flags + executable */
186
void MainWindow::runValgrind()
188
/* don't come in here if there's no current view */
189
if ( m_viewStack->visible() == 0 )
192
/* valkyrie may have been started with no executable
193
specified. if so, show prefsWindow + msgbox */
194
if ( vkConfig->rdEntry("binary","valkyrie").isEmpty() ) {
195
showOptionsWindow( Valkyrie::ID_VALKYRIE );
196
vkInfo( m_optionsWin, "Run Valgrind",
197
"Please enter the path to the executable "
198
"you wish to run, together with any arguments");
202
run( VkRunState::VALGRIND );
206
void MainWindow::showAboutInfo( int id )
208
HelpAbout::TabId tabid = (HelpAbout::TabId)id;
209
HelpAbout * dlg = new HelpAbout( this, tabid );
215
void MainWindow::showOptionsWindow( int view_id )
217
m_optionsWin->showPage( view_id );
218
m_optionsWin->raise();
222
/* slot, connected to a tool object's signal running(bool) */
223
void MainWindow::updateButtons( bool running )
225
m_runButton->setEnabled( !running );
226
m_stopButton->setEnabled( running );
230
void MainWindow::setToggles( int tview_id )
233
for ( uint index=0; index < m_toolsMenu->count(); index++ ) {
234
obj_id = m_toolsMenu->idAt( index );
235
/* set the view menu item on || off */
236
m_toolsMenu->setItemEnabled( obj_id, obj_id != tview_id );
240
if ( tview_id == -1 ) {
241
tbutt = (QToolButton*)m_viewButtGroup->selected();
242
tbutt->setOn( false );
244
tbutt = (QToolButton*)m_viewButtGroup->find( tview_id );
245
tbutt->setOn( true );
248
if ( tview_id == -1 ) {
249
/* no more tool views */
250
m_fileMenu->setItemEnabled( FILE_RUN, false );
251
m_fileMenu->setItemEnabled( FILE_STOP, false );
252
m_fileMenu->setItemEnabled( FILE_CLOSE, false );
254
m_runButton->setEnabled( false );
255
m_stopButton->setEnabled( false );
257
if ( m_flagsButton->isOn() ) {
258
m_flagsLabel->hide();
259
m_flagsButton->setDown( false );
261
m_flagsButton->setEnabled( false );
263
/* someone is hanging around ... */
264
m_fileMenu->setItemEnabled( FILE_CLOSE, true );
265
bool is_running = false;
266
if (m_viewStack->visible() != 0) {
267
ToolObject* tool = valkyrie()->valgrind()->toolObj( m_viewStack->visibleId() );
268
is_running = tool->isRunning();
270
m_fileMenu->setItemEnabled( FILE_RUN, !is_running );
271
m_fileMenu->setItemEnabled( FILE_STOP, is_running );
273
m_runButton->setEnabled( !is_running );
274
m_stopButton->setEnabled( is_running );
276
if ( m_flagsButton->isOn() ) {
277
showFlagsWidget( true );
279
m_flagsButton->setEnabled( true );
285
/* slot: connected to a tool object's signal message(QString) */
286
void MainWindow::setStatus( QString msg )
287
{ m_statusMsg->setText( msg ); }
290
/* shows / hides the label which contains the flags relevant to
291
the current toolview */
292
void MainWindow::showFlagsWidget( bool show )
295
m_flagsLabel->hide();
297
if ( m_viewStack->visible() != 0 ) {
298
QString flags = valkyrie()->getDisplayFlags();
299
m_flagsLabel->setText( flags );
300
if ( !m_flagsLabel->isVisible() ) {
301
m_flagsLabel->show();
308
/* Called by this->showToolView(),
309
m_optionsWin::flagsChanged() signal
311
void MainWindow::updateVgFlags()
313
/* update valkyrie's flags: if there's a visible ToolView */
314
if ( m_viewStack->visible() != 0 )
315
valkyrie()->updateVgFlags( m_viewStack->visibleId() );
317
/* update flags display */
318
if ( m_flagsLabel->isVisible() ) {
319
showFlagsWidget( true );
324
/* the stack owns the toolviews, and MainWin owns the stack, so we
325
don't need to explicitly delete the toolviews as they will be
326
auto-deleted when MainWin closes */
327
void MainWindow::closeEvent( QCloseEvent *ce )
329
ToolObjList tools = valkyrie()->valgrind()->toolObjList();
330
for ( ToolObject* tool = tools.first(); tool; tool = tools.next() ) {
331
if ( tool->view() != 0 && !tool->queryDone() ) {
337
/* handbook is a top-level parent-less widget, so we have to
338
explicitly delete it */
342
QMainWindow::closeEvent( ce );
346
void MainWindow::closeToolView()
348
int currViewId = m_viewStack->visibleId();
350
/* don't come in here if there's no current view */
351
if ( currViewId == -1 ) return;
353
ToolObject* currTool = valkyrie()->valgrind()->toolObj( currViewId );
355
vk_assert(currTool->view() != 0);
356
vk_assert(currTool->view() == m_viewStack->visible());
358
/* process might still be running, or whatever ... */
359
if ( !currTool->queryDone() ) return;
361
/* remove view from stack (doesn't delete) */
362
m_viewStack->removeView( m_viewStack->widget( currViewId ) );
364
/* delete view, and zero tool's view ptr */
365
currTool->deleteView();
367
/* find the next view to be shown, if exists, and show it */
368
ToolView* nextView = m_viewStack->nextView();
369
if ( nextView != 0 ) { // Found another view in stack
370
m_viewStack->raiseView( nextView );
373
setToggles( m_viewStack->id( nextView ) );
377
void MainWindow::toggleToolTips()
379
m_showToolTips = !m_showToolTips;
380
QToolTip::setGloballyEnabled( m_showToolTips );
384
void MainWindow::toggleToolbarLabels()
386
m_showToolbarLabels = !m_showToolbarLabels;
387
m_runButton->setUsesTextLabel( m_showToolbarLabels );
388
m_stopButton->setUsesTextLabel( m_showToolbarLabels );
389
/* tell the toolviews to follow suit */
390
emit toolbarLabelsToggled( m_showToolbarLabels );
394
void MainWindow::mkMenuBar()
396
/* show toolbutton text labels (or not) */
397
m_showToolbarLabels = vkConfig->rdBool("show-butt-text","valkyrie");
399
/* --------------------------------------------------------------- */
400
/* Main Menu ----------------------------------------------------- */
401
QMenuBar* mainMenu = new QMenuBar( this, "main menubar" );
402
ContextHelp::add( mainMenu, urlValkyrie::menuBar );
406
/* file menu --------------------------------------------------------- */
408
m_fileMenu = new QPopupMenu( this, "file_menu" );
409
m_fileMenu->insertItem( "&Run Valgrind", this, SLOT(runValgrind()),
410
CTRL+Key_R, FILE_RUN );
411
m_fileMenu->insertItem( "S&top", this, SLOT(stop()),
412
CTRL+Key_T, FILE_STOP );
413
m_fileMenu->insertSeparator();
414
m_fileMenu->insertItem( "&Close", this, SLOT(closeToolView()),
415
CTRL+Key_W, FILE_CLOSE );
416
m_fileMenu->insertItem( "E&xit", qApp,
417
SLOT(closeAllWindows()), CTRL+Key_X );
418
mainMenu->insertItem( "&File", m_fileMenu, -1, index );
419
ContextHelp::add( m_fileMenu, urlValkyrie::fileMenu );
421
/* toolview menu ----------------------------------------------------- */
423
QPixmap bulletSet(black_bullet_xpm);
424
m_toolsMenu = new QPopupMenu( this, "tools_menu" );
425
ToolObjList tools = valkyrie()->valgrind()->toolObjList();
426
for ( ToolObject* tool = tools.first(); tool; tool = tools.next() ) {
427
m_toolsMenu->insertItem( bulletSet, tool->accelTitle(),
428
this, SLOT( showToolView(int) ),
429
tool->accelKey(), tool->objId() );
431
mainMenu->insertItem( "&Tools", m_toolsMenu, -1, index );
432
ContextHelp::add( m_toolsMenu, urlValkyrie::toolMenu );
434
/* options / preferences et al --------------------------------------- */
436
m_optsMenu = new QPopupMenu( this, "options_menu" );
437
VkObjectList objList = valkyrie()->vkObjList();
438
for ( VkObject* obj = objList.first(); obj; obj = objList.next() ) {
439
m_optsMenu->insertItem( obj->title(), this,
440
SLOT(showOptionsWindow(int)),
443
mainMenu->insertItem( "O&ptions", m_optsMenu, -1, index );
444
ContextHelp::add( m_optsMenu, urlValkyrie::optionsMenu );
447
/* help menu ----------------------------------------------------- */
449
m_helpMenu = new QPopupMenu( this, "help_menu" );
450
m_helpMenu->insertItem( "Handbook", m_handBook, SLOT(showYourself()), Key_F1 );
451
m_helpMenu->insertSeparator();
452
m_helpMenu->insertItem( "About Valkyrie", this,
453
SLOT(showAboutInfo(int)), 0, HelpAbout::ABOUT_VK );
454
m_helpMenu->insertItem( "About Qt", this,
455
SLOT(showAboutInfo(int)), 0, HelpAbout::ABOUT_QT );
456
m_helpMenu->insertSeparator();
457
m_helpMenu->insertItem( "License", this,
458
SLOT(showAboutInfo(int)), 0, HelpAbout::LICENSE );
459
m_helpMenu->insertItem( "Support", this,
460
SLOT(showAboutInfo(int)), 0, HelpAbout::SUPPORT );
461
mainMenu->insertItem( "&Help", m_helpMenu, -1, index );
462
QToolTip::add( m_helpMenu, "Show help manual / information" );
463
ContextHelp::add( m_helpMenu, urlValkyrie::helpMenu );
465
/* Note: 'windows' style horizontal menu's seem to right-justify anything
466
after a non-QPopupMenu */
468
/* application-wide context help button ------------------------------ */
470
QToolButton* ctxtButton = new ContextHelpButton( this, m_handBook );
471
QToolTip::add( ctxtButton, "This is a <b>Context Help</b> button. "
472
"Clicking on a widget will open the relevant manual help page");
473
mainMenu->insertItem( ctxtButton, -1, index );
476
/* --------------------------------------------------------------- */
477
/* Valgrind Control Toolbar -------------------------------------- */
478
QToolBar* vgCtlToolBar = new QToolBar( this, "vg_ctl_toolbar" );
479
vgCtlToolBar->setLabel( "Valgrind Control Toolbar" );
481
/* run button ---------------------------------------------------- */
483
m_runButton = new QToolButton( vgCtlToolBar, "tb_rerun" );
484
m_runButton->setIconSet( QPixmap(run_xpm) );
485
m_runButton->setTextLabel( "&Run Valgrind" );
486
#if (QT_VERSION-0 >= 0x030200)
487
m_runButton->setTextPosition( QToolButton::BesideIcon );
488
#else // QT_VERSION < 3.2
489
m_runButton->setTextPosition( QToolButton::Right );
491
m_runButton->setUsesTextLabel( m_showToolbarLabels );
492
m_runButton->setAutoRaise( true );
493
m_runButton->setAccel( CTRL+Key_R );
494
connect( m_runButton, SIGNAL( clicked() ),
495
this, SLOT( runValgrind() ) );
496
QToolTip::add( m_runButton, "Run valgrind with specified executable" );
497
ContextHelp::add( m_runButton, urlValkyrie::runButton );
499
/* stop button --------------------------------------------------- */
501
m_stopButton = new QToolButton( vgCtlToolBar, "tb_stop" );
502
m_stopButton->setIconSet( QPixmap(stop_xpm) );
503
m_stopButton->setTextLabel( "S&top" );
504
#if (QT_VERSION-0 >= 0x030200)
505
m_stopButton->setTextPosition( QToolButton::BesideIcon );
506
#else // QT_VERSION < 3.2
507
m_stopButton->setTextPosition( QToolButton::Right );
509
m_stopButton->setUsesTextLabel( m_showToolbarLabels );
510
m_stopButton->setAutoRaise( true );
511
m_stopButton->setAccel( CTRL+Key_T );
512
connect( m_stopButton, SIGNAL( clicked() ),
513
this, SLOT( stop() ) );
514
QToolTip::add( m_stopButton, "Terminate program execution immediately" );
515
ContextHelp::add( m_stopButton, urlValkyrie::stopButton );
518
/* strech toolbar to right --------------------------------------- */
519
QLabel* lbl_extend = new QLabel( vgCtlToolBar, "lbl_extend" );
520
vgCtlToolBar->setStretchableWidget( lbl_extend );
524
/* 'status bar' with 3 rows: label to show non-default flags on top,
525
message text in the middle
526
toolview buttons on the bottom */
527
void MainWindow::mkStatusBar()
529
QFrame* statusFrame = new QFrame( statusBar() );
530
statusBar()->addWidget( statusFrame, 10, true );
531
QVBoxLayout* statusLayout = new QVBoxLayout( statusFrame );
532
statusLayout->setSpacing( 2 );
534
/* hbox for top row */
535
QHBoxLayout* top_row = new QHBoxLayout( 2, "top_row" );
536
statusLayout->addLayout( top_row, 20 );
538
m_flagsLabel = new QLabel( statusFrame, "flags_label" );
539
top_row->addWidget( m_flagsLabel );
540
m_flagsLabel->setFrameStyle( QFrame::StyledPanel | QFrame::Sunken );
541
m_flagsLabel->setPaletteBackgroundColor( Qt::white );
542
m_flagsLabel->setAlignment( AlignLeft );
543
m_flagsLabel->setTextFormat( Qt::PlainText );
544
ContextHelp::add( m_flagsLabel, urlValkyrie::flagsWidget );
545
m_flagsLabel->hide();
548
/* hbox for middle row */
549
QHBoxLayout* mid_row = new QHBoxLayout( 5, "middle_row" );
550
statusLayout->addLayout( mid_row );
552
/* frame+layout for messages */
553
QFrame* msgFrame = new QFrame( statusFrame );
554
msgFrame->setFrameStyle( QFrame::StyledPanel | QFrame::Sunken );
555
mid_row->addWidget( msgFrame );
556
QBoxLayout* msgLayout = new QHBoxLayout( msgFrame, 2 );
557
m_statusMsg = new QLabel( "", msgFrame, "status_msg" );
558
m_statusMsg->setAlignment( AlignLeft );
559
m_statusMsg->setTextFormat( Qt::PlainText );
560
int status_height = fontMetrics().height();
561
m_statusMsg->setFixedHeight( status_height );
562
msgLayout->addWidget( m_statusMsg );
563
ContextHelp::add( m_statusMsg, urlValkyrie::statusMsg );
566
/* hbox for the bottom row */
567
QHBoxLayout* bot_row = new QHBoxLayout( 5, "bot_row" );
568
statusLayout->addLayout( bot_row, 0 );
570
/* the toolview buttons */
571
m_viewButtGroup = new QButtonGroup( statusFrame );
572
m_viewButtGroup->setExclusive( true );
573
m_viewButtGroup->hide();
574
connect( m_viewButtGroup, SIGNAL(clicked(int)),
575
this, SLOT(showToolView(int)) );
576
//RM: ContextHelp::add( m_viewButtGroup, urlValkyrie::tviewButtons );
578
/* set the buttons to all be the same width */
579
int butt_width = fontMetrics().width( "XMemcheckX" );
580
ToolObjList tools = valkyrie()->valgrind()->toolObjList();
581
for ( ToolObject* tool = tools.first(); tool; tool = tools.next() ) {
582
int len = tool->accelTitle().length();
583
butt_width = ( len > butt_width ) ? len : butt_width;
585
int butt_height = fontMetrics().height() + 12;
586
QToolButton* tvButton;
587
for ( ToolObject* tool = tools.first(); tool; tool = tools.next() ) {
588
tvButton = new QToolButton( statusFrame, tool->name() + "_button" );
589
tvButton->setToggleButton( true );
590
tvButton->setEnabled( true );
591
tvButton->setText( tool->accelTitle() );
592
tvButton->setAccel( tool->accelKey() );
593
tvButton->setMinimumWidth( butt_width );
594
tvButton->setFixedHeight( butt_height );
595
m_viewButtGroup->insert( tvButton, tool->objId() );
596
bot_row->addWidget( tvButton );
597
ContextHelp::add( tvButton, urlValkyrie::toolMenu );
600
bot_row->addStretch(1);
602
/* frame+layout for the view-flags icon */
603
m_flagsButton = new QToolButton( statusFrame, "flags_button" );
604
bot_row->addWidget( m_flagsButton );
605
m_flagsButton->setToggleButton( true );
606
m_flagsButton->setEnabled( true );
607
m_flagsButton->setPixmap( QPixmap(view_flags_xpm) );
608
connect( m_flagsButton, SIGNAL( toggled(bool) ),
609
this, SLOT( showFlagsWidget(bool) ) );
610
QToolTip::add( m_flagsButton, "Show non-default valgrind flags for current tool" );
611
ContextHelp::add( m_flagsButton, urlValkyrie::flagsWidget );