ProjectExplorer: Allow project managers to provide uniquification

... for otherwise identically-named targets.
It happens quite often in larger qmake projects that some applications
in a nested SUBDIRS structure get the same name (e.g. a tool and its
autotest).
It was until now impossible for a user to differentiate between the
corresponding run configurations: In the list of run configs, we just
appended numbers, and in the UI element for manually creating run
configs, the strings were even entirely identical. For a practical
example, open tests.pro in qtbase and count the number of run configs
called "test".
Now we detect such collisions early and append the relative path of the
project file to the display names of the affected run configurations.
For now, this is only done for qmake projects: The problem cannot occur
with qbs, and we don't have any complaints about cmake. The
infrastructure is generic, however.

Fixes: QTCREATORBUG-9563
Change-Id: Ic076df9b5a8bda7c9a1f88df683f33c837eaa197
Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
Christian Kandeler
2019-01-31 18:23:10 +01:00
parent 443931c1da
commit f18214b407
4 changed files with 20 additions and 1 deletions

View File

@@ -41,6 +41,7 @@ class PROJECTEXPLORER_EXPORT BuildTargetInfo
public: public:
QString buildKey; // Used to identify this BuildTargetInfo object in its list. QString buildKey; // Used to identify this BuildTargetInfo object in its list.
QString displayName; QString displayName;
QString displayNameUniquifier;
Utils::FileName targetFilePath; Utils::FileName targetFilePath;
Utils::FileName projectFilePath; Utils::FileName projectFilePath;

View File

@@ -49,6 +49,7 @@
#include <QDir> #include <QDir>
#include <QFormLayout> #include <QFormLayout>
#include <QHash>
#include <QPushButton> #include <QPushButton>
#include <QTimer> #include <QTimer>
#include <QLoggingCategory> #include <QLoggingCategory>
@@ -466,6 +467,7 @@ RunConfigurationFactory::availableCreators(Target *parent) const
rci.id = m_runConfigBaseId; rci.id = m_runConfigBaseId;
rci.buildKey = ti.buildKey; rci.buildKey = ti.buildKey;
rci.displayName = displayName; rci.displayName = displayName;
rci.displayNameUniquifier = ti.displayNameUniquifier;
rci.creationMode = ti.isQtcRunnable || !hasAnyQtcRunnable rci.creationMode = ti.isQtcRunnable || !hasAnyQtcRunnable
? RunConfigurationCreationInfo::AlwaysCreate ? RunConfigurationCreationInfo::AlwaysCreate
: RunConfigurationCreationInfo::ManualCreationOnly; : RunConfigurationCreationInfo::ManualCreationOnly;
@@ -540,7 +542,7 @@ RunConfiguration *RunConfigurationCreationInfo::create(Target *target) const
rc->m_buildKey = buildKey; rc->m_buildKey = buildKey;
rc->doAdditionalSetup(*this); rc->doAdditionalSetup(*this);
rc->setDefaultDisplayName(displayName); rc->setDisplayName(displayName);
return rc; return rc;
} }
@@ -575,6 +577,15 @@ const QList<RunConfigurationCreationInfo> RunConfigurationFactory::creatorsForTa
if (factory->canHandle(parent)) if (factory->canHandle(parent))
items.append(factory->availableCreators(parent)); items.append(factory->availableCreators(parent));
} }
QHash<QString, QList<RunConfigurationCreationInfo *>> itemsPerDisplayName;
for (RunConfigurationCreationInfo &item : items)
itemsPerDisplayName[item.displayName] << &item;
for (auto it = itemsPerDisplayName.cbegin(); it != itemsPerDisplayName.cend(); ++it) {
if (it.value().size() == 1)
continue;
for (RunConfigurationCreationInfo * const rci : it.value())
rci->displayName += rci->displayNameUniquifier;
}
return items; return items;
} }

View File

@@ -234,6 +234,7 @@ public:
Core::Id id; Core::Id id;
QString buildKey; QString buildKey;
QString displayName; QString displayName;
QString displayNameUniquifier;
CreationMode creationMode = AlwaysCreate; CreationMode creationMode = AlwaysCreate;
bool useTerminal = false; bool useTerminal = false;
}; };

View File

@@ -1029,6 +1029,12 @@ void QmakeProject::updateBuildSystemData()
bti.projectFilePath = node->filePath(); bti.projectFilePath = node->filePath();
bti.workingDirectory = FileName::fromString(workingDir); bti.workingDirectory = FileName::fromString(workingDir);
bti.displayName = bti.projectFilePath.toFileInfo().completeBaseName(); bti.displayName = bti.projectFilePath.toFileInfo().completeBaseName();
const FileName relativePathInProject
= bti.projectFilePath.relativeChildPath(projectDirectory());
if (!relativePathInProject.isEmpty()) {
bti.displayNameUniquifier = QString::fromLatin1(" (%1)")
.arg(relativePathInProject.toUserOutput());
}
bti.buildKey = bti.projectFilePath.toString(); bti.buildKey = bti.projectFilePath.toString();
bti.isQtcRunnable = config.contains("qtc_runnable"); bti.isQtcRunnable = config.contains("qtc_runnable");