A more convenient way to see project dependencies? - visual-studio

VS has the "Project Dependencies" window but in a solution I work on there are over 100 projects. Trying to see all the dependencies of a specific project is time-consuming as you have to scroll through the entire list, and it's easy to miss one.
Is there a way just to list the dependencies, not all the projects with a tick-box showing which are dependencies?

You may open a Visual Studio Solution file (.sln) in a text editor, for example, Notepad++. Once opened, search for ProjectSection(ProjectDependencies) = postProject within the specific project you are looking for.
The example of part of a .sln file below shows that the NativeUnitTest_CppDll project depends on NativeWin32CppDll project.
The only downside is that the dependencies are listed as GUIDs. You will have to do a text Find to locate their project names.
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NativeWin32CppDll", "NativeWin32CppDll\NativeWin32CppDll.vcxproj", "{83FC3109-17DF-4B53-BCA0-F0DFC10AAE7F}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NativeUnitTest_CppDll", "NativeUnitTest_CppDll\NativeUnitTest_CppDll.vcxproj", "{559CB21A-4763-4A1E-A70A-E8C656C53ED9}"
ProjectSection(ProjectDependencies) = postProject
{83FC3109-17DF-4B53-BCA0-F0DFC10AAE7F} = {83FC3109-17DF-4B53-BCA0-F0DFC10AAE7F}
EndProjectSection
EndProject

Could you please clarify: to see and list where? In the Visual Studio or some external tool? Just to see in a pop-up or to have an ability to copy the list?
I was trying to get those dependencies using Visual Studio's Solution object and its properties. There is a property named ProjectDependencies, but it was empty on my test, so I assume it is tracking auto-dependencies, not the one you specify manually.
Then I tried to get the list out of *.sln file, as was also suggested by gxy, in a simple console project (you should pass the solution file on a command line):
int main(int argc, char* argv[])
{
if (argc != 2)
return -1;
ifstream sln(argv[1]);
string line, name, guid;
unordered_map<string, string> names;
unordered_map<string, list<string>> dependencies;
while (getline(sln, line))
{
if (line.find("Project(") == 0)
{
ParseProjGuid(line, name, guid);
names[guid] = name;
while (getline(sln, line))
{
if (line == "EndProject")
break;
if (line.find("ProjectSection(ProjectDependencies)") != string::npos)
{
while (getline(sln, line))
{
if (line.find("EndProjectSection") != string::npos)
break;
ParseDependGuid(line, guid);
dependencies[name].push_back(guid);
}
}
}
}
}
for (auto d : dependencies)
{
cout << d.first << endl;
for (auto g : d.second)
cout << "\t" << names[g] << endl;
}
return 0;
}
I am using a couple of helper functions there:
string unquote(const string& s)
{
if (s[0] == '"' && s[s.length() - 1] == '"')
return s.substr(1, s.length() - 2);
else
return s;
}
void ParseProjGuid(const string& src, string& proj, string& guid)
{
// Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "name", "path\name.vcxproj", "{9D4B97C3-1069-406C-973F-652706414C86}"
size_t pos1 = src.find('=');
size_t pos2 = src.find(',');
size_t pos3 = src.rfind(',');
proj = src.substr(pos1 + 1, pos2 - pos1 - 1);
guid = src.substr(pos3 + 1);
proj = trim(proj);
guid = trim(guid);
proj = unquote(proj);
guid = unquote(guid);
}
void ParseDependGuid(const string& src, string& guid)
{
// {165C1503-36B1-4577-9D99-3C1AFEBFC201} = {165C1503-36B1-4577-9D99-3C1AFEBFC201}
size_t pos = src.find('=');
guid = src.substr(0, pos);
guid = trim(guid);
}
As well as trim function borrowed from from What's the best way to trim std::string?:
// trim from start
static inline string &ltrim(string &s) {
s.erase(s.begin(), find_if(s.begin(), s.end(), std::not1(std::ptr_fun<int, int>(std::isspace))));
return s;
}
// trim from end
static inline string &rtrim(string &s) {
s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
return s;
}
// trim from both ends
static inline string &trim(string &s) {
return ltrim(rtrim(s));
}
As my hobby is writing Visual Studio extensions, I have a question: do you think it will be a useful tool?

