Merge remote branch 'remotes/kimmo/loadable-project'

Conflicts:
	gui/gui.qrc
	gui/mainwindow.cpp
	gui/mainwindow.h
This commit is contained in:
Kimmo Varis 2010-08-24 20:37:51 +03:00
commit 4ccdcf0fc2
14 changed files with 493 additions and 61 deletions

12
cppcheck.cppcheck Normal file
View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="1">
<root name="."/>
<includedir>
<dir name="lib/"/>
</includedir>
<paths>
<dir name="lib/"/>
<dir name="cli/"/>
<dir name="gui/"/>
</paths>
</project>

View File

@ -1,23 +1,25 @@
<RCC>
<qresource prefix="/" >
<file>icon.png</file>
<file>images/dialog-error.png</file>
<file>images/dialog-information.png</file>
<file>images/dialog-warning.png</file>
<file>images/edit-clear.png</file>
<file>images/go-down.png</file>
<file>images/help-browser.png</file>
<file>images/media-floppy.png</file>
<file>images/preferences-system.png</file>
<file>images/process-stop.png</file>
<file>images/text-x-generic.png</file>
<file>images/view-refresh.png</file>
<file>images/showerrors.png</file>
<file>images/showstylewarnings.png</file>
<file alias="COPYING" >../COPYING</file>
<file alias="AUTHORS" >../AUTHORS</file>
<file>images/go-home.png</file>
<file>images/go-next.png</file>
<file>images/go-previous.png</file>
</qresource>
<!DOCTYPE RCC><RCC version="1.0">
<qresource>
<file>icon.png</file>
<file>images/dialog-error.png</file>
<file>images/dialog-information.png</file>
<file>images/dialog-warning.png</file>
<file>images/edit-clear.png</file>
<file>images/go-down.png</file>
<file>images/help-browser.png</file>
<file>images/media-floppy.png</file>
<file>images/preferences-system.png</file>
<file>images/process-stop.png</file>
<file>images/text-x-generic.png</file>
<file>images/view-refresh.png</file>
<file>images/showerrors.png</file>
<file>images/showstylewarnings.png</file>
<file>images/openproject.png</file>
<file alias="COPYING">../COPYING</file>
<file alias="AUTHORS">../AUTHORS</file>
<file>images/go-home.png</file>
<file>images/go-next.png</file>
<file>images/go-previous.png</file>
</qresource>
</RCC>

BIN
gui/images/openproject.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -74,8 +74,12 @@
<string>&amp;File</string>
</property>
<addaction name="mActionOpenXML"/>
<addaction name="separator"/>
<addaction name="mActionNewProjectFile"/>
<addaction name="mActionOpenProjectFile"/>
<addaction name="mActionEditProjectFile"/>
<addaction name="mActionCloseProjectFile"/>
<addaction name="separator"/>
<addaction name="mActionSave"/>
<addaction name="mActionQuit"/>
</widget>
@ -151,6 +155,7 @@
<bool>false</bool>
</attribute>
<addaction name="mActionCheckDirectory"/>
<addaction name="mActionOpenProjectFile"/>
<addaction name="mActionSave"/>
<addaction name="mActionRecheck"/>
<addaction name="mActionStop"/>
@ -357,6 +362,10 @@
</property>
</action>
<action name="mActionOpenProjectFile">
<property name="icon">
<iconset resource="gui.qrc">
<normaloff>:/images/openproject.png</normaloff>:/images/openproject.png</iconset>
</property>
<property name="text">
<string>Open P&amp;roject File...</string>
</property>
@ -374,6 +383,22 @@
<string>Log View</string>
</property>
</action>
<action name="mActionCloseProjectFile">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>C&amp;lose Project File</string>
</property>
</action>
<action name="mActionEditProjectFile">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>&amp;Edit Project File...</string>
</property>
</action>
</widget>
<customwidgets>
<customwidget>

View File

