|
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] |