Related

How to properly compare Q_ENUM and QStringList

I have a small example .ui where the user can drag and drop from a QListWidget to a QGraphicsView using QGraphicsProxyWidget a specific widget (in my case is a QTableWidget) as shown below.
Basically the behavior I have been looking for is:
If I drag and drop "Imgaes" than the QTableWidget on the QGraphicsView will have 2 columns and 2 rows; (which is correct)
If I drag and drop "Path" than the QTableWidget on the QGraphicsView will have 3 columns and 3 rows; (which is wrong)
[1] : https://imgur.com/NQ1DZpx
Below the selection of "Path", which still give 2 rows and 2 columns instead of 3 rows and 3 columns
[2] : https://imgur.com/d4YcOiL
Below the code:
scene.h
class Scene : public QGraphicsScene {
enum LaserTableWidget {
Images,
Path
};
Q_ENUM(LaserTableWidget)
public:
Scene(QObject *parent = nullptr);
void compare(const QString& comp);
template<typename QEnum>
std::string QtEnumToString (const QEnum value)
{
return std::string(QMetaEnum::fromType<QEnum>().valueToKey(value));
}
protected:
void dropEvent(QGraphicsSceneDragDropEvent *event);
scene.cpp
Scene::Scene(QObject *parent) : QGraphicsScene(parent) {
setBackgroundBrush(Qt::lightGray);
}
void Scene::compare(const QString &comp)
{
// get information about the enum named "LaserTableWidget"
QMetaObject MetaObject = this->staticMetaObject;
QMetaEnum MetaEnum = MetaObject.enumerator(MetaObject.indexOfEnumerator("LaserTableWidget"));
QStringList tabs;
switch (MetaEnum.keyToValue(comp.toUpper().toLatin1()))
// or simply switch (MetaEnum.keyToValue(word)) if no string modification is needed
{
case Images:
for (const QString &color : tabs) {
QPoint initPos(0,0);
QTableWidget *wgt = new QTableWidget;
QGraphicsRectItem *proxyControl = addRect(initPos.x(), initPos.y(), wgt->width(), 20, QPen(Qt::black), QBrush(Qt::darkGreen)); // widget->width() works properly here because of the resize(layout->sizeHint()) that we have used inside it
proxyControl->setFlag(QGraphicsItem::ItemIsMovable, true);
proxyControl->setFlag(QGraphicsItem::ItemIsSelectable, true);
wgt->setColumnCount(2);
wgt->setRowCount(2);
for (int ridx = 0 ; ridx < wgt->rowCount() ; ridx++ )
{
for (int cidx = 0 ; cidx < wgt->columnCount() ; cidx++)
{
QTableWidgetItem* item = new QTableWidgetItem();
item->setText(QString("%1").arg(ridx));
wgt->setItem(ridx,cidx,item);
}
}
QGraphicsProxyWidget * const proxy = addWidget(wgt);
// In my case the rectangular graphics item is supposed to be above my widget so the position of the widget is shifted along the Y axis based on the height of the rectangle of that graphics item
proxy->setPos(initPos.x(), initPos.y()+proxyControl->rect().height());
proxy->setParentItem(proxyControl);
}
break;
case Path:
for (const QString &color : tabs) {
QPoint initPos(0,0);
QTableWidget *wgt = new QTableWidget;
QGraphicsRectItem *proxyControl = addRect(initPos.x(), initPos.y(), wgt->width(), 20, QPen(Qt::black), QBrush(Qt::darkGreen)); // widget->width() works properly here because of the resize(layout->sizeHint()) that we have used inside it
proxyControl->setFlag(QGraphicsItem::ItemIsMovable, true);
proxyControl->setFlag(QGraphicsItem::ItemIsSelectable, true);
wgt->setColumnCount(3);
wgt->setRowCount(3);
for (int ridx = 0 ; ridx < wgt->rowCount() ; ridx++ )
{
for (int cidx = 0 ; cidx < wgt->columnCount() ; cidx++)
{
QTableWidgetItem* item = new QTableWidgetItem();
item->setText(QString("%1").arg(ridx));
wgt->setItem(ridx,cidx,item);
}
}
QGraphicsProxyWidget * const proxy = addWidget(wgt);
// In my case the rectangular graphics item is supposed to be above my widget so the position of the widget is shifted along the Y axis based on the height of the rectangle of that graphics item
proxy->setPos(initPos.x(), initPos.y()+proxyControl->rect().height());
proxy->setParentItem(proxyControl);
}
break;
default:
break;
}
}
void Scene::dropEvent(QGraphicsSceneDragDropEvent *event) {
QByteArray encoded =
event->mimeData()->data("application/x-qabstractitemmodeldatalist");
QDataStream stream(&encoded, QIODevice::ReadOnly);
QStringList rosTables;
while (!stream.atEnd()) {
int row, col;
QMap<int, QVariant> roleDataMap;
stream >> row >> col >> roleDataMap;
rosTables << roleDataMap[Qt::DisplayRole].toString();
}
compare(const QString &comp)
}
I tried to use the template function declared on the header file that for completeness I am also attaching below:
template<typename QEnum>
std::string QtEnumToString (const QEnum value)
{
return std::string(QMetaEnum::fromType<QEnum>().valueToKey(value));
}
Maybe I the template function is the wrong choice? I was trying to find a way to use it if possible.
That is the reason why I switched to a void compare(const QString& comp); function and tried to delegate the job to a switch - case statement but that also is not working as I expect and I still see the same exact QtableWidget dropped onto the QGraphicsView.
Of course I did more research and came across this source and above all this post which was useful to understand the basic comparison and following this post I decided to go ahead and try to apply the Q_ENUM - QString or even the QStringList as a valuable tool. But I could not figure out what I was doing wrong.
Can anyone please shed light on which approach could be better? (or maybe they are both correct) and try to explain what I am missing to solve this problem.
There are two problems I see in your code:
Wrong parameter passed to keyToValue(). Since you have Image and Path in your enum, the valid values to pass to keyToValue() are "Image" (returns 0), and "Path" (return 1), other values will returns -1.
In the function Scene::compare(), tabs is just created as an empty QStringList, so the code inside the loops for (const QString &color : tabs) are never executed
Below is a test program to show you what I mean:
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QMetaEnum>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
enum LaserTableWidget
{
Images,
Path
};
Q_ENUM(LaserTableWidget)
template<typename enum_type>
QString QtEnumToString (const enum_type value)
{
return QMetaEnum::fromType<enum_type>().valueToKey(value);
}
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include <QDebug>
#include <QStringList>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
// First problem: wrong parameter passed to keyToValue()
qDebug() << 1 << QtEnumToString<LaserTableWidget>(Images);
qDebug() << 2 << QtEnumToString<LaserTableWidget>(Path);
QMetaObject MetaObject = this->staticMetaObject;
QMetaEnum MetaEnum = MetaObject.enumerator(MetaObject.indexOfEnumerator("LaserTableWidget"));
qDebug() << 3 << MetaEnum.keyToValue(QtEnumToString<LaserTableWidget>(Path).toUpper().toLatin1());
qDebug() << 4 << MetaEnum.keyToValue(QtEnumToString<LaserTableWidget>(Path).toStdString().c_str());
switch (MetaEnum.keyToValue(QtEnumToString<LaserTableWidget>(Path).toUpper().toLatin1()))
{
case Images:
qDebug() << "switch Images";
break;
case Path:
qDebug() << "switch Path";
break;
default:
qDebug() << "switch default";
break;
}
// Second problem: tabs is empty
QStringList tabs;
for (const QString &color : tabs)
qDebug() << color; // this line is never executed
}
MainWindow::~MainWindow()
{
}
Output:
1 "Images"
2 "Path"
3 -1
4 1
switch default

