Android: generate .project and .classpath

These files are needed by the java language server to operate properly.

Change-Id: Ie96a1fe32fefeea7333c7fa752557f79796a1478
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
David Schulz
2021-02-22 12:09:52 +01:00
parent 605df0c4b6
commit 65d977ed93
2 changed files with 117 additions and 4 deletions

View File

@@ -25,11 +25,17 @@
#include "javalanguageserver.h"
#include "androidconfigurations.h"
#include "androidconstants.h"
#include "androidmanager.h"
#include <languageclient/client.h>
#include <languageclient/languageclientinterface.h>
#include <languageclient/languageclientutils.h>
#include <projectexplorer/kitinformation.h>
#include <projectexplorer/project.h>
#include <projectexplorer/projectnodes.h>
#include <projectexplorer/target.h>
#include <utils/environment.h>
#include <utils/pathchooser.h>
#include <utils/temporarydirectory.h>
@@ -41,7 +47,6 @@
using namespace Utils;
constexpr char languageServerKey[] = "languageServer";
constexpr char workspaceKey[] = "workspace";
namespace Android {
namespace Internal {
@@ -199,6 +204,12 @@ public:
using Client::Client;
void executeCommand(const LanguageServerProtocol::Command &command) override;
void setCurrentProject(ProjectExplorer::Project *project) override;
void updateProjectFiles();
void updateTarget(ProjectExplorer::Target *target);
private:
ProjectExplorer::Target *m_currentTarget = nullptr;
};
void JLSClient::executeCommand(const LanguageServerProtocol::Command &command)
@@ -217,6 +228,108 @@ void JLSClient::executeCommand(const LanguageServerProtocol::Command &command)
}
}
void JLSClient::setCurrentProject(ProjectExplorer::Project *project)
{
Client::setCurrentProject(project);
QTC_ASSERT(project, return);
updateTarget(project->activeTarget());
updateProjectFiles();
connect(project, &ProjectExplorer::Project::activeTargetChanged,
this, &JLSClient::updateTarget);
}
static void generateProjectFile(const FilePath &projectDir, const QString &projectName)
{
const FilePath projectFilePath = projectDir.pathAppended(".project");
QFile projectFile(projectFilePath.toString());
if (projectFile.open(QFile::Truncate | QFile::WriteOnly)) {
QXmlStreamWriter writer(&projectFile);
writer.setAutoFormatting(true);
writer.writeStartDocument();
writer.writeComment("Autogenerated by Qt Creator. "
"Changes to this file will not be taken into account.");
writer.writeStartElement("projectDescription");
writer.writeTextElement("name", projectName);
writer.writeStartElement("natures");
writer.writeTextElement("nature", "org.eclipse.jdt.core.javanature");
writer.writeEndElement(); // natures
writer.writeEndElement(); // projectDescription
writer.writeEndDocument();
projectFile.close();
}
}
static void generateClassPathFile(const FilePath &projectDir,
const QString &sourceDir,
const QStringList &libs)
{
const FilePath classPathFilePath = projectDir.pathAppended(".classpath");
QFile classPathFile(classPathFilePath.toString());
if (classPathFile.open(QFile::Truncate | QFile::WriteOnly)) {
QXmlStreamWriter writer(&classPathFile);
writer.setAutoFormatting(true);
writer.writeStartDocument();
writer.writeComment("Autogenerated by Qt Creator. "
"Changes to this file will not be taken into account.");
writer.writeStartElement("classpath");
writer.writeEmptyElement("classpathentry");
writer.writeAttribute("kind", "src");
writer.writeAttribute("path", sourceDir);
for (const QString &lib : libs) {
writer.writeEmptyElement("classpathentry");
writer.writeAttribute("kind", "lib");
writer.writeAttribute("path", lib);
}
writer.writeEndElement(); // classpath
writer.writeEndDocument();
classPathFile.close();
}
}
void JLSClient::updateProjectFiles()
{
using namespace ProjectExplorer;
if (!m_currentTarget)
return;
if (Target *target = m_currentTarget) {
Kit *kit = m_currentTarget->kit();
if (DeviceTypeKitAspect::deviceTypeId(kit) != Android::Constants::ANDROID_DEVICE_TYPE)
return;
if (ProjectNode *node = project()->findNodeForBuildKey(target->activeBuildKey())) {
const FilePath &projectDir = project()->rootProjectDirectory();
if (!projectDir.exists())
return;
FilePath sourceDir = FilePath::fromVariant(
node->data(Constants::AndroidPackageSourceDir));
sourceDir = sourceDir.pathAppended("src");
if (!sourceDir.exists())
return;
sourceDir = sourceDir.relativeChildPath(projectDir);
const FilePath &sdkLocation = AndroidConfigurations::currentConfig().sdkLocation();
const QString &targetSDK = AndroidManager::buildTargetSDK(m_currentTarget);
const QString androidJar = QString("%1/platforms/%2/android.jar")
.arg(sdkLocation.toString(), targetSDK);
const QStringList libs(androidJar);
generateClassPathFile(projectDir, sourceDir.toString(), libs);
generateProjectFile(projectDir, project()->displayName());
}
}
}
void JLSClient::updateTarget(ProjectExplorer::Target *target)
{
if (m_currentTarget) {
disconnect(m_currentTarget, &ProjectExplorer::Target::parsingFinished,
this, &JLSClient::updateProjectFiles);
}
m_currentTarget = target;
if (m_currentTarget) {
connect(m_currentTarget, &ProjectExplorer::Target::parsingFinished,
this, &JLSClient::updateProjectFiles);
}
updateProjectFiles();
}
LanguageClient::Client *JLSSettings::createClient(LanguageClient::BaseClientInterface *interface) const
{
return new JLSClient(interface);

View File

@@ -134,10 +134,10 @@ public:
bool documentUpdatePostponed(const Utils::FilePath &fileName) const;
// workspace control
void setCurrentProject(ProjectExplorer::Project *project);
virtual void setCurrentProject(ProjectExplorer::Project *project);
const ProjectExplorer::Project *project() const;
void projectOpened(ProjectExplorer::Project *project);
void projectClosed(ProjectExplorer::Project *project);
virtual void projectOpened(ProjectExplorer::Project *project);
virtual void projectClosed(ProjectExplorer::Project *project);
// commands
void requestCodeActions(const LanguageServerProtocol::DocumentUri &uri,