ui: Added user interface for auto system header search paths detection

* moved detection files to lib_gui
* added ui to global header search and framework search ui in project wizzard and preferences
* detecting the search paths will add them to the list if not added yet
* only detected compilers are shown in the dropdown list
This commit is contained in:
Eberhard Graether
2016-04-06 11:23:20 +02:00
parent 93f21283f6
commit 5e6714d95a
26 changed files with 345 additions and 243 deletions
-12
View File
@@ -6,18 +6,6 @@ add_files(
utility/commandline/CommandLineParser.cpp
utility/commandline/CommandLineParser.h
utility/headerSearch/CompilerDetector.cpp
utility/headerSearch/CompilerDetector.h
utility/headerSearch/DetectorBase.cpp
utility/headerSearch/DetectorBase.h
utility/headerSearch/StandardHeaderDetection.cpp
utility/headerSearch/StandardHeaderDetection.h
utility/headerSearch/VisualStudioDetector.cpp
utility/headerSearch/VisualStudioDetector.h
utility/utilityApp.cpp
utility/utilityApp.h
isTrial.cpp
LicenseChecker.h
main.cpp
-7
View File
@@ -20,9 +20,6 @@
#include "settings/ProjectSettings.h"
#include "utility/headerSearch/StandardHeaderDetection.h"
void init()
{
std::shared_ptr<ConsoleLogger> consoleLogger = std::make_shared<ConsoleLogger>();
@@ -86,10 +83,6 @@ int main(int argc, char *argv[])
LicenseChecker checker;
StandardHeaderDetection detection;
detection.printdetectedCompilers();
detection.printAvailableDetectors();
utility::loadFontsFromDirectory(ResourcePaths::getFontsPath(), ".otf");
std::shared_ptr<Application> app = Application::create(version, &viewFactory, &networkFactory);
@@ -1,37 +0,0 @@
#include "utility/headerSearch/CompilerDetector.h"
#include "utility/utilityApp.h"
#include "utility/utilityString.h"
CompilerDetector::CompilerDetector(const std::string& name)
: DetectorBase(name)
{
}
CompilerDetector::~CompilerDetector()
{
}
std::vector<FilePath> CompilerDetector::getStandardHeaderPaths()
{
std::string command = m_name + " -x c++ -v -E /dev/null";
std::string clangOutput = utility::executeProcess(command.c_str());
std::string standardHeaders = utility::substrBetween(clangOutput, "#include <...> search starts here:\n","\nEnd of search list");
std::vector<FilePath> paths;
if (!standardHeaders.empty())
{
for (std::string s : utility::splitToVector(standardHeaders, '\n'))
{
paths.push_back(s);
}
}
return paths;
}
// Add Gcc to Available Detectors
static StandardHeaderDetection::Add<CompilerDetector> gcc("gcc");
// Add Clang to Available Detectors
static StandardHeaderDetection::Add<CompilerDetector> clang("clang");
@@ -1,13 +0,0 @@
#ifndef DETECTOR_PROXY_H
#define DETECTOR_PROXY_H
class DetectorProxyBase
{
public:
};
#endif // DETECTOR_PROXY_H
@@ -1,87 +0,0 @@
#include "utility/headerSearch/StandardHeaderDetection.h"
#include <cstdlib>
#include <map>
#include <string>
#include <vector>
#include <utility>
#include <iostream>
#include "utility/file/FilePath.h"
#include "utility/logging/logging.h"
#include "utility/utilityApp.h"
#include "utility/utilityString.h"
#include "clang/Driver/ToolChain.h"
#include "clang/Driver/Options.h"
#include "clang/Driver/Tool.h"
#include "clang/Driver/DriverDiagnostic.h"
typedef std::pair<std::string, std::shared_ptr<DetectorBase>> DetectorPair;
DetectorMap* StandardHeaderDetection::s_availableDetectors;
StandardHeaderDetection::StandardHeaderDetection()
{
detectHeaders();
}
StandardHeaderDetection::~StandardHeaderDetection()
{
if ( s_availableDetectors != nullptr )
{
delete s_availableDetectors;
}
}
void StandardHeaderDetection::detectHeaders()
{
for ( DetectorPair detector : *s_availableDetectors)
{
if ( detector.second->detect() )
{
m_detectedCompilers.insert(detector);
}
}
}
std::vector<std::string> StandardHeaderDetection::getDetectedCompilers()
{
std::vector<std::string> v;
for ( DetectorPair detector : m_detectedCompilers)
{
v.push_back(detector.first);
}
return v;
}
std::vector<FilePath> StandardHeaderDetection::getStandardHeaderPaths(std::string compiler)
{
auto it = m_detectedCompilers.find(compiler);
if(it != m_detectedCompilers.end())
{
return it->second->getStandardHeaderPaths();
}
return std::vector<FilePath>();
}
void StandardHeaderDetection::printdetectedCompilers()
{
std::cout << "Detected Compilers: " << std::endl;
std::vector<std::string> compilers = getDetectedCompilers();
for ( std::string compiler : compilers)
{
std::cout << compiler << std::endl;
}
}
void StandardHeaderDetection::printAvailableDetectors()
{
std::cout << "printAvailableDetectors: " << std::endl;
for ( DetectorPair detector : *s_availableDetectors)
{
std::cout << detector.first << std::endl;
}
}
@@ -1,53 +0,0 @@
#ifndef STANDARDHEADER_DETECTION_H
#define STANDARDHEADER_DETECTION_H
#include <map>
#include <memory>
#include <string>
#include "utility/headerSearch/DetectorBase.h"
typedef std::map<std::string, std::shared_ptr<DetectorBase>> DetectorMap;
class FilePath;
class StandardHeaderDetection
{
public:
StandardHeaderDetection();
~StandardHeaderDetection();
/// Checks all availabe detectors and saves found Compilers
void detectHeaders();
/// Returns alls found compilers
std::vector<std::string> getDetectedCompilers();
/// Returns the headerpaths from a found compiler
std::vector<FilePath> getStandardHeaderPaths(std::string compiler);
/// Declare a instance of this class to add a detector
template <typename U>
class Add
{
public:
Add(const std::string& name)
{
std::shared_ptr<DetectorBase> detector = std::shared_ptr<U>(new U(name));
if (!s_availableDetectors)
{
s_availableDetectors = new DetectorMap();
}
s_availableDetectors->insert(std::make_pair(detector->getName(), detector));
}
};
/// Debugging Output
void printAvailableDetectors();
void printdetectedCompilers();
private:
static DetectorMap* s_availableDetectors;
DetectorMap m_detectedCompilers;
};
#endif //STANDARDHEADER_DETECTION_H
+7 -2
View File
@@ -122,12 +122,17 @@ namespace utility
bool isPrefix(const std::string& prefix, const std::string& text)
{
typedef std::pair<std::string::const_iterator, std::string::const_iterator> ResType;
ResType res = std::mismatch(prefix.begin(), prefix.end(), text.begin());
std::pair<std::string::const_iterator, std::string::const_iterator> res =
std::mismatch(prefix.begin(), prefix.end(), text.begin());
return res.first == prefix.end();
}
bool isPostfix(const std::string& postfix, const std::string& text)
{
return text.size() >= postfix.size() && text.rfind(postfix) == (text.size() - postfix.size());
}
std::string toUpperCase(const std::string& in)
{
std::string out;
+1
View File
@@ -35,6 +35,7 @@ namespace utility
std::string substrBetween(const std::string& str, const std::string& delimiter1, const std::string& delimiter2);
bool isPrefix(const std::string& prefix, const std::string& text);
bool isPostfix(const std::string& postfix, const std::string& text);
std::string toUpperCase(const std::string& in);
std::string toLowerCase(const std::string& in);
+12
View File
@@ -151,4 +151,16 @@ add_files(
qt/QtApplication.h
qt/QtCoreApplication.cpp
qt/QtCoreApplication.h
utility/headerSearch/CompilerDetector.cpp
utility/headerSearch/CompilerDetector.h
utility/headerSearch/DetectorBase.cpp
utility/headerSearch/DetectorBase.h
utility/headerSearch/StandardHeaderDetection.cpp
utility/headerSearch/StandardHeaderDetection.h
utility/headerSearch/VisualStudioDetector.cpp
utility/headerSearch/VisualStudioDetector.h
utility/utilityApp.cpp
utility/utilityApp.h
)
@@ -92,7 +92,7 @@ void QtProjectWizzard::newProjectFromSolution(const std::string& ideId, const st
std::string title = "NEW PROJECT FROM ";
title += ideId;
title += " SOLUTION";
boost::algorithm::to_upper(title);
window->updateTitle(QString(title.c_str()));
@@ -232,8 +232,8 @@ QtProjectWizzardWindow* QtProjectWizzard::createWindowWithContent<QtProjectWizza
connect(window, SIGNAL(canceled()), this, SLOT(cancelWizzard()));
QtProjectWizzardContentSelect* content = new QtProjectWizzardContentSelect(&m_settings, window, m_parserManager);
window->setContent(content);
window->setup();
@@ -7,6 +7,7 @@
#include "qt/element/QtDirectoryListBox.h"
#include "settings/ApplicationSettings.h"
#include "utility/file/FileSystem.h"
#include "utility/headerSearch/StandardHeaderDetection.h"
#include "utility/utility.h"
QtProjectWizzardContentPaths::QtProjectWizzardContentPaths(ProjectSettings* settings, QtProjectWizzardWindow* window)
@@ -47,6 +48,11 @@ void QtProjectWizzardContentPaths::populateWindow(QGridLayout* layout, int& row)
addFilesButton(m_showFilesString, layout, row);
}
if (m_detectionString.size() > 0)
{
addDetection(m_detectionString, layout, row);
}
row++;
layout->setColumnStretch(QtProjectWizzardWindow::FRONT_COL, 1);
@@ -72,6 +78,12 @@ void QtProjectWizzardContentPaths::populateForm(QGridLayout* layout, int& row)
addFilesButton(m_showFilesString, layout, row);
row++;
}
if (m_detectionString.size() > 0)
{
addDetection(m_detectionString, layout, row);
row++;
}
}
QSize QtProjectWizzardContentPaths::preferredWindowSize() const
@@ -101,6 +113,60 @@ void QtProjectWizzardContentPaths::setHelpString(const QString& help)
m_helpString = help;
}
void QtProjectWizzardContentPaths::addDetection(QString name, QGridLayout* layout, int row)
{
StandardHeaderDetection detection;
std::vector<std::string> compilers = detection.getDetectedCompilers();
if (!compilers.size())
{
return;
}
QLabel* label = new QLabel("Auto detection from:");
m_detectorBox = new QComboBox();
for (const std::string& compiler : compilers)
{
m_detectorBox->addItem(compiler.c_str());
}
QPushButton* button = new QPushButton("detect");
button->setObjectName("windowButton");
connect(button, SIGNAL(clicked()), this, SLOT(detectionClicked()));
QHBoxLayout* hlayout = new QHBoxLayout();
hlayout->addWidget(label);
hlayout->addWidget(m_detectorBox);
hlayout->addWidget(button);
layout->addLayout(hlayout, row, QtProjectWizzardWindow::BACK_COL, Qt::AlignLeft | Qt::AlignTop);
}
void QtProjectWizzardContentPaths::detectionClicked()
{
StandardHeaderDetection detection;
std::vector<FilePath> paths;
if (m_detectionString == "headers")
{
paths = detection.getStandardHeaderPaths(m_detectorBox->currentText().toStdString());
}
else if (m_detectionString == "frameworks")
{
paths = detection.getStandardFrameworkPaths(m_detectorBox->currentText().toStdString());
}
std::vector<FilePath> oldPaths = m_list->getList();
std::set<FilePath> uniquePaths;
uniquePaths.insert(oldPaths.begin(), oldPaths.end());
uniquePaths.insert(paths.begin(), paths.end());
m_list->setList(utility::toVector(uniquePaths));
}
QtProjectWizzardContentPathsSource::QtProjectWizzardContentPathsSource(
ProjectSettings* settings, QtProjectWizzardWindow* window
)
@@ -291,14 +357,16 @@ QtProjectWizzardContentPathsHeaderSearchGlobal::QtProjectWizzardContentPathsHead
{
setInfo(
"Global Header Search Paths",
"These header search paths will be used in all your projects. Use it to add system header and Standard Library "
"header paths (See <a href=\"https://coati.io/documentation/#FindingSystemHeaderLocations\">Finding "
"System Header Locations</a>).",
"These header search paths will be used in all your projects. Use it to add system header paths "
"(See <a href=\"https://coati.io/documentation/#FindingSystemHeaderLocations\">Finding System Header Locations</a> "
"or use the auto detection below).",
"Header Search Paths define where additional headers, that your project depends on, are found. Usually they are "
"header files of frameworks or libraries that your project uses. These files won't be analyzed, but Coati needs "
"them for correct analysis.\n\n"
"Header Search Paths defined here will be used for all projects."
);
m_detectionString = "headers";
}
void QtProjectWizzardContentPathsHeaderSearchGlobal::load()
@@ -350,11 +418,13 @@ QtProjectWizzardContentPathsFrameworkSearchGlobal::QtProjectWizzardContentPathsF
"Global Framework Search Paths",
"These framework search paths will be used in all your projects. Use it to add system frameworks "
"(See <a href=\"https://coati.io/documentation/#FindingSystemHeaderLocations\">"
"Finding System Header Locations</a>).",
"Finding System Header Locations</a> or use the auto detection below).",
"Framework Search Paths define where MacOS framework containers (.framework), that your project depends on, are "
"found.\n\n"
"Framework Search Paths defined here will be used for all projects."
);
m_detectionString = "frameworks";
}
void QtProjectWizzardContentPathsFrameworkSearchGlobal::load()
@@ -1,6 +1,7 @@
#ifndef QT_PROJECT_WIZZARD_CONTENT_PATHS_H
#define QT_PROJECT_WIZZARD_CONTENT_PATHS_H
#include <QComboBox>
#include <QPushButton>
#include "qt/window/project_wizzard/QtProjectWizzardContent.h"
@@ -31,14 +32,22 @@ protected:
void setDescriptionString(const QString& description);
void setHelpString(const QString& help);
void addDetection(QString name, QGridLayout* layout, int row);
QtDirectoryListBox* m_list;
QString m_showFilesString;
QString m_detectionString;
private slots:
void detectionClicked();
private:
QString m_titleString;
QString m_descriptionString;
QString m_helpString;
QComboBox* m_detectorBox;
};
@@ -0,0 +1,62 @@
#include "utility/headerSearch/CompilerDetector.h"
#include "utility/utilityApp.h"
#include "utility/utilityString.h"
CompilerDetector::CompilerDetector(const std::string& name)
: DetectorBase(name)
{
}
CompilerDetector::~CompilerDetector()
{
}
std::vector<std::string> CompilerDetector::getHeaderPaths()
{
std::string command = m_name + " -x c++ -v -E /dev/null";
std::string clangOutput = utility::executeProcess(command.c_str());
std::string standardHeaders =
utility::substrBetween(clangOutput, "#include <...> search starts here:\n","\nEnd of search list");
std::vector<std::string> paths;
if (!standardHeaders.empty())
{
for (std::string s : utility::splitToVector(standardHeaders, '\n'))
{
paths.push_back(utility::trim(s));
}
}
return paths;
}
std::vector<FilePath> CompilerDetector::getStandardHeaderPaths()
{
std::vector<std::string> paths = getHeaderPaths();
std::vector<FilePath> headerPaths;
for (const std::string& path : paths)
{
if (!utility::isPostfix(" (framework directory)", path))
{
headerPaths.push_back(FilePath(path).canonical());
}
}
return headerPaths;
}
std::vector<FilePath> CompilerDetector::getStandardFrameworkPaths()
{
std::vector<std::string> paths = getHeaderPaths();
std::vector<FilePath> frameworkPaths;
for (const std::string& path : paths)
{
if (utility::isPostfix(" (framework directory)", path))
{
frameworkPaths.push_back(FilePath(utility::replace(path, " (framework directory)", "")).canonical());
}
}
return frameworkPaths;
}
@@ -2,16 +2,19 @@
#define COMPILER_DETECTOR_H
#include "utility/headerSearch/DetectorBase.h"
#include "utility/headerSearch/StandardHeaderDetection.h"
class CompilerDetector : public DetectorBase
class CompilerDetector
: public DetectorBase
{
public:
CompilerDetector(const std::string& name);
virtual ~CompilerDetector();
std::vector<std::string> getHeaderPaths();
virtual std::vector<FilePath> getStandardHeaderPaths();
private:
virtual std::vector<FilePath> getStandardFrameworkPaths();
};
#endif // COMPILER_DETECTOR_H
@@ -1,7 +1,5 @@
#include "utility/headerSearch/DetectorBase.h"
#include <iostream>
DetectorBase::DetectorBase(const std::string name)
{
setName(name);
@@ -12,6 +10,11 @@ bool DetectorBase::detect()
return !getStandardHeaderPaths().empty();
}
std::vector<FilePath> DetectorBase::getStandardFrameworkPaths()
{
return std::vector<FilePath>();
}
std::string DetectorBase::getName() const
{
return m_name;
@@ -2,6 +2,7 @@
#define DETECTOR_BASE_H
#include <vector>
#include "utility/file/FilePath.h"
class DetectorBase
@@ -11,19 +12,11 @@ public:
virtual ~DetectorBase(){};
virtual bool detect();
virtual std::vector<FilePath> getStandardHeaderPaths() = 0;
virtual std::vector<FilePath> getStandardFrameworkPaths();
virtual std::string getName() const;
virtual void setName(const std::string& name);
protected:
std::string m_name;
};
class Detector
{
public:
virtual ~Detector();
};
#endif // DETECTOR_BASE_H
@@ -0,0 +1,106 @@
#include "utility/headerSearch/StandardHeaderDetection.h"
#include <cstdlib>
#include <iostream>
#include <map>
#include <string>
#include <utility>
#include <vector>
#include "utility/file/FilePath.h"
#include "utility/headerSearch/CompilerDetector.h"
#include "utility/headerSearch/VisualStudioDetector.h"
#include "utility/logging/logging.h"
#include "utility/utilityApp.h"
#include "utility/utilityString.h"
StandardHeaderDetection::DetectorMap StandardHeaderDetection::s_availableDetectors;
StandardHeaderDetection::DetectorMap StandardHeaderDetection::s_detectedCompilers;
StandardHeaderDetection::StandardHeaderDetection()
{
if (!s_availableDetectors.size())
{
addDetector(std::make_shared<CompilerDetector>("gcc"));
addDetector(std::make_shared<CompilerDetector>("clang"));
addDetector(std::make_shared<VisualStudioDetector>("14"));
addDetector(std::make_shared<VisualStudioDetector>("12"));
addDetector(std::make_shared<VisualStudioDetector>("11"));
addDetector(std::make_shared<VisualStudioDetector>("9"));
detectHeaders();
}
}
StandardHeaderDetection::~StandardHeaderDetection()
{
}
void StandardHeaderDetection::addDetector(std::shared_ptr<DetectorBase> detector)
{
s_availableDetectors.emplace(detector->getName(), detector);
}
void StandardHeaderDetection::detectHeaders()
{
for ( DetectorPair detector : s_availableDetectors)
{
if ( detector.second->detect() )
{
s_detectedCompilers.insert(detector);
}
}
}
std::vector<std::string> StandardHeaderDetection::getDetectedCompilers()
{
std::vector<std::string> v;
for ( DetectorPair detector : s_detectedCompilers)
{
v.push_back(detector.first);
}
return v;
}
std::vector<FilePath> StandardHeaderDetection::getStandardHeaderPaths(std::string compiler)
{
auto it = s_detectedCompilers.find(compiler);
if (it != s_detectedCompilers.end())
{
return it->second->getStandardHeaderPaths();
}
return std::vector<FilePath>();
}
std::vector<FilePath> StandardHeaderDetection::getStandardFrameworkPaths(std::string compiler)
{
auto it = s_detectedCompilers.find(compiler);
if (it != s_detectedCompilers.end())
{
return it->second->getStandardFrameworkPaths();
}
return std::vector<FilePath>();
}
void StandardHeaderDetection::printDetectedCompilers()
{
std::cout << "Detected Compilers: " << std::endl;
std::vector<std::string> compilers = getDetectedCompilers();
for ( std::string compiler : compilers)
{
std::cout << compiler << std::endl;
}
}
void StandardHeaderDetection::printAvailableDetectors()
{
std::cout << "Available Detectors: " << std::endl;
for ( DetectorPair detector : s_availableDetectors)
{
std::cout << detector.first << std::endl;
}
}
@@ -0,0 +1,43 @@
#ifndef STANDARD_HEADER_DETECTION_H
#define STANDARD_HEADER_DETECTION_H
#include <map>
#include <memory>
#include <string>
#include <iostream>
#include "utility/headerSearch/DetectorBase.h"
class FilePath;
class StandardHeaderDetection
{
public:
StandardHeaderDetection();
~StandardHeaderDetection();
void addDetector(std::shared_ptr<DetectorBase> detector);
/// Checks all availabe detectors and saves found Compilers
void detectHeaders();
/// Returns alls found compilers
std::vector<std::string> getDetectedCompilers();
/// Returns the headerpaths from a found compiler
std::vector<FilePath> getStandardHeaderPaths(std::string compiler);
std::vector<FilePath> getStandardFrameworkPaths(std::string compiler);
/// Debugging Output
void printAvailableDetectors();
void printDetectedCompilers();
private:
typedef std::map<std::string, std::shared_ptr<DetectorBase>> DetectorMap;
typedef std::pair<std::string, std::shared_ptr<DetectorBase>> DetectorPair;
static DetectorMap s_availableDetectors;
static DetectorMap s_detectedCompilers;
};
#endif // STANDARD_HEADER_DETECTION_H
@@ -1,14 +1,13 @@
#include "utility/headerSearch/VisualStudioDetector.h"
#include <string>
#include <QSettings>
#include <QSysInfo>
#include <QDir>
#include <string>
#include "utility/file/FilePath.h"
#include "utility/logging/logging.h"
#include "utility/headerSearch/StandardHeaderDetection.h"
#include <iostream>
VisualStudioDetector::VisualStudioDetector(const std::string name)
: DetectorBase("")
@@ -116,10 +115,3 @@ bool VisualStudioDetector::getStanardHeaderPathsUsingRegistry(std::vector<FilePa
return false;
}
// Add Visual Studio Version to the available detectors
static StandardHeaderDetection::Add<VisualStudioDetector> vs2015("14");
static StandardHeaderDetection::Add<VisualStudioDetector> vs2013("12");
static StandardHeaderDetection::Add<VisualStudioDetector> vs2012("11");
static StandardHeaderDetection::Add<VisualStudioDetector> vs2010("9");
@@ -2,6 +2,7 @@
#define VISUAL_STUDIO_DETECTOR_H
#include <vector>
#include "utility/headerSearch/DetectorBase.h"
class FilePath;
Binary file not shown.