C++ Template function with is_same type_trait not working for type T=std::string

I have implemented a simple Xerces-c based C++ library for parsing and reading data items from XML config files. I provide facility to convert data types read into int, long, double, bool, float and string.
All items work fine except std::string where any conversion is not needed. I would simply like to compare using traits and return but it does not work. is_same works only for built in types ?
template<typename T> T CppXMLConfigReader::getTypeVal(const std::string& key, const T& defaultVal) const
{
T returnVal = defaultVal;
auto iter = m_configMapItems.find(key.c_str());
if(iter != m_configMapItems.end())
{
try
{
if(is_same<T,int>::value)
returnVal = stoi(iter->second);
if(is_same<T,float>::value)
returnVal = stof(iter->second);
if(is_same<T,long>::value)
returnVal = stol(iter->second);
if(is_same<T,double>::value)
returnVal = stod(iter->second);
if(is_same<T,bool>::value)
{
if(iter->second == "true" || iter->second == "1")
returnVal=true;
else
returnVal=false;
}
if(is_same<T,string>::value) // Error is from here.
returnVal = iter->second; // Error is from here.
}
catch(const invalid_argument& e)
{
cout << "Exception happened while converting " << iter->second << " Into rqequired type. Please investigate." << endl;
}
}
return(returnVal);
}

