From: <sv...@va...> - 2011-06-27 14:35:43
|
Author: cerion Date: 2011-06-27 15:30:50 +0100 (Mon, 27 Jun 2011) New Revision: 532 Log: Added: 1. Suppressions editor 2. Right click on an error -> suppress that error 3. Right click on any listitem -> copy text/XML to clipboard Added: trunk/icons/arrow_down.png trunk/icons/arrow_up.png trunk/src/options/suppressions.cpp trunk/src/options/suppressions.h trunk/src/options/vk_suppressions_dialog.cpp trunk/src/options/vk_suppressions_dialog.h Modified: trunk/icons.qrc trunk/src/mainwindow.cpp trunk/src/objects/valgrind_object.cpp trunk/src/objects/valkyrie_object.cpp trunk/src/options/valgrind_options_page.cpp trunk/src/options/valgrind_options_page.h trunk/src/options/vk_options_dialog.cpp trunk/src/options/vk_options_dialog.h trunk/src/options/vk_options_page.h trunk/src/options/widgets/opt_lb_widget.cpp trunk/src/options/widgets/opt_lb_widget.h trunk/src/src.pro trunk/src/toolview/memcheckview.cpp trunk/src/toolview/memcheckview.h trunk/src/toolview/vglogview.cpp trunk/src/toolview/vglogview.h trunk/vk_config.pri Added: trunk/icons/arrow_down.png =================================================================== (Binary files differ) Property changes on: trunk/icons/arrow_down.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: trunk/icons/arrow_up.png =================================================================== (Binary files differ) Property changes on: trunk/icons/arrow_up.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Modified: trunk/icons.qrc =================================================================== --- trunk/icons.qrc 2011-06-24 12:31:13 UTC (rev 531) +++ trunk/icons.qrc 2011-06-27 14:30:50 UTC (rev 532) @@ -1,5 +1,5 @@ <RCC> - <qresource prefix="/vk_icons" > + <qresource prefix="/vk_icons"> <file>icons/msgbox_error.xpm</file> <file>icons/msgbox_info.xpm</file> <file>icons/msgbox_query.xpm</file> @@ -30,5 +30,7 @@ <file>icons/tree_open.png</file> <file>icons/text_less.png</file> <file>icons/text_more.png</file> + <file>icons/arrow_down.png</file> + <file>icons/arrow_up.png</file> </qresource> </RCC> Modified: trunk/src/mainwindow.cpp =================================================================== --- trunk/src/mainwindow.cpp 2011-06-24 12:31:13 UTC (rev 531) +++ trunk/src/mainwindow.cpp 2011-06-27 14:30:50 UTC (rev 532) @@ -113,6 +113,13 @@ updateEventFilters( this ); updateEventFilters( handBook ); + +#if 0 + // CAB: Handy shortcut for testing: load last project + QString proj_fname = actFile_RecentProjs[0]->data().toString(); + vkCfgProj->openProject( proj_fname ); + setCurrentProject( proj_fname ); +#endif } Modified: trunk/src/objects/valgrind_object.cpp =================================================================== --- trunk/src/objects/valgrind_object.cpp 2011-06-24 12:31:13 UTC (rev 531) +++ trunk/src/objects/valgrind_object.cpp 2011-06-27 14:30:50 UTC (rev 532) @@ -409,9 +409,9 @@ this->objectName(), "gen-suppressions", '\0', - "<yes|no|all>", - "yes|no|all", - "no", + "<no|all>", + "no|all", + "all", // Vg default is 'no', but we (generally) want this on. "Print suppressions for errors", "print suppressions for errors?", urlVgCore::genSuppressions, @@ -511,14 +511,14 @@ case VALGRIND::SHOW_BELOW: case VALGRIND::MAX_SFRAME: case VALGRIND::SMC_CHECK: + case VALGRIND::GEN_SUPP: opt->isValidArg( &errval, argval ); break; - + case VALGRIND::VERBOSITY: case VALGRIND::TRACK_FDS: case VALGRIND::TIME_STAMP: case VALGRIND::EM_WARNS: - case VALGRIND::GEN_SUPP: case VALGRIND::ERROR_LIMIT: case VALGRIND::DB_COMMAND: case VALGRIND::DB_ATTACH: @@ -724,7 +724,6 @@ case VALGRIND::TRACK_FDS: case VALGRIND::TIME_STAMP: case VALGRIND::EM_WARNS: - case VALGRIND::GEN_SUPP: case VALGRIND::ERROR_LIMIT: case VALGRIND::DB_ATTACH: case VALGRIND::DB_COMMAND: @@ -739,6 +738,12 @@ } break; + + // suppressions + case VALGRIND::GEN_SUPP: + // always add, irrespective of cfgVal / dfltVal + modFlags << "--" + opt->longFlag + "=" + cfgVal; + break; // all tools use an internal logging option, // so logging options should not be used Modified: trunk/src/objects/valkyrie_object.cpp =================================================================== --- trunk/src/objects/valkyrie_object.cpp 2011-06-24 12:31:13 UTC (rev 531) +++ trunk/src/objects/valkyrie_object.cpp 2011-06-27 14:30:50 UTC (rev 532) @@ -714,7 +714,7 @@ vg_flags.insert( ++( vg_flags.begin() ), ( "--xml-file=" + logfile ) ); vg_flags.insert( ++( vg_flags.begin() ), "--xml=yes" ); - + return activeTool->start( procId, vg_flags, logfile ); } Added: trunk/src/options/suppressions.cpp =================================================================== --- trunk/src/options/suppressions.cpp (rev 0) +++ trunk/src/options/suppressions.cpp 2011-06-27 14:30:50 UTC (rev 532) @@ -0,0 +1,469 @@ +/**************************************************************************** +** Suppressions implementation +** -------------------------------------------------------------------------- +** +** Copyright (C) 2000-2011, OpenWorks LLP. All rights reserved. +** <in...@op...> +** +** This file is part of Valkyrie, a front-end for Valgrind. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 as published by the Free Software Foundation +** and appearing in the file COPYING included in the packaging of +** this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +#include "options/suppressions.h" +#include "options/vk_suppressions_dialog.h" +#include "utils/vk_config.h" +#include "utils/vk_messages.h" +#include "utils/vk_utils.h" + +#include <QDateTime> +#include <QFile> + + +SuppRanges *SuppRanges::s_instance = 0; + +/*! + class SuppRanges + */ +SuppRanges::SuppRanges() +{ + // init ref lists of allowable values + + // Tools + kindTools.append("Memcheck"); + kindTools.append("DRD"); + kindTools.append("Exp-PtrCheck"); + kindTools.append("Helgrind"); + + // Suppr types PER TOOL + for (int i=0; i<kindTools.count(); i++) + kindTypes.append( QStringList() ); + + int i=0; + QStringList* mc_types = &kindTypes[i++]; + mc_types->append("Value1"); // "Uninitialised-value error for value of 1, 2, 4, 8 or 16 bytes." + mc_types->append("Value2"); + mc_types->append("Value4"); + mc_types->append("Value8"); + mc_types->append("Value16"); + mc_types->append("Cond"); // "Uninitialised CPU condition code." + mc_types->append("Value0"); // "Old name for Cond - uninitialised CPU condition code" + mc_types->append("Addr1"); // "Invalid address during a memory access of 1, 2, 4, 8 or 16 bytes." + mc_types->append("Addr2"); + mc_types->append("Addr4"); + mc_types->append("Addr8"); + mc_types->append("Addr16"); + mc_types->append("Jump"); // "jump to an unaddressable location error." + mc_types->append("Param"); // "invalid system call parameter error." + mc_types->append("Free"); // "invalid or mismatching free." + mc_types->append("Overlap");// "src / dst overlap in memcpy or similar function." + mc_types->append("Leak"); // "memory leak." + + QStringList* hg_types = &kindTypes[i++]; + hg_types->append("Race"); + +#if 0 // TODO: support drd, ptr-check + QStringList* drd_types = &kindTypes[i++]; + drd_types->append("CondErr"); + drd_types->append("ConflictingAccess"); + + QStringList* exp_pchk_types = &kindTypes[i++]; + exp_pchk_types->append("Arith"); + exp_pchk_types->append("Heap"); + exp_pchk_types->append("SorG"); +#endif + + // Frame types + frameTypes.append("fun"); // "name of the function in which the error occurred" + frameTypes.append("obj"); // "full path of the .so file or executable containing the error location" +} + + + + +/*! + class Suppression + */ +Suppression::Suppression() +{} + +// free format text, e.g. "from test_socket_ssl" +bool Suppression::setName( QString str ) +{ + str = str.simplified(); + if ( str.isEmpty() ) + return false; + + m_name = str; + return true; +} + +// *** TODO: multiple tools e.g. "Memcheck,Addrcheck:Cond" *** +// e.g. "Memcheck:Cond" +bool Suppression::setKind( QString str ) +{ + vk_assert( !m_name.isEmpty() ); + + str = str.simplified(); + if ( str.isEmpty() ) + return false; + + QStringList list = str.split(":"); + if (list.count() != 2) { + vkPrintErr("Bad Kind (%s) for this suppression (%s).", + qPrintable(str), qPrintable(m_name)); + return false; + } + + QRegExp re( list[0], Qt::CaseInsensitive ); + int idx = SuppRanges::instance()->kindTools.indexOf( re ); + if ( idx == -1 ) { + vkPrintErr("Bad Tool (%s) for this suppression (%s).", + qPrintable(list[0]), qPrintable(m_name)); + return false; + } + else { + QStringList kindTypes = SuppRanges::instance()->kindTypes[idx]; + if ( !kindTypes.contains( list[1], Qt::CaseInsensitive ) ) { + vkPrintErr("Bad SupprType (%s) for Tool (%s) for this suppression (%s).", + qPrintable(list[1]), qPrintable(list[0]), qPrintable(m_name)); + return false; + } + } + m_kind = str; + return true; +} + +// free format text, e.g. "write(buf)" +bool Suppression::setKindAux( QString str ) +{ + str = str.simplified(); + + m_kind_aux = str; + return true; +} + +// e.g. "obj:/usr/X11R6/lib*/libX11.so.6.2" +// e.g. "fun:*libc_write" +bool Suppression::addFrame( QString str ) +{ + str = str.simplified(); + + QStringList list = str.split(":"); + if (list.count() != 2) { + vkPrintErr( "Bad Kind (%s) for suppression '%s'.", + qPrintable(str), qPrintable(m_name) ); + return false; + } + + if ( !SuppRanges::instance()->frameTypes.contains( list[0], Qt::CaseInsensitive ) ) { + vkPrintErr( "Unsupported frame type (%s) for suppression '%s'.", + qPrintable(list[0]), qPrintable(m_name) ); + return false; + } + + if ( list.at(1).isEmpty() ) { + vkPrintErr( "Empty frame contents ('%s') for suppression '%s'.", + qPrintable(str), qPrintable(m_name) ); + return false; + } + + m_frames.append( str ); + return true; +} + + +// suppression lines: name[1], kind[1], kindaux[0:1], frame[1:N] +bool Suppression::fromStringList( const QStringList& lines ) +{ + int i=0; + + if ( lines.count() < 3 ) { + vkPrintErr( "Expecting at least 3 lines: name, kind, frame" ); + return false; + } + + // name, kind + if ( !setName( lines[i++] ) ) return false; + if ( !setKind( lines[i++] ) ) return false; + + // kaux (optional) + QRegExp re( "Memcheck:Param", Qt::CaseInsensitive ); + if ( m_kind.contains( re ) && + !(lines.at(i).startsWith("obj:") || + lines.at(i).startsWith("fun:") ) ) { + // found an aux line + if ( !setKindAux( lines[i++] ) ) return false; + } + + int nFrames = lines.count() - i; + if ( nFrames < 1 ) { + vkPrintErr( "No frames found: must have at least 1 frame." ); + return false; + } + if ( nFrames > MAX_SUPP_FRAMES ) { + vkPrintErr( "Numer of frames (%d) greater than allowed (%d)", + nFrames, MAX_SUPP_FRAMES ); + return false; + } + + // frames + for (;i<lines.count(); i++) { + if ( !addFrame( lines[i] ) ) return false; + } + + return true; +} + + +QString Suppression::toString() const +{ + QString str = "{\n"; + str += " " + m_name + "\n"; + str += " " + m_kind + "\n"; + if ( !m_kind_aux.isEmpty() ) + str += " " + m_kind_aux + "\n"; + for (int i=0; i<m_frames.count(); ++i) { + str += " " + m_frames.at(i) + "\n"; + } + str += "}\n\n"; + + return str; +} + + + + +/*! + class SuppList + */ +bool SuppList::readSuppFile( QString& fname ) +{ + m_fname = fname; + + QFile file( fname ); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + // TODO: error + return false; + } + + bool suppParseError = false; + QTextStream in(&file); + + while (!in.atEnd()) { + QString line = in.readLine().simplified(); + if ( line.contains(QRegExp("^\\{$")) ) { // start of new supp + QStringList suppLines; + Suppression supp; + + while(!in.atEnd()) { + line = in.readLine().simplified(); + if ( line.startsWith("#") || line.isEmpty() ) + continue; + if ( line.contains(QRegExp("^\\}$")) ) // end of supp + break; + suppLines += line; + } + + if ( supp.fromStringList( suppLines ) ) { + m_supps.append( supp ); + } + else { + suppParseError = true; + vkPrintErr( "Error reading supps file: %s\n", qPrintable(fname)); + // carry on with rest of input + } + } + } + + if ( m_supps.count() == 0 ) { + //TODO: tell user (INFO) no supps found in this file. + } + + if ( suppParseError ) { + + int res = vkQuery( 0, "Confirm Continue", "&Ok;&Cancel", + "<p>Problems were found with a suppression file.<br/>" + "If you continue, the suppressions that were unsuccessfully " + "parsed will be deleted from the suppressions file.</p>" + "<p>Are you sure you want to continue?</p>" ); + + if (res == MsgBox::vkYes) { + // write parsed supps back to file. + writeSuppFile(); + } + else { + return false; + } + } + return true; +} + + +bool SuppList::writeSuppFile() +{ + if ( !initSuppsFile( m_fname ) ) { + return false; + } + + QFile file( m_fname ); + if (!file.open( QIODevice::WriteOnly | + QIODevice::Text | + QIODevice::Append )) { // append to init header + // TODO: error + return false; + } + + QTextStream out(&file); + + for (int i=0; i<m_supps.count(); ++i) { + out << m_supps.at(i).toString(); + } + + file.close(); + return true; +} + + + +const QStringList SuppList::suppNames() +{ + QStringList list; + foreach(Suppression supp, m_supps) { + list.append( supp.getName() ); + } + return list; +} + + +void SuppList::clear() +{ + m_supps.clear(); + m_fname = QString(); +} + + + +// truncate and initialise supp file +bool SuppList::initSuppsFile( const QString& fname ) +{ + QFile file( fname ); + if ( file.open( QIODevice::WriteOnly | QIODevice::Truncate ) ) + { + QTextStream stream( &file ); + stream << "# Valgrind suppressions file\n" + << "# Created by: Valkyrie (" + VkCfg::appVersion() + ")\n" + << "# Date: " + QDateTime::currentDateTimeUtc().toString() << "\n" + << "#\n" + << "# WARNING: other '# comments' will be discarded by Valkyrie.\n" + << "#\n" + << "# Format of the objects in this file (in regex style) is:\n" + << "#\n" + << "# {\n" + << "# TEXT -supp name\n" + << "# TOOL::KIND -Valgrind tools, supp kind, eg 'Memcheck:Param'\n" + << "# KAUX? -(optional) aux for some kinds, eg 'write(buf)'\n" + << "# ((obj|fun):<TEXT>\\n)+ -(min one) list of call-chain frames, one per line\n" + << "# }\n" + << "#\n" + << "# Note: Multiple tools per kind e.g. TOOL(,TOOL)*::KIND' is not (yet) supported.\n" + << "#\n" + << "# Note: For Memcheck, the the optional aux info is:\n" + << "# if (KIND == 'Param'): KAUX = system call param e.g. 'write(buf)'\n" << endl; + + file.close(); + return true; + } + else { + return false; + } +} + + + +/*! + New suppression + Returns false if user cancelled edit, else true +*/ +bool SuppList::newSupp() +{ + return editSupp( -1 ); +} + +/*! + Edit suppression + idx == -1: new supp (i.e. not yet managed by us) + supp: empty for !new supp + empty|filled for new supp + Returns false if user cancelled edit, else true +*/ +bool SuppList::editSupp( int idx, Suppression supp ) +{ + bool isNew = (idx == -1); + if ( !isNew ) { // if editing an existing supp: + vk_assert( supp.getName().isEmpty() ); // - it can't be empty + supp = m_supps.at( idx ); // - load supp from model at idx + } + + VkSuppressionsDialog dlg; + + // If supp has content, load it + if ( !supp.getName().isEmpty() ) { + dlg.setSupp( supp ); + } + + // run dialogbox + if ( dlg.exec() == QDialog::Accepted ) { + supp = dlg.getUpdatedSupp(); + + // update model and rewrite suppfile + if ( isNew ) + m_supps.append( supp ); + else { + m_supps.replace( idx, supp ); + } + + if (!writeSuppFile()) { + //TODO: error + vkPrintErr("Error: failure during log save"); + } + return true; + } + else { + // QDialog::Rejected: + return false; + } +} + +/*! + Delete suppression + Returns false if user cancelled delete, else true +*/ +bool SuppList::deleteSupp( int idx ) +{ + int res = vkQuery( 0, "Confirm Delete", "&Delete;&Cancel", + "<p>The suppression will be deleted from the file.</p>" + "<p>Are you sure you want to do this ?</p>" ); + + if ( res == MsgBox::vkYes ) { // Delete + // remove from our list, and write our list over the file. + m_supps.removeAt( idx ); + if (!writeSuppFile()) { + //TODO: error + vkPrintErr("Error: failure during log save"); + } + return true; + } + else { // Cancel + // MsgBox::vkNo + return false; + } +} + Added: trunk/src/options/suppressions.h =================================================================== --- trunk/src/options/suppressions.h (rev 0) +++ trunk/src/options/suppressions.h 2011-06-27 14:30:50 UTC (rev 532) @@ -0,0 +1,107 @@ +/**************************************************************************** +** Suppressions definition +** -------------------------------------------------------------------------- +** +** Copyright (C) 2000-2011, OpenWorks LLP. All rights reserved. +** <in...@op...> +** +** This file is part of Valkyrie, a front-end for Valgrind. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 as published by the Free Software Foundation +** and appearing in the file COPYING included in the packaging of +** this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +#ifndef SUPPRESSIONS_H +#define SUPPRESSIONS_H + +#include <QList> +#include <QString> +#include <QStringList> +#include <QTextStream> + +// TODO: what's reasonable? what does Vg allow? +#define MAX_SUPP_FRAMES 20 + + + +// ============================================================ +// Singleton class holding some handy reference data +class SuppRanges +{ +public: + static SuppRanges *instance() + { + if (!s_instance) + s_instance = new SuppRanges; + return s_instance; + } + + QStringList kindTools; // Memcheck|... + QList<QStringList> kindTypes; // list for every tool + QStringList frameTypes; // obj|fun + +private: + SuppRanges(); + static SuppRanges *s_instance; +}; + + + + +// ============================================================ +class Suppression +{ +public: + Suppression(); + + bool fromStringList( const QStringList& lines ); + QString toString() const; + + // Setters + bool setName( QString str ); + bool setKind( QString str ); + bool setKindAux( QString str ); + bool addFrame( QString str ); + + // Getters + QString getName() const { return m_name; } + QString getKind() const { return m_kind; } + QString getKAux() const { return m_kind_aux; } + QStringList getFrames() const { return m_frames; } + +private: + QString m_name; // name of the suppression + QString m_kind; // kind, eg "Memcheck:Param" + QString m_kind_aux; // (optional) aux kind, eg "write(buf)" + QStringList m_frames; // (one or more) frames +}; + + +// ============================================================ +class SuppList +{ +public: + SuppList() {}; + + bool readSuppFile( QString& filename ); + bool writeSuppFile(); + const QStringList suppNames(); + void clear(); + bool initSuppsFile( const QString& fname ); + bool newSupp(); + bool editSupp( int idx, Suppression supp = Suppression() ); + bool deleteSupp( int idx ); + +private: + QList<Suppression> m_supps; + QString m_fname; +}; + + +#endif // SUPPRESSIONS_H Modified: trunk/src/options/valgrind_options_page.cpp =================================================================== --- trunk/src/options/valgrind_options_page.cpp 2011-06-24 12:31:13 UTC (rev 531) +++ trunk/src/options/valgrind_options_page.cpp 2011-06-27 14:30:50 UTC (rev 532) @@ -19,6 +19,7 @@ ****************************************************************************/ #include <QDir> +#include <QFileDialog> #include <QListWidget> #include <QTabWidget> @@ -62,7 +63,7 @@ group1->setObjectName( QString::fromUtf8( "ValgrindOptionsPage_group1" ) ); pageTopVLayout->addWidget( group1 ); - QTabWidget* tabWidget = new QTabWidget( this ); + tabWidget = new QTabWidget( this ); tabWidget->setObjectName( QString::fromUtf8( "ValgrindOptionsPage_tabWidget" ) ); pageTopVLayout->addWidget( tabWidget ); @@ -201,18 +202,95 @@ tabWidget->addTab( tabSupps, " Suppressions " ); ContextHelp::addHelp( tabSupps, urlValkyrie::suppsTab ); - // tabErep - vbox - QVBoxLayout* supp_vbox = new QVBoxLayout( tabSupps ); - supp_vbox->setObjectName( QString::fromUtf8( "supp_vbox" ) ); + // tabSupps - suppression files + QGroupBox* suppfile_groupbox = new QGroupBox(); + QHBoxLayout* suppfile_hbox = new QHBoxLayout(); + suppfile_hbox->setObjectName( QString::fromUtf8( "suppfile_hbox" ) ); + suppfile_hbox->setMargin(0); + // listbox(options) + insertOptionWidget( VALGRIND::SUPPS_SEL, tabSupps, false ); // listbox + LbWidget* lbSel = ( LbWidget* )m_itemList[VALGRIND::SUPPS_SEL]; + QListWidget* lwSuppFiles = (QListWidget*)lbSel->widget(); + connect( lwSuppFiles, SIGNAL(currentRowChanged(int)), this, SLOT(setSuppFileBtns()) ); + connect( lwSuppFiles, SIGNAL(currentRowChanged(int)), this, SLOT(suppLoad()) ); + // buttongroup + QWidget* butts1_groupbox = new QWidget(); + QVBoxLayout* butts1_vbox = new QVBoxLayout(); + butts1_vbox->setObjectName( QString::fromUtf8( "butts1_vbox" ) ); + butts1_vbox->setMargin(0); - // tabErep - options - insertOptionWidget( VALGRIND::SUPPS_SEL, tabSupps, true ); // listbox + QIcon icon_arrow_up; + icon_arrow_up.addPixmap( QPixmap( QString::fromUtf8( ":/vk_icons/icons/arrow_up.png" ) ) ); + QIcon icon_arrow_down; + icon_arrow_down.addPixmap( QPixmap( QString::fromUtf8( ":/vk_icons/icons/arrow_down.png" ) ) ); - LbWidget* lbSel = ( LbWidget* )m_itemList[VALGRIND::SUPPS_SEL]; - supp_vbox->addLayout( lbSel->vlayout() ); + btn_suppfile_up = new QPushButton( icon_arrow_up, "", butts1_groupbox ); + btn_suppfile_dwn = new QPushButton( icon_arrow_down, "", butts1_groupbox ); + btn_suppfile_new = new QPushButton("New", butts1_groupbox ); + btn_suppfile_add = new QPushButton("Add", butts1_groupbox ); + btn_suppfile_rmv = new QPushButton("Remove", butts1_groupbox ); + setSuppFileBtns(); + connect( btn_suppfile_up, SIGNAL(clicked()), this, SLOT( suppfileUp() ) ); + connect( btn_suppfile_dwn, SIGNAL(clicked()), this, SLOT( suppfileDown() ) ); + connect( btn_suppfile_new, SIGNAL(clicked()), this, SLOT( suppfileNew() ) ); + connect( btn_suppfile_add, SIGNAL(clicked()), this, SLOT( suppfileAdd() ) ); + connect( btn_suppfile_rmv, SIGNAL(clicked()), this, SLOT( suppfileRemove() ) ); + butts1_vbox->addWidget( btn_suppfile_up ); + butts1_vbox->addWidget( btn_suppfile_dwn ); + butts1_vbox->addWidget( btn_suppfile_new ); + butts1_vbox->addWidget( btn_suppfile_add ); + butts1_vbox->addWidget( btn_suppfile_rmv ); + butts1_vbox->addStretch( 1 ); + butts1_groupbox->setLayout( butts1_vbox ); + // setup horizontal layout + suppfile_hbox->addWidget( lbSel->widget() ); + suppfile_hbox->addWidget( butts1_groupbox ); + suppfile_groupbox->setLayout( suppfile_hbox ); + // tabSupps - suppressions + QGroupBox* supps_groupbox = new QGroupBox(); + QHBoxLayout* supps_hbox = new QHBoxLayout(); + supps_hbox->setObjectName( QString::fromUtf8( "supps_hbox" ) ); + supps_hbox->setMargin(0); + // listview + lwSupps = new QListWidget( supps_groupbox ); + lwSupps->setObjectName( QString::fromUtf8( "list_widget_supps" ) ); + lwSupps->setSelectionMode( QAbstractItemView::SingleSelection );//QListWidget::Single ); + ContextHelp::addHelp( lwSupps, urlValkyrie::suppsTab ); + connect( lwSupps, SIGNAL(currentRowChanged(int)), this, SLOT(setSuppBtns()) ); + connect( lwSupps, SIGNAL(itemDoubleClicked(QListWidgetItem*)), + this, SLOT(suppEdit(QListWidgetItem*)) ); + // buttongroup + QWidget* butts_groupbox = new QWidget(); + QVBoxLayout* butts_vbox = new QVBoxLayout(); + butts_vbox->setObjectName( QString::fromUtf8( "butts_vbox" ) ); + butts_vbox->setMargin(0); + btn_supp_new = new QPushButton("New", butts_groupbox ); + btn_supp_edt = new QPushButton("Edit", butts_groupbox ); + btn_supp_del = new QPushButton("Delete", butts_groupbox ); + suppLoad(); + connect( btn_supp_new, SIGNAL(clicked()), this, SLOT( suppNew() ) ); + connect( btn_supp_edt, SIGNAL(clicked()), this, SLOT( suppEdit() ) ); + connect( btn_supp_del, SIGNAL(clicked()), this, SLOT( suppDelete() ) ); + butts_vbox->addWidget( btn_supp_new ); + butts_vbox->addWidget( btn_supp_edt ); + butts_vbox->addWidget( btn_supp_del ); + butts_vbox->addStretch( 1 ); + butts_groupbox->setLayout( butts_vbox ); + // setup horizontal layout + supps_hbox->addWidget( lwSupps ); + supps_hbox->addWidget( butts_groupbox ); + supps_groupbox->setLayout( supps_hbox ); + // tabSupps - Add everything to our top vbox layout + QVBoxLayout* suppressions_vlayout = new QVBoxLayout(); + suppressions_vlayout->setObjectName( QString::fromUtf8( "suppfile_vlayout" ) ); + suppressions_vlayout->addWidget( suppfile_groupbox ); + suppressions_vlayout->addWidget( supps_groupbox ); + tabSupps->setLayout( suppressions_vlayout ); + + // ============================================================ // Disabled Widgets /* These widgets are disabled because Valkyrie uses @@ -245,12 +323,11 @@ m_itemList[VALGRIND::VERBOSITY ]->setEnabled( false ); m_itemList[VALGRIND::TRACK_FDS ]->setEnabled( false ); m_itemList[VALGRIND::EM_WARNS ]->setEnabled( false ); - m_itemList[VALGRIND::GEN_SUPP ]->setEnabled( false ); m_itemList[VALGRIND::ERROR_LIMIT]->setEnabled( false ); m_itemList[VALGRIND::DB_ATTACH ]->setEnabled( false ); m_itemList[VALGRIND::DB_COMMAND ]->setEnabled( false ); dbLedit->button()->setEnabled( false ); - + vk_assert( m_itemList.count() <= VALGRIND::NUM_OPTS ); } @@ -261,6 +338,211 @@ } + + + +//--------------------------------------------------------------------- +// Suppression routines +void ValgrindOptionsPage::setSuppFileBtns() +{ + QListWidget* lwSuppFiles = (QListWidget*)m_itemList[VALGRIND::SUPPS_SEL]->widget(); + + if ( lwSuppFiles->currentItem() != 0 ) { + btn_suppfile_rmv->setEnabled( true ); + btn_suppfile_up->setEnabled( lwSuppFiles->currentRow() > 0 ); + btn_suppfile_dwn->setEnabled( lwSuppFiles->currentRow() < lwSuppFiles->count()-1 ); + } + else { + btn_suppfile_rmv->setEnabled( false ); + btn_suppfile_up->setEnabled( false ); + btn_suppfile_dwn->setEnabled( false ); + } +} + +void ValgrindOptionsPage::suppfileUp() +{ + QListWidget* lwSuppFiles = (QListWidget*)m_itemList[VALGRIND::SUPPS_SEL]->widget(); + int currRow = lwSuppFiles->currentRow(); + + QListWidgetItem* item = lwSuppFiles->takeItem( currRow ); + lwSuppFiles->insertItem( currRow-1, item ); + lwSuppFiles->setCurrentItem( item ); +} + +void ValgrindOptionsPage::suppfileDown() +{ + QListWidget* lwSuppFiles = (QListWidget*)m_itemList[VALGRIND::SUPPS_SEL]->widget(); + int currRow = lwSuppFiles->currentRow(); + + QListWidgetItem* item = lwSuppFiles->takeItem( currRow ); + lwSuppFiles->insertItem( currRow+1, item ); + lwSuppFiles->setCurrentItem( item ); +} + +void ValgrindOptionsPage::suppfileNew() +{ + LbWidget* lbSel = ( LbWidget* )m_itemList[VALGRIND::SUPPS_SEL]; + QListWidget* lwSuppFiles = (QListWidget*)lbSel->widget(); + + QString supp_file = + QFileDialog::getSaveFileName( this, + tr( "Enter Supporessions Filename" ), + "./", tr("Suppression Files (*.supp)") ); + + if ( supp_file.isEmpty() ) { // user clicked Cancel + // ignore. + } + else { + // create clean suppfile, add filename to view and opt_list + if ( supplist.initSuppsFile( supp_file ) ) { + lwSuppFiles->addItem( supp_file ); + lwSuppFiles->setCurrentRow( lwSuppFiles->count()-1 ); + } + else { + vkPrintErr("Failed to write suppressions file '%s'", qPrintable(supp_file)); + // TODO: file write error: tell user + } + } +} + + +void ValgrindOptionsPage::suppfileAdd() +{ + LbWidget* lbSel = ( LbWidget* )m_itemList[VALGRIND::SUPPS_SEL]; + QListWidget* lwSuppFiles = (QListWidget*)lbSel->widget(); + + QString supp_file = + QFileDialog::getOpenFileName( this, + tr( "Choose Suppression File" ), + "./", tr("Suppression Files (*.supp)") ); + + if ( ! supp_file.isEmpty() ) { // user clicked Cancel ? + lwSuppFiles->addItem( supp_file ); + lwSuppFiles->setCurrentRow( lwSuppFiles->count()-1 ); + } +} + +void ValgrindOptionsPage::suppfileRemove() +{ + LbWidget* lbSel = ( LbWidget* )m_itemList[VALGRIND::SUPPS_SEL]; + QListWidget* lwSuppFiles = (QListWidget*)lbSel->widget(); + + QListWidgetItem* item = lwSuppFiles->currentItem(); + vk_assert( item ); + + lwSuppFiles->takeItem( lwSuppFiles->row( item ) ); + + setSuppFileBtns(); +} + + + +void ValgrindOptionsPage::setSuppBtns() +{ + QListWidget* lwFiles = (QListWidget*)m_itemList[VALGRIND::SUPPS_SEL]->widget(); + bool suppfileSelected = (lwFiles->currentItem() != 0); + bool suppItemSelected = (lwSupps->currentItem() != 0); + + btn_supp_new->setEnabled( suppfileSelected ); + btn_supp_edt->setEnabled( suppfileSelected && suppItemSelected ); + btn_supp_del->setEnabled( suppfileSelected && suppItemSelected ); +} + +void ValgrindOptionsPage::suppLoad() +{ + QListWidget* lwFiles = (QListWidget*)m_itemList[VALGRIND::SUPPS_SEL]->widget(); + bool suppfileSelected = (lwFiles->currentItem() != 0); + + // first clear the last entries + lwSupps->clear(); + supplist.clear(); + + if ( suppfileSelected ) { // show the suppression names from the file + QString fname = lwFiles->currentItem()->text(); + if (!supplist.readSuppFile( fname )) { + // TODO: error + vkPrintErr("Failed to read/parse supp file '%s'", qPrintable(fname)); + return; + } + lwSupps->addItems( supplist.suppNames() ); + lwSupps->setCurrentRow( 0 ); + } + + setSuppBtns(); +} + +// +void ValgrindOptionsPage::setCurrentTab( int idx ) +{ + tabWidget->setCurrentIndex( idx ); +} + + +// add supp from string, pass to editor, save if ok +void ValgrindOptionsPage::suppNewFromStr( const QString& str ) +{ + Suppression supp; + if ( !supp.fromStringList( str.split("\n") ) ) { + // TODO: err + vkPrintErr("Failed to parse supp from input string '%s'", qPrintable(str)); + return; + } + + // Edit new supp: update model and suppfile first... + if ( supplist.editSupp( -1, supp ) ) { + // ... then update the view + lwSupps->addItem( supplist.suppNames().last() ); + lwSupps->setCurrentRow( lwSupps->count()-1 ); + } +} + + +// create default supp, pass to editor, save if ok +void ValgrindOptionsPage::suppNew() +{ + // New supp: update model and suppfile first... + if ( supplist.newSupp() ) { + // then update the view + lwSupps->addItem( supplist.suppNames().last() ); + lwSupps->setCurrentRow( lwSupps->count()-1 ); + } +} + +// pass supp to editor, save to file +void ValgrindOptionsPage::suppEdit( QListWidgetItem* ) +{ + // currentRow() already updated, so just use that + suppEdit(); +} + +// pass supp to editor, save to file +void ValgrindOptionsPage::suppEdit() +{ + int suppIdx = lwSupps->currentRow(); + vk_assert( suppIdx != -1 ); + + // Edit supp: + if ( supplist.editSupp( suppIdx ) ) { + // then update the view + lwSupps->currentItem()->setText( supplist.suppNames().at(suppIdx) ); + lwSupps->setCurrentRow( suppIdx ); + } +} + +// delete supp from file, view, list +void ValgrindOptionsPage::suppDelete() +{ + int suppIdx = lwSupps->currentRow(); + vk_assert( suppIdx != -1 ); + + // Delete supp: update model and suppfile first... + if ( supplist.deleteSupp( suppIdx ) ) { + // then update the view + lwSupps->takeItem( suppIdx ); + } +} + + #if 0 //TODO { if ((( QListWidget* )lbSel->widget() )->count() < VG_CLO_MAX_SFILES ) { @@ -274,3 +556,5 @@ } } #endif + + Modified: trunk/src/options/valgrind_options_page.h =================================================================== --- trunk/src/options/valgrind_options_page.h 2011-06-24 12:31:13 UTC (rev 531) +++ trunk/src/options/valgrind_options_page.h 2011-06-27 14:30:50 UTC (rev 532) @@ -22,9 +22,12 @@ #define __VALGRIND_OPTIONS_PAGE_H #include <QGroupBox> +#include <QListWidget> +#include <QPushButton> #include <QStringList> #include "options/vk_options_page.h" +#include "options/suppressions.h" // ============================================================ @@ -34,15 +37,43 @@ public: ValgrindOptionsPage( VkObject* obj ); + void setCurrentTab( int idx ); + void suppNewFromStr( const QString& str ); + +public slots: + void suppNew(); + void suppEdit(); + private slots: void getDbBin(); + void setSuppFileBtns(); + void suppfileNew(); + void suppfileAdd(); + void suppfileRemove(); + void suppfileUp(); + void suppfileDown(); + void setSuppBtns(); + void suppLoad(); + void suppEdit( QListWidgetItem* ); + void suppDelete(); private: void setupOptions(); private: + QTabWidget* tabWidget; QGroupBox* group1; - + QListWidget* lwSupps; + QPushButton* btn_suppfile_up; + QPushButton* btn_suppfile_dwn; + QPushButton* btn_suppfile_new; + QPushButton* btn_suppfile_add; + QPushButton* btn_suppfile_rmv; + QPushButton* btn_supp_new; + QPushButton* btn_supp_edt; + QPushButton* btn_supp_del; + + SuppList supplist; }; Modified: trunk/src/options/vk_options_dialog.cpp =================================================================== --- trunk/src/options/vk_options_dialog.cpp 2011-06-24 12:31:13 UTC (rev 531) +++ trunk/src/options/vk_options_dialog.cpp 2011-06-27 14:30:50 UTC (rev 532) @@ -103,6 +103,14 @@ } +QWidget* VkOptionsDialog::setCurrentPage( int idx ) +{ + optionPages->setCurrentIndex( idx ); + contentsListWidget->setCurrentRow( idx ); + + return optionPages->currentWidget(); +} + /*! A return/enter keypress in an option widget isn't eaten up by that widgets' event handler - it's propogated to the QDialog parent. Modified: trunk/src/options/vk_options_dialog.h =================================================================== --- trunk/src/options/vk_options_dialog.h 2011-06-24 12:31:13 UTC (rev 531) +++ trunk/src/options/vk_options_dialog.h 2011-06-27 14:30:50 UTC (rev 532) @@ -37,6 +37,9 @@ VkOptionsDialog( QWidget* ); ~VkOptionsDialog(); + // setup and return new current page + QWidget* setCurrentPage( int idx ); + private: void setupLayout(); void keyPressEvent( QKeyEvent* event ); // overloaded Modified: trunk/src/options/vk_options_page.h =================================================================== --- trunk/src/options/vk_options_page.h 2011-06-24 12:31:13 UTC (rev 531) +++ trunk/src/options/vk_options_page.h 2011-06-27 14:30:50 UTC (rev 532) @@ -68,6 +68,8 @@ void rejectEdits(); bool applyEdits(); bool isModified() { return m_mod; } + + static QFrame* sep( QWidget* parent ); signals: void modified(); @@ -79,7 +81,6 @@ protected: OptionWidget* insertOptionWidget( int optid, QWidget* parent, bool mklabel ); - QFrame* sep( QWidget* parent ); protected: bool m_mod; Added: trunk/src/options/vk_suppressions_dialog.cpp =================================================================== --- trunk/src/options/vk_suppressions_dialog.cpp (rev 0) +++ trunk/src/options/vk_suppressions_dialog.cpp 2011-06-27 14:30:50 UTC (rev 532) @@ -0,0 +1,322 @@ +/**************************************************************************** +** VkSuppressionsDialog implementation +** -------------------------------------------------------------------------- +** +** Copyright (C) 2000-2011, OpenWorks LLP. All rights reserved. +** <in...@op...> +** +** This file is part of Valkyrie, a front-end for Valgrind. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 as published by the Free Software Foundation +** and appearing in the file COPYING included in the packaging of +** this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +#include "help/help_context.h" +#include "help/help_urls.h" +#include "options/suppressions.h" +#include "options/vk_suppressions_dialog.h" +#include "options/vk_options_page.h" +#include "utils/vk_utils.h" + +#include <QApplication> +#include <QDialogButtonBox> +#include <QFontMetrics> +#include <QScrollArea> + + +#define SIZE_COL1 "XXXXXXXXX" // for a font-dependent size + + +/*! + class CallChainFrame +*/ +SuppFrame::SuppFrame( bool isFirstFrame, QWidget* parent ) + : QWidget( parent ) +{ + setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Preferred ); + + QFontMetrics fm( qApp->font() ); + int width_col1 = fm.width( SIZE_COL1 ); + width_col1 -= 5; // compensate for margin of central widget + + QHBoxLayout* topHLayout = new QHBoxLayout( this ); + topHLayout->setObjectName( QString::fromUtf8( "topHLayout" ) ); + topHLayout->setMargin(0); + + frame_cmb = new QComboBox(); + frame_cmb->setMinimumWidth( width_col1 ); + frame_cmb->addItems( SuppRanges::instance()->frameTypes ); + + frame_le = new QLineEdit(); + + frame_but = new QPushButton("-"); + if ( isFirstFrame ) frame_but->hide(); + frame_but->setFixedWidth( 30 ); + connect( frame_but, SIGNAL(clicked()), this, SLOT(buttClicked()) ); + + topHLayout->addWidget( frame_cmb ); + topHLayout->addWidget( frame_le ); + topHLayout->addWidget( frame_but ); +} + +void SuppFrame::buttClicked() +{ + emit removeFrame( this ); +} + + + + + +/*! + class VkSuppressionsDialog +*/ +VkSuppressionsDialog::VkSuppressionsDialog( QWidget *parent ) + : QDialog( parent ) +{ + setObjectName( QString::fromUtf8( "VkSuppressionsDialog" ) ); + setWindowTitle( "Valkyrie Suppressions Dialog" ); + + QIcon icon_vk; + icon_vk.addPixmap( QPixmap( QString::fromUtf8( ":/vk_icons/icons/valkyrie.xpm" ) ), QIcon::Normal, QIcon::Off ); + setWindowIcon( icon_vk ); + + setMinimumWidth( 500 ); // allow reasonable length paths + + setupLayout(); + + ContextHelp::addHelp( this, urlValkyrie::optsDlg ); +} + + +void VkSuppressionsDialog::setupLayout() +{ + QFontMetrics fm( qApp->font() ); + int width_col1 = fm.width( SIZE_COL1 ); + + // ------------------------------------------------------------ + QVBoxLayout* topVLayout = new QVBoxLayout( this ); + topVLayout->setObjectName( QString::fromUtf8( "topVLayout" ) ); + setLayout( topVLayout ); + + // ------------------------------------------------------------ + QWidget* layoutWidget = new QWidget( this ); + layoutWidget->setObjectName( QString::fromUtf8( "layoutWidget" ) ); + topVLayout->addWidget( layoutWidget, 0 ); + + // Note: not using opt_widget->hlayout()'s as button width won't match qlabel width. + QGridLayout* gridLayout = new QGridLayout( layoutWidget ); + gridLayout->setColumnStretch( 0, 0 ); + gridLayout->setColumnStretch( 1, 1 ); + gridLayout->setColumnMinimumWidth( 0, width_col1 ); + gridLayout->setMargin(0); + + // ------------------------------------------------------------ + // Name + QLabel* name_lbl = new QLabel("Name:"); + name_le = new QLineEdit(); + + // Kind-Tool + QLabel* tool_lbl = new QLabel("Kind-Tool:"); + tool_cmb = new QComboBox(); + tool_cmb->addItems( SuppRanges::instance()->kindTools ); + connect( tool_cmb, SIGNAL(currentIndexChanged(int)), this, SLOT(ToolChanged(int)) ); + + // Kind-Type + QLabel* type_lbl = new QLabel("Kind-Type:"); + type_cmb = new QComboBox(); + connect( type_cmb, SIGNAL(currentIndexChanged(int)), this, SLOT(TypeChanged(int)) ); + + // Kind-Aux + kaux_lbl = new QLabel("Kind-Aux:"); + kaux_le = new QLineEdit(); + + // Trigger Tool change setup Type and Aux + ToolChanged( 0 ); + + // (start of) Call chain + QLabel* cchn_lbl = new QLabel("Call Chain:"); + QPushButton* cchn_but = new QPushButton("Add Frame"); + connect( cchn_but, SIGNAL(clicked()), this, SLOT(addNewSuppFrame()) ); + + QWidget* pb_addFrame = new QWidget(); + QHBoxLayout* hLayout = new QHBoxLayout( pb_addFrame ); + hLayout->setMargin(0); + hLayout->addWidget( cchn_but ); + hLayout->addStretch(10); + + // ------------------------------------------------------------ + // layout + int i = 0; + // gridLayout->setRowMinimumHeight( i++, lineHeight / 2 ); // blank row + gridLayout->addWidget( name_lbl, i, 0, Qt::AlignRight ); + gridLayout->addWidget( name_le, i++, 1 ); + + gridLayout->addWidget( VkOptionsPage::sep( layoutWidget ), i++, 0, 1, 2 ); + + gridLayout->addWidget( tool_lbl, i, 0, Qt::AlignRight ); + gridLayout->addWidget( tool_cmb, i++, 1 ); + gridLayout->addWidget( type_lbl, i, 0, Qt::AlignRight ); + gridLayout->addWidget( type_cmb, i++, 1 ); + gridLayout->addWidget( kaux_lbl, i, 0, Qt::AlignRight ); + gridLayout->addWidget( kaux_le, i++, 1 ); + + gridLayout->addWidget( VkOptionsPage::sep( layoutWidget ), i++, 0, 1, 2 ); + + gridLayout->addWidget( cchn_lbl, i, 0, Qt::AlignRight ); + gridLayout->addWidget( pb_addFrame, i++, 1, 1, 2 ); + + // ------------------------------------------------------------ + // scrollarea for call chain + QScrollArea* scroll = new QScrollArea( this ); + scroll->setObjectName( QString::fromUtf8( "scroll" ) ); + topVLayout->addWidget( scroll, 1 ); + + callChainLayout = new QVBoxLayout( scroll ); + callChainLayout->setObjectName( QString::fromUtf8( "callChainLayout" ) ); + callChainLayout->setMargin(5); + // this needed else internal widgets resize to nothing! + callChainLayout->setSizeConstraint( QLayout::SetMinAndMaxSize ); + + QWidget* callChainWidget = new QWidget( scroll ); + callChainWidget->setObjectName( QString::fromUtf8( "callChainWidget" ) ); + callChainWidget->setLayout( callChainLayout ); + + scroll->setWidget( callChainWidget ); + scroll->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); + scroll->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOn ); + scroll->setMinimumHeight( 200 ); + scroll->setFrameStyle( QFrame::Box | QFrame::Plain ); + // allow internal widgets to resize when needed + scroll->setWidgetResizable(true); + + // call chain (always have at least ONE frame) + SuppFrame* suppFrm = new SuppFrame( true/*isFirst*/ ); + suppFrames.append( suppFrm ); + callChainLayout->addWidget( suppFrm ); + + // ------------------------------------------------------------ + // *** other suppFrames dynimically placed here *** + + // push frames to top of scrollarea + callChainLayout->addStretch( 1 ); + + // ------------------------------------------------------------ + // Standard buttons: Ok, Cancel + QDialogButtonBox* buttbox = new QDialogButtonBox(); + buttbox->setObjectName( QString::fromUtf8( "buttbox" ) ); + buttbox->setOrientation( Qt::Horizontal ); + buttbox->setStandardButtons( QDialogButtonBox::Ok | + QDialogButtonBox::Cancel ); + + QPushButton* pb_ok1 = buttbox->button( QDialogButtonBox::Ok ); + QPushButton* pb_cancel1 = buttbox->button( QDialogButtonBox::Cancel ); + connect( pb_ok1, SIGNAL( clicked() ), this, SLOT( accept() ) ); + connect( pb_cancel1, SIGNAL( clicked() ), this, SLOT( reject() ) ); + + topVLayout->addWidget( buttbox, 0 ); +} + +void VkSuppressionsDialog::addNewSuppFrame() +{ + if ( suppFrames.count() >= MAX_SUPP_FRAMES ) { + vkPrintErr("Maximum allowed number of frames reached."); + return; + } + + // add new frame just above our 'add frame' button + SuppFrame* frm = new SuppFrame( false ); + suppFrames.append( frm ); + // last widget in callchain is a 'stretch': insert before that. + callChainLayout->insertWidget( callChainLayout->count()-1, frm ); + connect( frm, SIGNAL(removeFrame(SuppFrame*)), + this, SLOT(removeSuppFrame(SuppFrame*)) ); +} + +void VkSuppressionsDialog::removeSuppFrame( SuppFrame* frm ) +{ + callChainLayout->removeWidget( frm ); + suppFrames.removeAll( frm ); + delete frm; +} + +void VkSuppressionsDialog::ToolChanged( int idx ) +{ + type_cmb->clear(); + type_cmb->addItems( SuppRanges::instance()->kindTypes[idx] ); +} + +void VkSuppressionsDialog::TypeChanged( int ) +{ + QRegExp re("^Param$", Qt::CaseInsensitive); + bool hasAux = type_cmb->currentText().contains(re); + kaux_lbl->setEnabled( hasAux ); + kaux_le->setEnabled( hasAux ); +} + + +void VkSuppressionsDialog::setSupp( const Suppression& supp ) +{ + // Name + name_le->setText( supp.getName() ); + + // Kind + QStringList kind = supp.getKind().split(":"); + vk_assert( kind.count() == 2 ); + tool_cmb->setCurrentIndex( tool_cmb->findText(kind[0], Qt::MatchExactly) ); + type_cmb->setCurrentIndex( type_cmb->findText(kind[1], Qt::MatchExactly) ); + + // Kaux + if ( !supp.getKAux().isEmpty() ) + kaux_le->setText( supp.getKAux() ); + + // Call-Chain + QStringList frames = supp.getFrames(); + vk_assert( frames.count() > 0 ); + for (int i=0; i<frames.count(); i++) { + // new widgets for new frames, apart from first + if ( i>0) addNewSuppFrame(); + + QStringList frame = frames.at(i).split(":"); + vk_assert( frame.count() == 2 ); + + QComboBox* cmb = suppFrames[i]->frame_cmb; + cmb->setCurrentIndex( cmb->findText( frame[0], Qt::MatchExactly ) ); + QLineEdit* le = suppFrames[i]->frame_le; + le->setText( frame[1] ); + } +} + +const Suppression VkSuppressionsDialog::getUpdatedSupp() +{ + Suppression supp; + + // Name + QString name = name_le->text(); + supp.setName( name.isEmpty() ? "<unknown>" : name ); + + // Kind + supp.setKind( tool_cmb->currentText() + ":" + type_cmb->currentText() ); + + // Kaux + if ( kaux_le->isEnabled() && !kaux_le->text().isEmpty() ) + supp.setKindAux( kaux_le->text() ); + + // Call Chain + for (int i=0; i<suppFrames.count(); i++) { + QString type = suppFrames[i]->frame_cmb->currentText(); + QString data = suppFrames[i]->frame_le->text(); + if ( i==0 && data.isEmpty() ) + data = "<unknown>"; + if ( !data.isEmpty() ) + supp.addFrame( type + ":" + data ); + } + + return supp; +} Added: trunk/src/options/vk_suppressions_dialog.h =================================================================== --- trunk/src/options/vk_suppressions_dialog.h (rev 0) +++ trunk/src/options/vk_suppressions_dialog.h 2011-06-27 14:30:50 UTC (rev 532) @@ -0,0 +1,85 @@ +/**************************************************************************** +** VkSuppressionsDialog definition +** -------------------------------------------------------------------------- +** +** Copyright (C) 2000-2011, OpenWorks LLP. All rights reserved. +** <in...@op...> +** +** This file is part of Valkyrie, a front-end for Valgrind. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 as published by the Free Software Foundation +** and appearing in the file COPYING included in the packaging of +** this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +#ifndef VK_SUPPRESSIONS_DIALOG_H +#define VK_SUPPRESSIONS_DIALOG_H + +#include <QComboBox> +#include <QDialog> +#include <QLabel> +#include <QLineEdit> +#include <QPushButton> +#include <QVBoxLayout> + + +// ============================================================ +class SuppFrame : public QWidget +{ + Q_OBJECT +public: + SuppFrame( bool isFirst, QWidget* parent=0 ); + +signals: + void removeFrame( SuppFrame* w ); + +private: + SuppFrame(); + +private slots: + void buttClicked(); + +public: + QComboBox* frame_cmb; + QLineEdit* frame_le; + QPushButton* frame_but; +}; + + +// ============================================================ +class Suppression; +class VkSuppressionsDialog : public QDialog +{ + Q_OBJECT +public: + VkSuppressionsDialog(QWidget *parent = 0); + + void setSupp( const Suppression& supp ); + const Suppression getUpdatedSupp(); + +private: + void setupLayout(); + +private slots: + void addNewSuppFrame(); + void removeSuppFrame( SuppFrame* w ); + void ToolChanged( int idx ); + void TypeChanged( int idx ); + +private: + QVBoxLayout* callChainLayout; + + QLineEdit* name_le; + QComboBox* tool_cmb; + QComboBox* type_cmb; + QLabel* kaux_lbl; + QLineEdit* kaux_le; + QList<SuppFrame*> suppFrames; +}; + +#endif // VK_SUPPRESSIONS_DIALOG_H Modified: trunk/src/options/widgets/opt_lb_widget.cpp =================================================================== --- trunk/src/options/widgets/opt_lb_widget.cpp 2011-06-24 12:31:13 UTC (rev 531) +++ trunk/src/options/widgets/opt_lb_widget.cpp 2011-06-27 14:30:50 UTC (rev 532) @@ -32,53 +32,48 @@ /***************************************************************************/ /*! - Constructs a LbWidget object - has-a QListBox - - Note: This widget was specifically written to handle suppression files - stuff and nothing else. + class MyListWidget + - sends signals for row add/delete */ +void MyListWidget::rowsInserted(const QModelIndex &parent, int start, int end) +{ + vk_assert( start == end ); + QListWidget::rowsInserted(parent, start, end); + emit rowsChanged( true, start ); +} -static const char* sel_supp_xpm[] = { - "11 11 8 1", - " c None", - ". c #024266", - "+ c #5A9AB8", - "@ c #1B5F8E", - "# c #79B7CD", - "$ c #5A97B5", - "% c #AEDDE9", - "& c #8ECADC", - " . ", - " . .+. . ", - " .+.@#@.+. ", - " .#$%$#. ", - " .@$&%&$@. ", - ".+#%%%%%#+.", - " .@$&%&$@. ", - " .#$%$#. ", - " .+.@#@.+. ", - " . .+. . ", - " . " -}; +void MyListWidget::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) +{ + vk_assert( start == end ); + QListWidget::rowsAboutToBeRemoved(parent, start, end); + emit rowsChanged( false, start ); +} + +/*! + Constructs a LbWidget object + has-a QListWidget + + Note: This widget was specifically written to handle suppression files + stuff and nothing else. This because of the difference in stored + (with comma's, for opt) and displayed (list) +*/ LbWidget::LbWidget( QWidget* parent, VkOption* vkopt, bool mklabel ) : OptionWidget( parent, vkopt, mklabel ) { this->setObjectName( "lb_widget" ); - m_lbox = new QListWidget( parent ); + m_lbox = new MyListWidget( parent ); m_lbox->setObjectName( QString::fromUtf8( "list_box" ) ); m_widg = m_lbox; - m_lbox->setSelectionMode( QAbstractItemView::SingleSelection );//QListWidget::Single ); + m_lbox->setSelectionMode( QAbstractItemView::SingleSelection ); + connect( m_lbox, SIGNAL(rowsChanged(bool,int)), + this, SLOT(updateValueFromView(bool, int))); m_sep = VkCfg::sepChar(); update( m_currentValue ); - m_lbox->setContextMenuPolicy( Qt::CustomContextMenu ); - connect( m_lbox, SIGNAL( customContextMenuRequested( const QPoint& ) ), - this, SLOT( popupMenu( const QPoint& ) ) ); // not added if the url is empty ContextHelp::addHelp( m_widg, m_opt->urlAddress ); @@ -107,66 +102,35 @@ for ( int i = 0; i < sfiles.count(); i++ ) { m_lbox->addItem( sfiles[i] ); } -} - -/*! - Pretty print current value -*/ -QString LbWidget::printCurrValue() -{ - return "For one (or more) of:<br>" + currValue().replace( m_sep, "<br>" ); + // auto-select the top row + m_lbox->setCurrentRow( 0 ); } /*! - return all contents concat'd with m_sep -*/ -QString LbWidget::lbText() + Update underlying value from lbox + Triggered by signals rowsInserted, rowsToBeDeleted + - inserted row is easy: just concat the items + - to_be_deleted row isn't yet gone: skip that row. + */ +void LbWidget::updateValueFromView( bool isInserted, int row ) { QStringList items; - - for ( int i = 0; i < m_lbox->count(); i++ ) { + for ( int i=0; i < m_lbox->count(); i++ ) { + if (!isInserted && i == row) continue; // 'row' is to be removed items += m_lbox->item( i )->text(); } - - return ( items.count() == 0 ) ? "" : items.join( m_sep ); + QString listViewText = items.join( m_sep ); + + setCurrValue( listViewText ); } /*! - different menus and stuff for the different modes + Pretty print current value */ -void LbWidget::popupMenu( const QPoint& pos ) +QString LbWidget::printCurrValue() { - QListWidgetItem* lb_item = m_lbox->itemAt( pos ); - - QAction actRemove( QPixmap( sel_supp_xpm ), "Remove File", this ); - QAction actAdd( QPixmap( sel_supp_xpm ), "Add File", this ); - - if ( !lb_item ) { - actRemove.setEnabled( false ); - } - - QMenu menu( m_lbox ); - menu.addAction( &actRemove ); - menu.addAction( &actAdd ); - QAction* act = menu.exec( m_lbox->mapToGlobal( pos ) ); - - if ( act == &actRemove ) { - vk_assert( lb_item ); - m_lbox->takeItem( m_lbox->row( lb_item ) ); - setCurrValue( lbText() ); - } - else if ( act == &actAdd ) { - QString supp_file = - QFileDialog::getOpenFileName( m_lbox, - tr( "Choose Suppression File" ), - "./", tr("Suppression Files (*.supp)") ); - - if ( ! supp_file.isEmpty() ) { // user clicked Cancel ? - m_lbox->addItem( supp_file ); - setCurrValue( lbText() ); - } - } + return "For one (or more) of:<br>" + currValue().replace( m_sep, "<br>" ); } Modified: trunk/src/options/widgets/opt_lb_widget.h =================================================================== --- trunk/src/options/widgets/opt_lb_widget.h 2011-06-24 12:31:13 UTC (rev 531) +++ trunk/src/options/widgets/opt_lb_widget.h 2011-06-27 14:30:50 UTC (rev 532) @@ -26,6 +26,26 @@ // ============================================================ +// reimplementation of QListWidget, in order to catch row changes +class MyListWidget : public QListWidget +{ + Q_OBJECT +public: + MyListWidget( QWidget* parent = 0 ) : QListWidget( parent ) {} +private: + MyListWidget( const MyListWidget& lw ); + +signals: + void rowsChanged( bool, int ); + +protected slots: + void rowsInserted(const QModelIndex &parent, int start, int end); + void rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end); +}; + + + +// ============================================================ // listbox widget - for lists of files class LbWidget : public OptionWidget { @@ -37,16 +57,12 @@ QString printCurrValue(); // overloads base class private slots: - void popupMenu( const QPoint& ); void update( const QString& txt ); + void updateValueFromView( bool isInserted, int row ); private: - QString lbText(); - void lbChanged(); - -private: - QListWidget* m_lbox; - QChar m_sep; + MyListWidget* m_lbox; + QChar m_sep; }; #endif // __VK_OPTION_LB_WIDGET_H Modified: trunk/src/src.pro =================================================================== --- trunk/src/src.pro 2011-06-24 12:31:13 UTC (rev 531) +++ trunk/src/src.pro 2011-06-27 14:30:50 UTC (rev 532) @@ -52,11 +52,13 @@ objects/vk_objects.cpp \ options/helgrind_options_page.cpp \ options/memcheck_options_page.cpp \ + options/suppressions.cpp \ options/vk_option.cpp \ options/vk_options_dialog.cpp \ options/vk_options_page.cpp \ options/vk_parse_cmdline.cpp \ options/vk_popt.cpp \ + options/vk_suppressions_dialog.cpp \ options/valgrind_options_page.cpp \ options/valkyrie_options_page.cpp \ options/widgets/opt_base_widget.cpp \ @@ -91,6 +93,7 @@ objects/vk_objects.h \ options/helgrind_options_page.h \ options/memcheck_options_page.h \ + options/suppressions.h \ options/vk_option.h \ options/vk_options_dialog.h \ options/vk_options_page.h \ @@ -98,6 +101,7 @@ options/vk_popt.h \ options/valgrind_options_page.h \ options/valkyrie_options_page.h \ + options/vk_suppressions_dialog.h \ options/widgets/opt_base_widget.h \ options/widgets/opt_cb_widget.h \ options/widgets/opt_ck_widget.h \ Modified: trunk/src/toolview/memcheckview.cpp =================================================================== --- trunk/src/toolview/memcheckview.cpp 2011-06-24 12:31:13 UTC (rev 531) +++ trunk/src/toolview/memcheckview.cpp 2011-06-27 14:30:50 UTC (rev 532) @@ -18,6 +18,11 @@ ** ****************************************************************************/ +#include "mainwindow.h" +#include "options/suppressions.h" +#include "options/vk_options_dialog.h" +#include "options/valgrind_options_page.h" +#include "options/vk_suppressions_dialog.h" #include "toolview/memcheckview.h" #include "toolview/memcheck_logview.h" #include "utils/vk_config.h" @@ -26,11 +31,13 @@ #include <QAction> #include <QApplication> +#include <QClipboard> #include <QFileDialog> #include <QHeaderView> #include <QLabel> #include <QMenuBar> #include <QProcess> +#include <QTextStream> #include <QToolBar> #include <QVBoxLayout> @@ -80,6 +87,10 @@ // launch editor with src file loaded connect( treeView, SIGNAL( itemDoubleClicked( QTreeWidgetItem*, in... [truncated message content] |