Before

Width:  |  Height:  |  Size: 134 KiB

After

Width:  |  Height:  |  Size: 164 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 158 KiB

After

Width:  |  Height:  |  Size: 180 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 168 KiB

After

Width:  |  Height:  |  Size: 193 KiB

+11
View File
@@ -579,13 +579,24 @@
</div>
</div>
<p>If you chose the advanced setup method Coati needs you to specify all the project's internal include paths in addition to the external dependencies. Project internal include paths are those paths your project internal <code>#include</code> directives are relative to.</p>
<p>Additionally you can also specify Global Header Search Paths, which will be used by all yout projects. These are usually the paths to system headers, which can also be auto detected by choosing a compiler below and pressing <var>detect</var>.</p>
<div class="row">
<div class="col-sm-10 col-sm-offset-1">
<img src="img/project_setup_wizard_empty_header_paths_advanced.png" style="width:100%;">
</div>
</div>
<table class="table table-hover">
<thead>
<tr> <th>Setting</th> <th>Description</th> </tr>
</thead>
<tbody>
<tr> <th scope="row">Header Search Paths</th> <td>These paths are used to find the files specified by <code>#include</code> directives. (For instructions on how to add paths see <a href="#PathListBox">Path List Box</a>.)</td> </tr>
<tr> <th scope="row">Global Header Search Paths</th> <td>These Header Search Paths will be used in all your projects. (For instructions on how to add paths see <a href="#PathListBox">Path List Box</a>. For instructions on how to find the system header paths see <a href="#FindingSystemHeaderLocations">Finding System Header Locations</a>)</td> </tr>
</tbody>
</table>
<strong>Interactions:</strong>
<ul>
<li>Selecting a compiler from the dropdown list below and pressing <var>detect</var> will automatically detect system header search paths used by this compiler and add them to the Global Header Search Paths.</li>
<li>Clicking <var>Cancel</var> or pressing <var>ESC</var> will close the window and abort the setup process.</li>
<li>Clicking <var>Next</var> will take you to the <a href="#NewProjectSummary">New Project Summary Window</a>.</li>
<li>Clicking <var>Previous</var> take you to the previous step of the setup process. All the information you entered will be saved.</li>