Type conversion, 'initializing': cannot convert from 'HtmlBuilder *' to 'HtmlElement'

I was trying to follow a tutorial and I am stuck badly at implementing the fluent builder for the unique_ptr as well.
Despite knowing that it is a type conversion thing and after inspecting the documentation I wasn't able to find a proper fix.
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <memory>
using namespace std;
class HtmlBuilder;
struct HtmlElement
{
string name;
string text;
vector<HtmlElement> elements;
const size_t indent_size = 2;
HtmlElement() {}
HtmlElement(const string& name, const string& text) : name{ name }, text{ text }
{
}
string str(int indent = 0) const // it is a const because it doesn't change the inner elements of htmlelement
{
ostringstream oss;
string i(indent_size * indent, ' '); // repeating a character as many times as required.
oss << i << "<" << name << ">" << endl;
if (text.size() > 0)
oss << string(indent_size * (indent + 1), ' ') << text << endl;
// recursive call
for (const auto& e : elements)
oss << e.str(indent + 1);
oss << i << "</" << name << ">" << endl;
return oss.str();
}
static HtmlBuilder build(string root_name);
static unique_ptr<HtmlBuilder> create(string root_name);
};
struct HtmlBuilder
{
HtmlBuilder(string root_name)
{
root.name = root_name;
}
HtmlElement root; // we can not do anything without root
HtmlBuilder& add_child(string child_name, string child_text)
{
HtmlElement e{ child_name, child_text };
root.elements.emplace_back(e);
// it is a reference
return *this;
}
HtmlBuilder* add_child2(string child_name, string child_text)
{
HtmlElement e{ child_name, child_text };
// emplace_back will return a reference to element that was just created in the vector where as push_back does not return anything, so you could preform some chaining if you wanted
root.elements.emplace_back(e);
// it is a pointer
return this;
}
string str() const {
return root.str();
}
// let's you convert the builder to htmlelement.
// automatic conversion.
// it wil be converted only after the chaining has finished.
operator HtmlElement() { return root; }
/*B& operator= (const A& x) { return *this; }*/
//operator unique_ptr<HtmlElement>() {
// return root;
//}
};
// it had to be pasted here after definition of HtmlBuilder
HtmlBuilder HtmlElement::build(string root_name)
{
// it will get automatically converted to a html element due to
// automatic conversion.
return HtmlBuilder{ root_name };
}
unique_ptr<HtmlBuilder> HtmlElement::create(string root_name) {
return make_unique<HtmlBuilder>(root_name);
}
// Basically we want to create builder from HtmlElement itself
// and be able to add childs as many as we want and at the end
// it will still return an HtmlElement due to automatic conversion
// in this way we hide builder completely
int main()
{
HtmlBuilder builder{ "ul" };
builder.add_child("li", "hello")
.add_child("li", "world");
//HtmlElement e = builder;
// important: automatic conversion occurs only at the end, if the object itself is returned.
HtmlElement e = HtmlElement::build("ul").add_child("li", "test").add_child("li", "test2");
HtmlElement ee = HtmlElement::create("ul")->add_child2("li", "test")->add_child2("li", "test2");
cout << e.str() << endl;
getchar();
return 0;
}
The problem is at trying to use use this line:
HtmlElement::create("ul")->add_child2("li", "test")->add_child2("li", "test2");
It throws the error as explained above. It says that cannot convert from 'HtmlBuilder *' to 'HtmlElement'. Tried several solution but I am a beginner in C++ and have not managed to fix it so far.
You've got an operator() to convert from HtmlBuilder to HtmlElement, but not from HtmBuilder* to HtmlElement. That's the difference between your build() line and your create() line.
So you have to dereference the pointer returned by the create()->add_child2() line.
Try this
HtmlElement ee = *(HtmlElement::create("ul")->add_child2("li", "test")->add_child2("li", "test2"));
Running on Wandbox