@ -44,7 +44,8 @@ MainWindow::MainWindow() :
mLanguages(new QActionGroup(this)),
mLogView(NULL),
mHelpWindow(NULL),
mExiting(false)
mExiting(false),
mProject(NULL)
{
mUI.setupUi(this);
mUI.mResults->Initialize(mSettings, mApplications);
@ -84,6 +85,8 @@ MainWindow::MainWindow() :
connect(mUI.mActionNewProjectFile, SIGNAL(triggered()), this, SLOT(NewProjectFile()));
connect(mUI.mActionOpenProjectFile, SIGNAL(triggered()), this, SLOT(OpenProjectFile()));
connect(mUI.mActionCloseProjectFile, SIGNAL(triggered()), this, SLOT(CloseProjectFile()));
connect(mUI.mActionEditProjectFile, SIGNAL(triggered()), this, SLOT(EditProjectFile()));
connect(mUI.mActionHelpContents, SIGNAL(triggered()), this, SLOT(OpenHelpContents()));
@ -112,6 +115,7 @@ MainWindow::~MainWindow()
{
delete mLogView;
delete mHelpWindow;
delete mProject;
}
void MainWindow::CreateLanguageMenuItems()
@ -240,6 +244,17 @@ void MainWindow::DoCheckFiles(const QStringList &files)
QStringList MainWindow::SelectFilesToCheck(QFileDialog::FileMode mode)
{
if (mProject)
{
QMessageBox msgBox(this);
msgBox.setWindowTitle(tr("Cppcheck"));
const QString msg(tr("You must close the project file before selecting new files or directories!"));
msgBox.setText(msg);
msgBox.setIcon(QMessageBox::Critical);
msgBox.exec();
return QStringList();
}
QStringList selected;
// NOTE: we use QFileDialog::getOpenFileNames() and
@ -289,48 +304,51 @@ void MainWindow::CheckDirectory()
Settings MainWindow::GetCppcheckSettings()
{
ProjectFile pfile;
ProjectFile *pfile = NULL;
Settings result;
bool projectRead = true;
if (!mCurrentDirectory.isEmpty())
if (!mCurrentDirectory.isEmpty() && !mProject)
{
// Format project filename (directory name + .cppcheck) and load
// the project file if it is found.
QStringList parts = mCurrentDirectory.split("/");
QString projfile = mCurrentDirectory + "/" + parts[parts.count() - 1] + ".cppcheck";
bool projectRead = false;
if (QFile::exists(projfile))
{
qDebug() << "Reading project file " << projfile;
projectRead = pfile.Read(projfile);
projectRead = pfile->Read(projfile);
}
}
else if (mProject)
{
pfile = mProject->GetProjectFile();
}
if (projectRead)
if (projectRead)
{
QStringList dirs = pfile->GetIncludeDirs();
QString dir;
foreach(dir, dirs)
{
QStringList dirs = pfile.GetIncludeDirs();
QString dir;
foreach(dir, dirs)
{
QString incdir;
if (!QDir::isAbsolutePath(dir))
incdir = mCurrentDirectory + "/";
incdir += dir;
incdir = QDir::cleanPath(incdir);
QString incdir;
if (!QDir::isAbsolutePath(dir))
incdir = mCurrentDirectory + "/";
incdir += dir;
incdir = QDir::cleanPath(incdir);
// include paths must end with '/'
if (!incdir.endsWith("/"))
incdir += "/";
result._includePaths.push_back(incdir.toStdString());
}
QStringList defines = pfile.GetDefines();
QString define;
foreach(define, defines)
{
if (!result.userDefines.empty())
result.userDefines += ";";
result.userDefines += define.toStdString();
}
// include paths must end with '/'
if (!incdir.endsWith("/"))
incdir += "/";
result._includePaths.push_back(incdir.toStdString());
}
QStringList defines = pfile->GetDefines();
QString define;
foreach(define, defines)
{
if (!result.userDefines.empty())
result.userDefines += ";";
result.userDefines += define.toStdString();
}
}
@ -667,6 +685,9 @@ void MainWindow::OpenHtmlHelpContents()
void MainWindow::OpenProjectFile()
{
if (mProject != NULL)
delete mProject;
const QString filter = tr("Project files (*.cppcheck);;All files(*.*)");
QString filepath = QFileDialog::getOpenFileName(this,
tr("Select Project File"),
@ -675,9 +696,38 @@ void MainWindow::OpenProjectFile()
if (!filepath.isEmpty())
{
Project prj(filepath, this);
if (prj.Open())
prj.Edit();
QFileInfo inf(filepath);
const QString filename = inf.fileName();
FormatAndSetTitle(tr("Project:") + QString(" ") + filename);
mUI.mActionCloseProjectFile->setEnabled(true);
mUI.mActionEditProjectFile->setEnabled(true);
mProject = new Project(filepath, this);
mProject->Open();
QString rootpath = mProject->GetProjectFile()->GetRootPath();
// If root path not give or "current dir" then use project file's directory
// as check path
if (rootpath.isEmpty() || rootpath == ".")
mCurrentDirectory = inf.canonicalPath();
else
mCurrentDirectory = rootpath;
QStringList paths = mProject->GetProjectFile()->GetCheckPaths();
if (!paths.isEmpty())
{
for (int i = 0; i < paths.size(); i++)
{
if (!QDir::isAbsolutePath(paths[i]))
{
QString path = mCurrentDirectory + "/";
path += paths[i];
paths[i] = QDir::cleanPath(path);
}
}
DoCheckFiles(paths);
}
}
}
@ -691,12 +741,44 @@ void MainWindow::NewProjectFile()
if (!filepath.isEmpty())
{
Project prj(filepath, this);
prj.Create();
prj.Edit();
mUI.mActionCloseProjectFile->setEnabled(true);
mUI.mActionEditProjectFile->setEnabled(true);
QFileInfo inf(filepath);
const QString filename = inf.fileName();
FormatAndSetTitle(tr("Project:") + QString(" ") + filename);
if (mProject)
delete mProject;
mProject = new Project(filepath, this);
mProject->Create();
mProject->Edit();
}
}
void MainWindow::CloseProjectFile()
{
delete mProject;
mProject = NULL;
mUI.mActionCloseProjectFile->setEnabled(false);
mUI.mActionEditProjectFile->setEnabled(false);
FormatAndSetTitle();
}
void MainWindow::EditProjectFile()
{
if (!mProject)
{
QMessageBox msg(QMessageBox::Critical,
tr("Cppcheck"),
QString(tr("No project file loaded")),
QMessageBox::Ok,
this);
msg.exec();
return;
}
mProject->Edit();
}
void MainWindow::ShowLogView()
{
if (mLogView == NULL)

View File

@ -31,9 +31,11 @@
#include "translationhandler.h"
#include "settings.h"
#include "ui_main.h"
class ThreadHandler;
class LogView;
class HelpWindow;
class Project;
/// @addtogroup GUI
/// @{
@ -140,11 +142,23 @@ public slots:
void NewProjectFile();
/**
* @brief Slot to edit existing project file.
* @brief Slot to open project file and start checking contained paths.
*
*/
void OpenProjectFile();
/**
* @brief Slot to close open project file.
*
*/
void CloseProjectFile();
/**
* @brief Slot to edit project file.
*
*/
void EditProjectFile();
/**
* @brief Slot for showing the log view.
*
@ -324,7 +338,7 @@ protected:
QString mCurrentDirectory;
/**
* @brief Log view..
* @brief Log view.
*/
LogView *mLogView;
@ -333,6 +347,11 @@ protected:
*/
HelpWindow *mHelpWindow;
/**
* @brief Project (file).
*/
Project *mProject;
private:
/**

View File

@ -77,18 +77,25 @@ bool Project::Open()
void Project::Edit()
{
ProjectFileDialog dlg(mFilename, mParentWidget);
QString root = mPFile->GetRootPath();
dlg.SetRootPath(root);
QStringList includes = mPFile->GetIncludeDirs();
dlg.SetIncludepaths(includes);
QStringList defines = mPFile->GetDefines();
dlg.SetDefines(defines);
QStringList paths = mPFile->GetCheckPaths();
dlg.SetPaths(paths);
int rv = dlg.exec();
if (rv == QDialog::Accepted)
{
QString root = dlg.GetRootPath();
mPFile->SetRootPath(root);
QStringList includes = dlg.GetIncludePaths();
mPFile->SetIncludes(includes);
QStringList defines = dlg.GetDefines();
mPFile->SetDefines(defines);
QStringList paths = dlg.GetPaths();
mPFile->SetCheckPaths(paths);
bool writeSuccess = mPFile->Write();
if (!writeSuccess)
{

View File

@ -62,6 +62,15 @@ public:
*/
void Create();
/**
* @brief Return current project file.
* @return project file.
*/
ProjectFile * GetProjectFile() const
{
return mPFile;
}
private:
QString mFilename;

View File

@ -32,6 +32,11 @@ static const char DirNameAttrib[] = "name";
static const char DefinesElementName[] = "defines";
static const char DefineName[] = "define";
static const char DefineNameAttrib[] = "name";
static const char PathsElementName[] = "paths";
static const char PathName[] = "dir";
static const char PathNameAttrib[] = "name";
static const char RootPathName[] = "root";
static const char RootPathNameAttrib[] = "name";
ProjectFile::ProjectFile(QObject *parent) :
QObject(parent)
@ -66,6 +71,13 @@ bool ProjectFile::Read(const QString &filename)
insideProject = true;
projectTagFound = true;
}
// Read root path from inside project element
if (insideProject && xmlReader.name() == RootPathName)
ReadRootPath(xmlReader);
// Find paths to check from inside project element
if (insideProject && xmlReader.name() == PathsElementName)
ReadCheckPaths(xmlReader);
// Find include directory from inside project element
if (insideProject && xmlReader.name() == IncludDirElementName)
@ -113,6 +125,19 @@ QStringList ProjectFile::GetDefines() const
return mDefines;
}
QStringList ProjectFile::GetCheckPaths() const
{
return mPaths;
}
void ProjectFile::ReadRootPath(QXmlStreamReader &reader)
{
QXmlStreamAttributes attribs = reader.attributes();
QString name = attribs.value("", RootPathNameAttrib).toString();
if (!name.isEmpty())
mRootPath = name;
}
void ProjectFile::ReadIncludeDirs(QXmlStreamReader &reader)
{
QXmlStreamReader::TokenType type;
@ -196,6 +221,48 @@ void ProjectFile::ReadDefines(QXmlStreamReader &reader)
while (!allRead);
}
void ProjectFile::ReadCheckPaths(QXmlStreamReader &reader)
{
QXmlStreamReader::TokenType type;
bool allRead = false;
do
{
type = reader.readNext();
switch (type)
{
case QXmlStreamReader::StartElement:
// Read dir-elements
if (reader.name().toString() == PathName)
{
QXmlStreamAttributes attribs = reader.attributes();
QString name = attribs.value("", PathNameAttrib).toString();
if (!name.isEmpty())
mPaths << name;
}
break;
case QXmlStreamReader::EndElement:
if (reader.name().toString() == PathsElementName)
allRead = true;
break;
// Not handled
case QXmlStreamReader::NoToken:
case QXmlStreamReader::Invalid:
case QXmlStreamReader::StartDocument:
case QXmlStreamReader::EndDocument:
case QXmlStreamReader::Characters:
case QXmlStreamReader::Comment:
case QXmlStreamReader::DTD:
case QXmlStreamReader::EntityReference:
case QXmlStreamReader::ProcessingInstruction:
break;
}
}
while (!allRead);
}
void ProjectFile::SetIncludes(QStringList includes)
{
mIncludeDirs = includes;
@ -206,6 +273,11 @@ void ProjectFile::SetDefines(QStringList defines)
mDefines = defines;
}
void ProjectFile::SetCheckPaths(QStringList paths)
{
mPaths = paths;
}
bool ProjectFile::Write(const QString &filename)
{
if (!filename.isEmpty())
@ -221,6 +293,13 @@ bool ProjectFile::Write(const QString &filename)
xmlWriter.writeStartElement(ProjectElementName);
xmlWriter.writeAttribute(ProjectVersionAttrib, ProjectFileVersion);
if (!mRootPath.isEmpty())
{
xmlWriter.writeStartElement(RootPathName);
xmlWriter.writeAttribute(RootPathNameAttrib, mRootPath);
xmlWriter.writeEndElement();
}
if (!mIncludeDirs.isEmpty())
{
xmlWriter.writeStartElement(IncludDirElementName);
@ -246,6 +325,20 @@ bool ProjectFile::Write(const QString &filename)
}
xmlWriter.writeEndElement();
}
if (!mPaths.isEmpty())
{
xmlWriter.writeStartElement(PathsElementName);
QString path;
foreach(path, mPaths)
{
xmlWriter.writeStartElement(PathName);
xmlWriter.writeAttribute(PathNameAttrib, path);
xmlWriter.writeEndElement();
}
xmlWriter.writeEndElement();
}
xmlWriter.writeEndDocument();
file.close();
return true;

View File

@ -47,6 +47,15 @@ public:
*/
bool Read(const QString &filename = QString());
/**
* @brief Get project root path.
* @return project root path.
*/
QString GetRootPath() const
{
return mRootPath;
}
/**
* @brief Get list of include directories.
* @return list of directories.
@ -59,6 +68,21 @@ public:
*/
QStringList GetDefines() const;
/**
* @brief Get list of paths to check.
* @return list of paths.
*/
QStringList GetCheckPaths() const;
/**
* @brief Set project root path.
* @param rootpath new project root path.
*/
void SetRootPath(const QString &rootpath)
{
mRootPath = rootpath;
}
/**
* @brief Set list of includes.
* @param includes List of defines.
@ -71,6 +95,12 @@ public:
*/
void SetDefines(QStringList defines);
/**
* @brief Set list of paths to check.
* @param defines List of paths.
*/
void SetCheckPaths(QStringList paths);
/**
* @brief Write project file (to disk).
* @param filename Filename to use.
@ -87,6 +117,13 @@ public:
}
protected:
/**
* @brief Read optional root path from XML.
* @param reader XML stream reader.
*/
void ReadRootPath(QXmlStreamReader &reader);
/**
* @brief Read list of include directories from XML.
* @param reader XML stream reader.
@ -99,6 +136,12 @@ protected:
*/
void ReadDefines(QXmlStreamReader &reader);
/**
* @brief Read list paths to check.
* @param reader XML stream reader.
*/
void ReadCheckPaths(QXmlStreamReader &reader);
private:
/**
@ -106,6 +149,14 @@ private:
*/
QString mFilename;
/**
* @brief Root path (optional) for the project.
* This is the project root path. If it is present then all relative paths in
* the project file are relative to this path. Otherwise paths are relative
* to project file's path.
*/
QString mRootPath;
/**
* @brief List of include directories used to search include files.
*/
@ -115,6 +166,11 @@ private:
* @brief List of defines.
*/
QStringList mDefines;
/**
* @brief List of paths to check.
*/
QStringList mPaths;
};
/// @}
#endif // PROJECT_FILE_H

View File

@ -13,7 +13,12 @@ program. The format is:
<?xml version="1.0"?>
<project version="1">
<root name="c:/projects/cppcheck/" />
<paths>
<dir name="lib/" />
</paths>
<includedir>
<dir name="lib/" />
<dir name="c:/projects/framework/" />
<dir name="c:/Program Files/Visual Studio 8/VC/include/" />
</includedir>
@ -24,4 +29,18 @@ program. The format is:
</defines>
</project>
where:
- optional root element defines the root directory for the project. All
relative paths are considered to be relative to this path. If the root
element is missing or it contains "." as value then the project file's
location is considered to be the root path.
- paths element contains a list of checked paths. The paths can be relative or
absolute paths.
- indludedir element contains a list of additional include paths. These
include paths are used when finding local include files ("#include "file.h")
for source files. The paths can be relative or absolute paths. It is highly
recommended that relative paths are used for paths inside the project root
folder for better portability.
- defines element contains a list of C/C++ preprocessor defines.
See also gui.cppcheck file in gui-directory of cppcheck sources.

View File

@ -7,13 +7,47 @@
<x>0</x>
<y>0</y>
<width>400</width>
<height>112</height>
<height>131</height>
</rect>
</property>
<property name="windowTitle">
<string>Project File</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QLabel" name="label_4">
<property name="text">
<string>Project:</string>
</property>
<property name="buddy">
<cstring>mEditProjectRoot</cstring>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="mEditProjectRoot"/>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>Paths:</string>
</property>
<property name="buddy">
<cstring>mEditPaths</cstring>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="mEditPaths"/>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
@ -73,6 +107,13 @@
</item>
</layout>
</widget>
<tabstops>
<tabstop>mEditProjectRoot</tabstop>
<tabstop>mEditPaths</tabstop>
<tabstop>mEditIncludePaths</tabstop>
<tabstop>mEditDefines</tabstop>
<tabstop>mButtons</tabstop>
</tabstops>
<resources/>
<connections>
<connection>

View File

@ -33,6 +33,13 @@ ProjectFileDialog::ProjectFileDialog(const QString &path, QWidget *parent)
connect(mUI.mButtons, SIGNAL(accepted()), this, SLOT(accept()));
}
QString ProjectFileDialog::GetRootPath() const
{
QString root = mUI.mEditProjectRoot->text();
root = root.trimmed();
return root;
}
QStringList ProjectFileDialog::GetIncludePaths() const
{
QString include = mUI.mEditIncludePaths->text();
@ -63,6 +70,26 @@ QStringList ProjectFileDialog::GetDefines() const
return defines;
}
QStringList ProjectFileDialog::GetPaths() const
{
QString path = mUI.mEditPaths->text();
QStringList paths;
if (!path.isEmpty())
{
path = path.trimmed();
if (path.indexOf(';') != -1)
paths = path.split(";");
else
paths.append(path);
}
return paths;
}
void ProjectFileDialog::SetRootPath(const QString &root)
{
mUI.mEditProjectRoot->setText(root);
}
void ProjectFileDialog::SetIncludepaths(const QStringList &includes)
{
QString includestr;
@ -92,3 +119,18 @@ void ProjectFileDialog::SetDefines(const QStringList &defines)
definestr = definestr.left(definestr.length() - 1);
mUI.mEditDefines->setText(definestr);
}
void ProjectFileDialog::SetPaths(const QStringList &paths)
{
QString pathstr;
QString path;
foreach(path, paths)
{
pathstr += path;
pathstr += ";";
}
// Remove ; from the end of the string
if (pathstr.endsWith(';'))
pathstr = pathstr.left(pathstr.length() - 1);
mUI.mEditPaths->setText(pathstr);
}

View File

@ -21,6 +21,7 @@
#include <QDialog>
#include <QString>
#include <QStringList>
#include "ui_projectfile.h"
@ -39,6 +40,12 @@ class ProjectFileDialog : public QDialog
public:
ProjectFileDialog(const QString &path, QWidget *parent = 0);
/**
* @brief Return project root path from the dialog control.
* @return Project root path.
*/
QString GetRootPath() const;
/**
* @brief Return include paths from the dialog control.
* @return List of include paths.
@ -51,6 +58,18 @@ public:
*/
QStringList GetDefines() const;
/**
* @brief Return check paths from the dialog control.
* @return List of check paths.
*/
QStringList GetPaths() const;
/**
* @brief Set project root path to dialog control.
* @param root Project root path to set to dialog control.
*/
void SetRootPath(const QString &root);
/**
* @brief Set include paths to dialog control.
* @param includes List of include paths to set to dialog control.
@ -63,6 +82,12 @@ public:
*/
void SetDefines(const QStringList &defines);
/**
* @brief Set check paths to dialog control.
* @param paths List of path names to set to dialog control.
*/
void SetPaths(const QStringList &paths);
private:
Ui::ProjectFile mUI;
};