How to Search a file in QDir

I am developing an Application for MAC OS X. In which I have to find files in folder. Problem is that I want to give comfort, to user, to search a file by entering a QString. This QString may be the exact name of file or a text contain in the file name.Suppose the file name is "mysamplefile.txt". So if user enter either 'my' ; 'mysample' ; 'samplefile' ; 'mysamplefile' or 'mysamplefile.txt'. In all cases I want to get the QFileInfo for that file. I also give checkbox option 'Match Case' or 'Ignore case' to the user to get fileinfo. I have a QStringList for the strings that user want to search and I also have a QStringList of the locations selected by the user. So I want to search each string name(from QStringList strSearchFileName) in every Path(QStringList searchingdirectorylist). And I want to make a final QFileInfoList for all files after the searching process.
void MainWindowWipe::onSearchingProcess(QStringList strSearchFileName, QStringList searchingdirectorylist)
{
for(int i=0; i<strSearchFileName.size();i++)
{
for(j=0; j<searchingdirectorylist.size();j++)
{
QDir dir(searchingdirectorylist[j]);
dir.setNameFilters(QStringList(strSearchFileName[i]));
dir.setFilter(QDir::Files | QDir::NoDotAndDotDot | QDir::NoSymLinks);
QFileInfoList fileList = dir.entryInfoList();
for (int k=0; k<fileList.count(); k++)
{
QString temp = "";
temp = fileList[k].absoluteFilePath();
}
dir.setFilter(QDir::AllDirs | QDir::NoDotAndDotDot | QDir::NoSymLinks);
QStringList dirList = dir.entryList();
QStringList newList;
for (int l=0; l<dirList.size(); ++l)
{
QString newPath = QString("%1/%2").arg(dir.absolutePath()).arg(dirList.at(i));
newList<<newPath;
onSearchingProcess(strSearchFileName,newList);
}
}
}
}
This function is not working for me this work only when if I search only one file with exact name. But I want to search multiple files with not exact name.
You need to iterate through all the files and folders using a recursive function (or use the iterator). On each iteration you can use the QString::contains() to find out if the file's name contains the target string. Save each matching file name in a list.
#include <QCoreApplication>
#include <QDebug>
#include <QDirIterator>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QString targetStr = "init"; // What we search for
QFileInfoList hitList; // Container for matches
QString directory = "D:/python/"; // Where to search
QDirIterator it(directory, QDirIterator::Subdirectories);
// Iterate through the directory using the QDirIterator
while (it.hasNext()) {
QString filename = it.next();
QFileInfo file(filename);
if (file.isDir()) { // Check if it's a dir
continue;
}
// If the filename contains target string - put it in the hitlist
if (file.fileName().contains(targetStr, Qt::CaseInsensitive)) {
hitList.append(file);
}
}
foreach (QFileInfo hit, hitList) {
qDebug() << hit.absoluteFilePath();
}
return a.exec();
}

I want to really hightlight all word that i find in editor use QScintilla

This is the effect which i want :
this is actual effect.
//follow is code i codeļ¼š
SendScintilla(QsciScintillaBase::SCI_INDICSETSTYLE,0, INDIC_ROUNDBOX);
SendScintilla(QsciScintillaBase::SCI_INDICSETFORE,0, QColor(Qt::yellow));
This is my answer.
SendScintilla(QsciScintillaBase::SCI_INDICSETSTYLE,0, INDIC_BOX);
QString docText = text();
int end = docText.lastIndexOf(findText);
int cur = -1;
if(end != -1) {
while(cur != end) {
cur = docText.indexOf(findText,cur+1);`
SendScintilla(QsciScintillaBase::SCI_INDICATORFILLRANGE,cur,
findText.length());
}
}

Resources