1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-08-10 09:45:39 +02:00

Bug 422797 - API for retrieving QMake information from Qt project

API is located at org.eclipse.cdt.qt.core.index package.
Entry point is QMakeProjectInfoFactory.getForActiveConfigurationIn method
that provides ability to retrieve QMake information (IQMakeInfo interface)
for active project configuration of a specified project.
Also allows to listen on changes of such information.

qmakeEnvProvider extensions allows CDT build-system to provide environment
for QMake runs within their build-system.

Information is gather by parsing output of:
1) qmake -query
2) qmake -E file.pro // only for QMake version 3.0

Change-Id: Iae569bdbc89dc26d60530596b66b5227f36dfae6
Signed-off-by: David Kaspar <dkaspar@blackberry.com>
Reviewed-on: https://git.eclipse.org/r/19082
Reviewed-by: Andrew Eidsness <eclipse@jfront.com>
Tested-by: Hudson CI
Reviewed-by: Doug Schaefer <dschaefer@qnx.com>
IP-Clean: Doug Schaefer <dschaefer@qnx.com>
This commit is contained in:
David Kaspar 2013-11-28 19:58:37 +01:00 committed by Doug Schaefer
parent f887c8e671
commit 026b9325f0
21 changed files with 1730 additions and 6 deletions

View file

@ -7,8 +7,10 @@ Bundle-Activator: org.eclipse.cdt.qt.core.QtPlugin
Bundle-Vendor: Eclipse CDT Bundle-Vendor: Eclipse CDT
Require-Bundle: org.eclipse.core.runtime, Require-Bundle: org.eclipse.core.runtime,
org.eclipse.core.resources, org.eclipse.core.resources,
org.eclipse.core.expressions;bundle-version="[3.2.0,4.0.0)",
org.eclipse.cdt.core org.eclipse.cdt.core
Bundle-RequiredExecutionEnvironment: JavaSE-1.6 Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Bundle-ActivationPolicy: lazy Bundle-ActivationPolicy: lazy
Bundle-Localization: plugin Bundle-Localization: plugin
Export-Package: org.eclipse.cdt.qt.core Export-Package: org.eclipse.cdt.qt.core,
org.eclipse.cdt.qt.core.index

View file

@ -5,4 +5,5 @@ bin.includes = META-INF/,\
plugin.xml,\ plugin.xml,\
templates/,\ templates/,\
about.html about.html
src.includes = about.html src.includes = about.html,\
schema/

View file

@ -1,2 +1,3 @@
qtProjectFile.name = Qt Project File qtProjectFile.name = Qt Project File
qmlFile.name = QML File qmlFile.name = QML File
qmakeEnvProvider.name = QMake Environment Provider

View file

@ -1,6 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.4"?> <?eclipse version="3.4"?>
<plugin> <plugin>
<extension-point id="qmakeEnvProvider" name="%qmakeEnvProvider.name" schema="schema/qmakeEnvProvider.exsd"/>
<extension <extension
point="org.eclipse.cdt.core.templates"> point="org.eclipse.cdt.core.templates">
<template <template

View file

@ -0,0 +1,136 @@
<?xml version='1.0' encoding='UTF-8'?>
<!-- Schema file written by PDE -->
<schema targetNamespace="org.eclipse.cdt.qt.core" xmlns="http://www.w3.org/2001/XMLSchema">
<annotation>
<appinfo>
<meta.schema plugin="org.eclipse.cdt.qt.core" id="qmakeEnvProvider" name="QMake Environment Provider"/>
</appinfo>
<documentation>
This extension point allows to provide environment for qmake cmd-line tool execution.
</documentation>
</annotation>
<include schemaLocation="schema://org.eclipse.core.expressions/schema/expressionLanguage.exsd"/>
<element name="extension">
<annotation>
<appinfo>
<meta.element />
</appinfo>
</annotation>
<complexType>
<sequence>
<element ref="qmakeEnvProvider" minOccurs="1" maxOccurs="unbounded"/>
</sequence>
<attribute name="point" type="string" use="required">
<annotation>
<documentation>
a fully qualified identifier of the target extension point
</documentation>
</annotation>
</attribute>
<attribute name="id" type="string">
<annotation>
<documentation>
an optional identifier of the extension instance
</documentation>
</annotation>
</attribute>
<attribute name="name" type="string">
<annotation>
<documentation>
an optional name of the extension instance
</documentation>
<appinfo>
<meta.attribute translatable="true"/>
</appinfo>
</annotation>
</attribute>
</complexType>
</element>
<element name="qmakeEnvProvider">
<complexType>
<sequence>
<element ref="enablement" minOccurs="0" maxOccurs="1"/>
</sequence>
<attribute name="class" type="string" use="required">
<annotation>
<documentation>
Implementation of QMake environment provider which is used to determinate environment for running QMake.
</documentation>
<appinfo>
<meta.attribute kind="java" basedOn=":org.eclipse.cdt.qt.core.index.IQMakeEnvProvider"/>
</appinfo>
</annotation>
</attribute>
<attribute name="priority" type="integer" default="0">
<annotation>
<documentation>
Priority of QMake environment provider. Less number means higher priority. Default priority is 0.
</documentation>
</annotation>
</attribute>
</complexType>
</element>
<annotation>
<appinfo>
<meta.section type="since"/>
</appinfo>
<documentation>
8.2
</documentation>
</annotation>
<annotation>
<appinfo>
<meta.section type="examples"/>
</appinfo>
<documentation>
The following is an example of a qmakeEnvProvider contribution:
&lt;p&gt;
&lt;pre&gt;
&lt;extension
point=&quot;org.eclipse.cdt.qt.core.qmakeEnvProvider&quot;
id=&quot;example&quot;
name=&quot;Example QMake Env Provider Extension&quot;&gt;
&lt;qmakeEnvProvider
class=&quot;com.example.internal.ExampleProvider&quot;&gt;
&lt;enablement&gt;
&lt;with variable=&quot;projectNatures&quot;&gt;
&lt;iterate operator=&quot;or&quot;&gt;
&lt;equals value=&quot;com.example.my-nature&quot;/&gt;
&lt;/iterate&gt;
&lt;/with&gt;
&lt;/enablement&gt;
&lt;/qmakeEnvProvider&gt;
&lt;/extension&gt;
&lt;/pre&gt;
&lt;/p&gt;
</documentation>
</annotation>
<annotation>
<appinfo>
<meta.section type="apiinfo"/>
</appinfo>
<documentation>
The contributed class must implement &lt;code&gt;org.eclipse.cdt.qt.core.index.IQMakeEnvProvider&lt;/code&gt;.
</documentation>
</annotation>
<annotation>
<appinfo>
<meta.section type="copyright"/>
</appinfo>
<documentation>
Copyright (c) 2013 QNX Software Systems and others.
All rights reserved. This program and the accompanying materials
are made available under the terms of the Eclipse Public License v1.0
which accompanies this distribution, and is available at
http://www.eclipse.org/legal/epl-v10.html
</documentation>
</annotation>
</schema>

View file

@ -0,0 +1,146 @@
/*
* Copyright (c) 2013 QNX Software Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.cdt.internal.qt.core.index;
import java.util.Arrays;
import java.util.concurrent.atomic.AtomicReference;
import org.eclipse.cdt.core.settings.model.ICConfigurationDescription;
import org.eclipse.cdt.qt.core.QtPlugin;
import org.eclipse.cdt.qt.core.index.IQMakeEnv;
import org.eclipse.cdt.qt.core.index.IQMakeEnvProvider;
import org.eclipse.cdt.qt.core.index.IQMakeEnvProvider.IController;
import org.eclipse.core.expressions.EvaluationContext;
import org.eclipse.core.expressions.EvaluationResult;
import org.eclipse.core.expressions.Expression;
import org.eclipse.core.expressions.ExpressionConverter;
import org.eclipse.core.expressions.ExpressionTagNames;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
/**
* Represents a IQMakeEnvProvider that is registered via qmakeEnvProvider extension point.
*/
public final class QMakeEnvProviderDescriptor implements Comparable<QMakeEnvProviderDescriptor> {
private static final String ATTR_CLASS = "class"; //$NON-NLS-1$
private static final String ATTR_PRIORITY = "priority"; //$NON-NLS-1$
private static final String VAR_PROJECTNATURES = "projectNatures"; //$NON-NLS-1$
private final IConfigurationElement element;
private final String id;
private final int priority;
private final AtomicReference<Boolean> evaluation = new AtomicReference<Boolean>();
private final Expression enablementExpression;
private IQMakeEnvProvider provider;
QMakeEnvProviderDescriptor(IConfigurationElement element) {
this.element = element;
id = element.getContributor().getName();
// parse priority
int prio = 0;
String priorityString = element.getAttribute(ATTR_PRIORITY);
if (priorityString != null) {
try {
prio = Integer.parseInt(priorityString);
} catch (NumberFormatException e) {
QtPlugin.log("Invalid priority value of " + id, e); //$NON-NLS-1$
}
}
this.priority = prio;
// parse enablement expression
Expression expr = null;
IConfigurationElement[] children = element.getChildren(ExpressionTagNames.ENABLEMENT);
switch (children.length) {
case 0:
evaluation.set(Boolean.TRUE);
break;
case 1:
try {
ExpressionConverter parser = ExpressionConverter.getDefault();
expr = parser.perform(children[0]);
} catch (CoreException e) {
QtPlugin.log("Error in enablement expression of " + id, e); //$NON-NLS-1$
}
break;
default:
QtPlugin.log("Too many enablement expressions for " + id); //$NON-NLS-1$
evaluation.set(Boolean.FALSE);
break;
}
enablementExpression = expr;
}
@Override
public int compareTo(QMakeEnvProviderDescriptor that) {
if (that == null) {
return -1;
}
return this.priority - that.priority;
}
/**
* Used by QMakeEnvProviderManager to ask for creating a IQMakeEnv for a specific IQMakeEnvProvider.IController using the related IQMakeEnvProvider
*
* @param controller the controller
* @return the IQMakeEnv instance; or null if no instance is provided
*/
public IQMakeEnv createEnv(IController controller) {
if (! matches(controller)) {
return null;
}
if (provider == null) {
synchronized (this) {
if (provider == null) {
try {
provider = (IQMakeEnvProvider) element.createExecutableExtension(ATTR_CLASS);
} catch (CoreException e) {
QtPlugin.log("Error in class attribute of " + id, e); //$NON-NLS-1$
return null;
}
}
}
}
return provider.createEnv(controller);
}
/**
* Checks whether an enablement expression evaluation is true.
*
* @param controller the controller
* @return true if the provider can be used; false otherwise
*/
private boolean matches(IController controller) {
Boolean eval = evaluation.get();
if (eval != null) {
return eval.booleanValue();
}
if (enablementExpression != null) {
ICConfigurationDescription configuration = controller != null ? controller.getConfiguration() : null;
IProject project = configuration != null ? configuration.getProjectDescription().getProject() : null;
EvaluationContext evalContext = new EvaluationContext(null, project);
try {
if (project != null) {
String[] natures = project.getDescription().getNatureIds();
evalContext.addVariable(VAR_PROJECTNATURES, Arrays.asList(natures));
}
return enablementExpression.evaluate(evalContext) == EvaluationResult.TRUE;
} catch (CoreException e) {
QtPlugin.log("Error while evaluating enablement expression for " + id, e); //$NON-NLS-1$
}
}
evaluation.set(Boolean.FALSE);
return false;
}
}

View file

@ -0,0 +1,117 @@
/*
* Copyright (c) 2013 QNX Software Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.cdt.internal.qt.core.index;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.envvar.IEnvironmentVariable;
import org.eclipse.cdt.core.settings.model.ICConfigurationDescription;
import org.eclipse.cdt.qt.core.QtPlugin;
import org.eclipse.cdt.qt.core.index.IQMakeEnv;
import org.eclipse.cdt.qt.core.index.IQMakeEnvProvider;
import org.eclipse.cdt.qt.core.index.QMakeEnvInfo;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.Platform;
/**
* Represents a manager of registered qmakeEnvProvider extensions.
*/
public final class QMakeEnvProviderManager {
private static QMakeEnvProviderManager INSTANCE = new QMakeEnvProviderManager();
private final List<QMakeEnvProviderDescriptor> descriptors;
public static QMakeEnvProviderManager getInstance() {
return INSTANCE;
}
private QMakeEnvProviderManager() {
descriptors = loadDescriptors();
}
/**
* Returns a list of all registerd qmakeEnvProvider extensions.
*
* @return the list of extensions
*/
private static List<QMakeEnvProviderDescriptor> loadDescriptors() {
List<QMakeEnvProviderDescriptor> descriptors = new ArrayList<QMakeEnvProviderDescriptor>();
IConfigurationElement[] elements = Platform.getExtensionRegistry()
.getConfigurationElementsFor(QtPlugin.ID, QtPlugin.QMAKE_ENV_PROVIDER_EXT_POINT_NAME);
for (IConfigurationElement element : elements) {
descriptors.add(new QMakeEnvProviderDescriptor(element));
}
Collections.sort(descriptors);
return descriptors;
}
/**
* Called by QMakeProjectInfo to create IQMakeEnv for a specified IController.
* It asks each qmakeEnvProvider extensions to provide the instance. If none of them provides, then the default IQMakeEnvProvider is returned.
*
* @param controller the controller
* @return the IQMakeEnv instance for specifying the QMake environment
*/
public IQMakeEnv createEnv(IQMakeEnvProvider.IController controller) {
for (QMakeEnvProviderDescriptor descriptor : descriptors) {
IQMakeEnv env = descriptor.createEnv(controller);
if (env != null) {
return env;
}
}
return new ConfigurationQMakeEnv(controller.getConfiguration());
}
/**
* Represents a fallback IQMakeEnvProvider that is used for a project that has QtNature
* while there is no registered IQMakeEnvProvider that would provide any IQMakeEnv.
*/
private static class ConfigurationQMakeEnv implements IQMakeEnv {
private static final String PRO_FILE_SUFFIX = ".pro"; //$NON-NLS-1$
private static final String ENV_VAR_QMAKE = "QMAKE"; //$NON-NLS-1$
private final ICConfigurationDescription configuration;
public ConfigurationQMakeEnv(ICConfigurationDescription configuration) {
this.configuration = configuration;
}
@Override
public void destroy() {
}
/**
* Returns QMakeEnvInfo resolved from a project in a generic way.
* If exists, the root-level .pro file is resolved as the one that is located directly under the project and has the same name.
* If exists, qmake executable is resolved from "QMAKE" environment variable that is stored in the project configuration.
*
* @return the QMakeEnvInfo instance if the project configuration exists; otherwise null.
*/
@Override
public QMakeEnvInfo getQMakeEnvInfo() {
if (configuration == null) {
return null;
}
IProject project = configuration.getProjectDescription().getProject();
IFile proFile = project != null ? project.getFile(project.getName() + PRO_FILE_SUFFIX) : null;
IEnvironmentVariable variable = CCorePlugin.getDefault().getBuildEnvironmentManager().getVariable(ENV_VAR_QMAKE, configuration, true);
String qmakeFilePath = variable != null ? variable.getValue() : null;
return new QMakeEnvInfo(proFile, qmakeFilePath, Collections.<String,String>emptyMap(), Collections.<IFile>emptyList());
}
}
}

View file

@ -0,0 +1,199 @@
/*
* Copyright (c) 2013 QNX Software Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.cdt.internal.qt.core.index;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import org.eclipse.cdt.qt.core.QtPlugin;
import org.eclipse.cdt.qt.core.index.IQtVersion;
import org.eclipse.cdt.qt.core.index.IQMakeInfo;
import org.eclipse.cdt.utils.spawner.ProcessFactory;
/**
* Holder for QMake information.
*/
public final class QMakeInfo implements IQMakeInfo {
// reg. exp. for parsing output of "qmake -query" command
public static final Pattern PATTERN_QUERY_LINE = Pattern.compile("^(\\w+):(.*)$");
// reg. exp. for parsing output of "qmake -E file.pro" command (for QMake 3.0 only)
public static final Pattern PATTERN_EVAL_LINE = Pattern.compile("^([a-zA-Z0-9_\\.]+)\\s*=\\s*(.*)$");
/**
* Instance that is used to present an invalid IQMakeInfo.
*/
public static final IQMakeInfo INVALID = new QMakeInfo(
false, null, Collections.<String>emptyList(), Collections.<String>emptyList(),
Collections.<String>emptyList(), Collections.<String>emptyList(), Collections.<String>emptyList(),
Collections.<String>emptyList(), Collections.<String>emptyList(), Collections.<String>emptyList());
private final boolean valid;
private final IQtVersion qtVersion;
private final List<String> involvedQMakeFiles;
private final List<String> qtImportPath;
private final List<String> qtQmlPath;
private final List<String> includePath;
private final List<String> defines;
private final List<String> sourceFiles;
private final List<String> headerFiles;
private final List<String> otherFiles;
private QMakeInfo(boolean valid, IQtVersion qtVersion, List<String> involvedQMakeFiles, List<String> qtImportPath, List<String> qtQmlPath, List<String> includePath, List<String> defines, List<String> sourceFiles, List<String> headerFiles, List<String> otherFiles) {
this.valid = valid;
this.qtVersion = qtVersion;
this.involvedQMakeFiles = Collections.unmodifiableList(involvedQMakeFiles);
this.qtImportPath = Collections.unmodifiableList(qtImportPath);
this.qtQmlPath = Collections.unmodifiableList(qtQmlPath);
this.includePath = Collections.unmodifiableList(includePath);
this.defines = Collections.unmodifiableList(defines);
this.sourceFiles = Collections.unmodifiableList(sourceFiles);
this.headerFiles = Collections.unmodifiableList(headerFiles);
this.otherFiles = Collections.unmodifiableList(otherFiles);
}
public static IQMakeInfo create(File projectFile, File qmake, String[] extraEnv) {
return create(projectFile.getAbsolutePath(), qmake.getAbsolutePath(), extraEnv);
}
public static IQMakeInfo create(String proPath, String qmakePath, String[] extraEnv) {
if (proPath == null || qmakePath == null) {
return INVALID;
}
// run "qmake -query"
Map<String, String> qmake1 = exec(PATTERN_QUERY_LINE, extraEnv, qmakePath, "-query");
if (qmake1 == null)
return INVALID;
// check the qmake version
QMakeVersion version = QMakeVersion.create(qmake1.get(QMakeParser.KEY_QMAKE_VERSION));
// TODO - no support for pre-3.0
// for QMake version 3.0 or newer, run "qmake -E file.pro"
Map<String, String> qmake2 = version != null && version.getMajor() >= 3 ? exec(PATTERN_EVAL_LINE, extraEnv, qmakePath, "-E", proPath) : Collections.<String,String>emptyMap();
IQtVersion qtVersion = QMakeVersion.create(qmake1.get(QMakeParser.KEY_QT_VERSION));
List<String> qtImportPaths = QMakeParser.singleValue(qmake1, QMakeParser.KEY_QT_INSTALL_IMPORTS);
List<String> qtQmlPaths = QMakeParser.singleValue(qmake1, QMakeParser.KEY_QT_INSTALL_QML);
List<String> involvedQMakeFiles = QMakeParser.qmake3DecodeValueList(qmake2, QMakeParser.KEY_QMAKE_INTERNAL_INCLUDED_FILES);
List<String> includePath = QMakeParser.qmake3DecodeValueList(qmake2, QMakeParser.KEY_INCLUDEPATH);
List<String> defines = QMakeParser.qmake3DecodeValueList(qmake2, QMakeParser.KEY_DEFINES);
List<String> sourceFiles = QMakeParser.qmake3DecodeValueList(qmake2, QMakeParser.KEY_SOURCES);
List<String> headerFiles = QMakeParser.qmake3DecodeValueList(qmake2, QMakeParser.KEY_HEADERS);
List<String> otherFiles = QMakeParser.qmake3DecodeValueList(qmake2, QMakeParser.KEY_HEADERS);
List<String> qmlImportPath = QMakeParser.qmake3DecodeValueList(qmake2, QMakeParser.KEY_QML_IMPORT_PATH);
// combine qtImportPath and qtQmlPath from both qmake runs
List<String> realQtImportPaths = new ArrayList<String>(qtImportPaths);
realQtImportPaths.addAll(qmlImportPath);
List<String> realQtQmlPaths = new ArrayList<String>(qtQmlPaths);
realQtQmlPaths.addAll(qmlImportPath);
return new QMakeInfo(true, qtVersion, involvedQMakeFiles, realQtImportPaths, realQtQmlPaths, includePath, defines, sourceFiles, headerFiles, otherFiles);
}
@Override
public boolean isValid() {
return valid;
}
@Override
public IQtVersion getQtVersion() {
return qtVersion;
}
@Override
public List<String> getInvolvedQMakeFiles() {
return involvedQMakeFiles;
}
@Override
public List<String> getQtImportPath() {
return qtImportPath;
}
@Override
public List<String> getQtQmlPath() {
return qtQmlPath;
}
@Override
public List<String> getIncludePath() {
return includePath;
}
@Override
public List<String> getDefines() {
return defines;
}
@Override
public List<String> getSourceFiles() {
return sourceFiles;
}
@Override
public List<String> getHeaderFiles() {
return headerFiles;
}
@Override
public List<String> getOtherFiles() {
return otherFiles;
}
/**
* Executes a command and parses its output into a map.
*
* @param regex the reg. exp. used for parsing the output
* @param extraEnv the extra environment for command
* @param cmd the command line
* @return the map of resolved key-value pairs
*/
@SuppressWarnings("resource")
private static Map<String, String> exec(Pattern regex, String[] extraEnv, String...command) {
if (command.length < 1 || ! new File(command[0]).exists()) {
QtPlugin.log("qmake: cannot run command: " + (command.length > 0 ? command[0] : ""));
return null;
}
BufferedReader reader = null;
Process process = null;
try {
if (extraEnv != null && extraEnv.length > 0) {
process = ProcessFactory.getFactory().exec(command, extraEnv);
} else {
process = ProcessFactory.getFactory().exec(command);
}
reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
return QMakeParser.parse(regex, reader);
} catch(IOException e) {
QtPlugin.log(e);
return null;
} finally {
if (reader != null)
try {
reader.close();
} catch(IOException e) {
/* ignore */
}
if (process != null) {
process.destroy();
}
}
}
}

View file

@ -0,0 +1,211 @@
/*
* Copyright (c) 2013 QNX Software Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.cdt.internal.qt.core.index;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.cdt.qt.core.QtPlugin;
/**
* Provides a parser for QMake output.
*/
public final class QMakeParser {
public static final String KEY_QMAKE_VERSION = "QMAKE_VERSION";
public static final String KEY_QT_VERSION = "QT_VERSION";
public static final String KEY_QT_INSTALL_IMPORTS = "QT_INSTALL_IMPORTS";
public static final String KEY_QT_INSTALL_QML = "QT_INSTALL_QML";
public static final String KEY_QMAKE_INTERNAL_INCLUDED_FILES = "QMAKE_INTERNAL_INCLUDED_FILES";
public static final String KEY_SOURCES = "SOURCES";
public static final String KEY_HEADERS = "HEADERS";
public static final String KEY_INCLUDEPATH = "INCLUDEPATH";
public static final String KEY_DEFINES = "DEFINES";
public static final String KEY_QML_IMPORT_PATH = "QML_IMPORT_PATH";
/**
* Parses QMake output via a specified reg. exp.
*
* @param regex the reg. exp.
* @param reader the QMake output
* @return the map of parsed key-value pairs
* @throws IOException when io error happens
*/
public static Map<String, String> parse(Pattern regex, BufferedReader reader) throws IOException {
Map<String, String> result = new LinkedHashMap<String, String>();
String line;
while((line = reader.readLine()) != null) {
Matcher m = regex.matcher(line);
if (!m.matches() || m.groupCount() != 2) {
QtPlugin.log("qmake: cannot decode query line '" + line + '\'');
} else {
String key = m.group(1);
String value = m.group(2);
String oldValue = result.put(key, value);
if (oldValue != null)
QtPlugin.log("qmake: duplicate keys in query info '" + line + "' was '" + oldValue + '\'');
}
}
return result;
}
/**
* Returns a list with 0-1 values for a specific QMake variable.
*
* @param map the map
* @param key the QMake variable
* @return the list of values
*/
public static List<String> singleValue(Map<String, String> map, String key) {
String value = map.get(key);
return value == null ? Collections.<String>emptyList() : Collections.singletonList(value);
}
/**
* Returns a list of values for a specific QMake variable that is decoded as a list of values.
*
* @param map the map
* @param key the QMake variable
* @return the list of values
*/
public static List<String> qmake3DecodeValueList(Map<String, String> map, String key) {
String value = map.get(key);
if (value == null) {
return Collections.emptyList();
}
List<String> result = new ArrayList<String>();
for (String item : qmake3SplitValueList(value)) {
result.add(qmake3DecodeValue(item));
}
return result;
}
/**
* Decodes a specified QMake variable value.
*
* @param value the value
* @return the decoded value
*/
public static String qmake3DecodeValue(String value) {
int length = value.length();
if (length >= 2 && value.charAt(0) == '"' && value.charAt(length - 1) == '"') {
value = value.substring(1, length - 1);
length = value.length();
}
StringBuilder sb = new StringBuilder(length);
for (int i = 0; i < length; i ++) {
char c = value.charAt(i);
if (c == '\\') {
++ i;
if (i < length) {
char next = value.charAt(i);
switch (next) {
case 'r':
sb.append('\r');
break;
case 'n':
sb.append ('\n');
break;
case 't':
sb.append ('\t');
break;
case '\\':
case '\'':
case '"':
sb.append (next);
break;
case 'x':
i += 2;
if (i < length) {
char first = value.charAt(i - 1);
char second = value.charAt(i);
if (first >= '0' && first <= '9' && second >= '0' && second <= '9') {
sb.append ((char) ((first - '0') * 16 + (second - '0')));
}
}
}
}
} else {
sb.append (c);
}
}
return sb.toString();
}
/**
* Splits a specified QMake variable value into a list of values.
*
* @param value the value
* @return the list of values
*/
private static List<String> qmake3SplitValueList(String value) {
List<String> result = new ArrayList<String>();
StringBuilder sb = new StringBuilder();
char quote = 0;
boolean hadWord = false;
final int length = value.length();
for (int i = 0; i < length; i ++) {
char c = value.charAt(i);
if (quote == c) {
quote = 0;
hadWord = true;
sb.append(c);
continue;
}
switch (c) {
case '"':
case '\'':
quote = c;
hadWord = true;
break;
case ' ':
case '\t':
if (quote == 0) {
if (hadWord) {
result.add(sb.toString());
sb.delete(0, sb.length());
hadWord = false;
}
continue;
}
break;
case '\\':
if (i + 1 < length) {
char nextChar = value.charAt(i + 1);
if (nextChar == '\'' || nextChar == '"' || nextChar == '\\') {
sb.append(c);
c = nextChar;
++ i;
}
}
//$FALL-THROUGH$
default:
hadWord = true;
break;
}
sb.append (c);
}
if (hadWord) {
result.add(sb.toString());
}
return Collections.unmodifiableList(result);
}
}

View file

@ -0,0 +1,426 @@
/*
* Copyright (c) 2013 QNX Software Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.cdt.internal.qt.core.index;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import org.eclipse.cdt.core.model.CoreModel;
import org.eclipse.cdt.core.settings.model.CProjectDescriptionEvent;
import org.eclipse.cdt.core.settings.model.ICConfigurationDescription;
import org.eclipse.cdt.core.settings.model.ICDescriptionDelta;
import org.eclipse.cdt.core.settings.model.ICProjectDescription;
import org.eclipse.cdt.core.settings.model.ICProjectDescriptionListener;
import org.eclipse.cdt.qt.core.QtNature;
import org.eclipse.cdt.qt.core.index.IQMakeEnv;
import org.eclipse.cdt.qt.core.index.IQMakeEnvProvider;
import org.eclipse.cdt.qt.core.index.IQMakeProjectInfo;
import org.eclipse.cdt.qt.core.index.IQMakeProjectInfoListener;
import org.eclipse.cdt.qt.core.index.QMakeEnvInfo;
import org.eclipse.cdt.qt.core.index.IQMakeInfo;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IResourceDeltaVisitor;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
/**
* Represents a QMake project information that is based on an activate project configuration of a specified related IProject.
* Allows to resolve actual information and listen its change.
* Manages life-cycle of all QMakeProjectInfo instances.
*/
public final class QMakeProjectInfo implements IQMakeProjectInfo, ICProjectDescriptionListener {
private static final RCListener LISTENER = new RCListener();
// sync object for CACHE field
private static final Object SYNC = new Object();
// a map of all QMakeProjectInfo instances
private static final Map<IProject,QMakeProjectInfo> CACHE = new HashMap<IProject,QMakeProjectInfo>();
// called by QtPlugin activator to setup this class
public static final void start() {
ResourcesPlugin.getWorkspace().addResourceChangeListener(LISTENER, IResourceChangeEvent.POST_CHANGE | IResourceChangeEvent.PRE_CLOSE | IResourceChangeEvent.PRE_DELETE);
}
// called by QtPlugin activator to clean up this class
public static final void stop() {
ResourcesPlugin.getWorkspace().removeResourceChangeListener(LISTENER);
synchronized (SYNC) {
while (true) {
Iterator<IProject> iterator = CACHE.keySet().iterator();
if (!iterator.hasNext()) {
break;
}
removeProjectFromCache(iterator.next());
}
}
}
/**
* Returns a QMakeProjectInfo for an active project configuration of a specified project.
*
* @param project the project
* @return the QMakeProjectInfo; or null if the project does not have QtNature
*/
public static QMakeProjectInfo getQMakeProjectInfoFor(IProject project) {
synchronized (SYNC) {
QMakeProjectInfo info = CACHE.get(project);
if (info == null) {
if (QtNature.hasNature(project)) {
info = new QMakeProjectInfo(project);
CACHE.put(project,info);
}
}
return info;
}
}
// removes the project from the CACHE
private static void removeProjectFromCache(IResource project) {
QMakeProjectInfo info;
synchronized (SYNC) {
info = CACHE.remove(project);
}
if (info != null) {
info.destroy();
}
}
private final ICProjectDescription projectDescription;
// sync object for all mutable fields
private final Object sync = new Object();
// true if this instance still registered in CACHE
private boolean live = true;
// a set of sensitive files that might affects actual QMake information
private final SensitiveSet sensitiveFilePathSet = new SensitiveSet();
// an active project configuration
private ControllerImpl activeController;
// the last calculated QMake info; null if not calculated
private IQMakeInfo qmakeInfo = null;
// listeners
private final List<IQMakeProjectInfoListener> listeners = new CopyOnWriteArrayList<IQMakeProjectInfoListener>();
private QMakeProjectInfo(IProject project) {
projectDescription = CoreModel.getDefault().getProjectDescriptionManager().getProjectDescription(project);
CoreModel.getDefault().addCProjectDescriptionListener(this, ICDescriptionDelta.ACTIVE_CFG);
updateActiveConfiguration();
}
// called from removeProjectFromCache only
private void destroy() {
synchronized (sync) {
if (! live) {
return;
}
live = false;
CoreModel.getDefault().removeCProjectDescriptionListener(this);
removeActiveConfiguration();
qmakeInfo = QMakeInfo.INVALID;
}
}
// removes active configuration
private void removeActiveConfiguration() {
ControllerImpl previous = activeController;
activeController = null;
if (previous != null) {
previous.destroy();
}
}
// updates active configuration
private void updateActiveConfiguration() {
ICConfigurationDescription configuration = projectDescription.getActiveConfiguration();
if (configuration != null) {
activeController = new ControllerImpl(configuration);
}
scheduleFetchQMakeInfo();
}
// called on active project configuration change
@Override
public void handleEvent(CProjectDescriptionEvent event) {
synchronized (sync) {
removeActiveConfiguration();
updateActiveConfiguration();
}
}
@Override
public void addListener(IQMakeProjectInfoListener listener) {
listeners.add(listener);
}
@Override
public void removeListener(IQMakeProjectInfoListener listener) {
listeners.remove(listener);
}
// calculates (if does not exist) and returns actual QMake info
@Override
public IQMakeInfo getActualInfo() {
synchronized (sync) {
if (! live) {
return QMakeInfo.INVALID;
}
if (qmakeInfo == null) {
fetchQMakeInfo();
}
return qmakeInfo;
}
}
// calculates actual QMake info
private void fetchQMakeInfo() {
// retrieves IQMakeEnvInfo from IQMakeEnv
IQMakeEnv qmakeEnv = activeController != null ? activeController.getQMakeEnv() : null;
QMakeEnvInfo qmakeEnvInfo = qmakeEnv != null ? qmakeEnv.getQMakeEnvInfo() : null;
// retrieves .pro file path
String proFilePath = toFilePath(qmakeEnvInfo != null ? qmakeEnvInfo.getProFile() : null);
// retrieves qmake executable path
String qmakeFilePath = qmakeEnvInfo != null ? qmakeEnvInfo.getQMakeFilePath() : null;
// retries environment
List<String> envList = new ArrayList<String>();
Map<String, String> envMap = qmakeEnvInfo != null ? qmakeEnvInfo.getEnvironment() : Collections.<String,String>emptyMap();
for (Map.Entry<String,String> entry : envMap.entrySet()) {
envList.add(entry.getKey() + "=" + entry.getValue());
}
// calculates actual QMake info
qmakeInfo = QMakeInfo.create(proFilePath, qmakeFilePath, envList.toArray(new String[envList.size()]));
// calculates a new set of sensitive file paths
sensitiveFilePathSet.clear();
Set<IFile> envSensFiles = qmakeEnvInfo != null ? qmakeEnvInfo.getSensitiveFiles() : Collections.<IFile>emptySet();
for (IFile sensitiveFile : envSensFiles) {
if (sensitiveFile != null) {
sensitiveFilePathSet.addSensitiveFile(sensitiveFile);
}
}
if (proFilePath != null) {
sensitiveFilePathSet.addSensitiveFile(proFilePath);
}
List<String> sensitiveFiles = qmakeInfo.getInvolvedQMakeFiles();
if (sensitiveFiles != null) {
for (String sensitiveFile : sensitiveFiles) {
sensitiveFilePathSet.addSensitiveFile(sensitiveFile);
}
}
}
// converts IFile to absolute path
private static String toFilePath(IFile file) {
if (file != null) {
IPath rawLocation = file.getRawLocation();
if (rawLocation != null) {
rawLocation = rawLocation.makeAbsolute();
if (rawLocation != null) {
File f = rawLocation.toFile();
if (f != null) {
return f.getAbsolutePath();
}
}
}
}
return null;
}
// checks if any of the specified files is a sensitive file
private boolean containsAnySensitiveFile(Set<IPath> files) {
synchronized (sync) {
if (live) {
for (Iterator<IPath> iterator = files.iterator(); iterator.hasNext();) {
IPath path = iterator.next();
if (sensitiveFilePathSet.contains(path)) {
return true;
}
}
}
return false;
}
}
// resets actual QMake info and notifies all listeners that QMake information has changes
private void scheduleFetchQMakeInfo() {
synchronized (sync) {
if (! live) {
return;
}
qmakeInfo = null;
}
for (IQMakeProjectInfoListener listener : listeners) {
listener.qmakeInfoChanged();
}
}
/**
* Represents a project configuration.
*/
private final class ControllerImpl implements IQMakeEnvProvider.IController {
private final ICConfigurationDescription configuration;
private final IQMakeEnv qmakeEnv;
public ControllerImpl(ICConfigurationDescription configuration) {
this.configuration = configuration;
// qmakeEnv created from registry of qmakeEnvProvider extensions
this.qmakeEnv = QMakeEnvProviderManager.getInstance().createEnv(this);
}
public void destroy() {
qmakeEnv.destroy();
}
public IQMakeEnv getQMakeEnv() {
return qmakeEnv;
}
@Override
public ICConfigurationDescription getConfiguration() {
return configuration;
}
@Override
public void scheduleUpdate() {
scheduleFetchQMakeInfo();
}
}
/**
* Listens on Eclipse file system changes.
*/
private static final class RCListener implements IResourceChangeListener {
@Override
public void resourceChanged(IResourceChangeEvent event) {
RDVisitor visitor = new RDVisitor();
// collect project to delete and changed files
switch (event.getType()) {
case IResourceChangeEvent.PRE_CLOSE:
case IResourceChangeEvent.PRE_DELETE:
IResource project = event.getResource();
if (project != null && project.getType() == IResource.PROJECT) {
visitor.addProjectToDelete(project);
}
break;
case IResourceChangeEvent.POST_CHANGE:
IResourceDelta delta = event.getDelta();
if (delta != null) {
try {
delta.accept(visitor);
} catch (CoreException e) {
// empty
}
}
break;
}
// process collected data
visitor.process();
}
}
private static final class RDVisitor implements IResourceDeltaVisitor {
private final Set<IResource> projectsToDelete = new HashSet<IResource>();
private final Set<IPath> changedFiles = new HashSet<IPath>();
@Override
public boolean visit(IResourceDelta delta) throws CoreException {
IResource resource = delta.getResource();
if (resource != null) {
switch (resource.getType()) {
case IResource.FILE:
addChangedFile(resource);
return false;
case IResource.PROJECT:
if (delta.getKind() == IResourceDelta.REMOVED) {
addProjectToDelete(resource);
return false;
}
break;
}
}
return true;
}
private void addProjectToDelete(IResource project) {
projectsToDelete.add(project);
}
private void addChangedFile(IResource file) {
IPath fullPath = file.getFullPath();
if (fullPath != null) {
changedFiles.add(fullPath);
}
}
public void process() {
// removing projects from CACHE
for(IResource project : projectsToDelete) {
removeProjectFromCache(project);
}
List<QMakeProjectInfo> infos;
synchronized (SYNC) {
infos = new ArrayList<QMakeProjectInfo>(CACHE.values());
}
for (QMakeProjectInfo info : infos) {
// checking if any of the changed files affects QMakeProjectInfo
if (info.containsAnySensitiveFile(changedFiles)) {
// if so then scheduling update
info.scheduleFetchQMakeInfo();
}
}
}
}
private static final class SensitiveSet extends HashSet<IPath> {
// adds a sensitive file in form of a specified absolute path
private void addSensitiveFile(String sensitiveFile) {
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
IFile[] files = root.findFilesForLocation(Path.fromOSString(sensitiveFile));
if (files != null && files.length > 0) {
IFile file = files[0];
addSensitiveFile(file);
}
}
// adds a sensitive file in form of a IFile
private void addSensitiveFile(IFile file) {
IPath fullPath = file.getFullPath();
if (fullPath != null) {
add(fullPath);
}
}
}
}

View file

@ -0,0 +1,63 @@
/*
* Copyright (c) 2013 QNX Software Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.cdt.internal.qt.core.index;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.cdt.qt.core.QtPlugin;
import org.eclipse.cdt.qt.core.index.IQtVersion;
/**
* A container class to interpret and store value of the the qmake version.
*/
public final class QMakeVersion implements IQtVersion {
// QMAKE_VERSION looks like 2.01a or 3.0
private static final Pattern REGEXP = Pattern.compile( "([\\d]+)\\.([\\d]+).*" );
// parses major and minor version numbers only
public static QMakeVersion create(String version) {
if (version == null) {
return null;
}
Matcher m = REGEXP.matcher(version.trim());
if (!m.matches()) {
return null;
}
try {
int major = Integer.parseInt(m.group(1));
int minor = Integer.parseInt(m.group(2));
return new QMakeVersion(major, minor);
} catch(NumberFormatException e) {
QtPlugin.log(e);
}
return null;
}
private final int major;
private final int minor;
private QMakeVersion(int major, int minor) {
this.major = major;
this.minor = minor;
}
@Override
public int getMajor() {
return major;
}
@Override
public int getMinor() {
return minor;
}
}

View file

@ -16,7 +16,16 @@ import org.eclipse.core.runtime.CoreException;
public class QtNature implements IProjectNature { public class QtNature implements IProjectNature {
public static final String ID = "org.eclipse.cdt.qt.core.qtNature"; public static final String ID = "org.eclipse.cdt.qt.core.qtNature";
public static boolean hasNature(IProject project) {
try {
return project.hasNature(ID);
} catch (CoreException e) {
QtPlugin.log(e);
return false;
}
}
private IProject project; private IProject project;
@Override @Override
@ -36,5 +45,5 @@ public class QtNature implements IProjectNature {
public void setProject(IProject project) { public void setProject(IProject project) {
this.project = project; this.project = project;
} }
} }

View file

@ -1,9 +1,13 @@
package org.eclipse.cdt.qt.core; package org.eclipse.cdt.qt.core;
import org.osgi.framework.BundleActivator; import org.eclipse.cdt.core.model.CModelException;
import org.eclipse.cdt.internal.qt.core.index.QMakeProjectInfo;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Plugin;
import org.eclipse.core.runtime.Status;
import org.osgi.framework.BundleContext; import org.osgi.framework.BundleContext;
public class QtPlugin implements BundleActivator { public class QtPlugin extends Plugin {
public static final String ID = "org.eclipse.cdt.qt.core"; public static final String ID = "org.eclipse.cdt.qt.core";
public static final String SIGNAL_SLOT_TAGGER_ID = ID + ".signalslot.tagger"; public static final String SIGNAL_SLOT_TAGGER_ID = ID + ".signalslot.tagger";
@ -11,19 +15,29 @@ public class QtPlugin implements BundleActivator {
public static final int SignalSlot_Mask_signal = 1; public static final int SignalSlot_Mask_signal = 1;
public static final int SignalSlot_Mask_slot = 2; public static final int SignalSlot_Mask_slot = 2;
public static final String QMAKE_ENV_PROVIDER_EXT_POINT_NAME = "qmakeEnvProvider"; //$NON-NLS-1$
public static final String QMAKE_ENV_PROVIDER_ID = ID + "." + QMAKE_ENV_PROVIDER_EXT_POINT_NAME; //$NON-NLS-1$
private static QtPlugin INSTANCE;
private static BundleContext context; private static BundleContext context;
static BundleContext getContext() { static BundleContext getContext() {
return context; return context;
} }
static QtPlugin getDefault() {
return INSTANCE;
}
/* /*
* (non-Javadoc) * (non-Javadoc)
* @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext) * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
*/ */
@Override @Override
public void start(BundleContext bundleContext) throws Exception { public void start(BundleContext bundleContext) throws Exception {
INSTANCE = this;
QtPlugin.context = bundleContext; QtPlugin.context = bundleContext;
QMakeProjectInfo.start();
} }
/* /*
@ -32,7 +46,34 @@ public class QtPlugin implements BundleActivator {
*/ */
@Override @Override
public void stop(BundleContext bundleContext) throws Exception { public void stop(BundleContext bundleContext) throws Exception {
QMakeProjectInfo.stop();
QtPlugin.context = null; QtPlugin.context = null;
INSTANCE = null;
}
public static void log(String e) {
log(IStatus.INFO, e, null);
}
public static void log(Throwable e) {
String msg= e.getMessage();
if (msg == null) {
log("Error", e); //$NON-NLS-1$
} else {
log("Error: " + msg, e); //$NON-NLS-1$
}
}
public static void log(String message, Throwable e) {
Throwable nestedException;
if (e instanceof CModelException && (nestedException = ((CModelException)e).getException()) != null) {
e = nestedException;
}
log(IStatus.ERROR, message, e);
}
public static void log(int code, String msg, Throwable e) {
getDefault().getLog().log(new Status(code, ID, msg, e));
} }
} }

View file

@ -0,0 +1,27 @@
/*
* Copyright (c) 2013 QNX Software Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.cdt.qt.core.index;
/**
* Represents a QMake environment. It is usually created by IQMakeEnvProvider.createEnv() method for a specific project configuration.
*/
public interface IQMakeEnv {
/**
* Notifies that this environment is no longer used.
*/
void destroy();
/**
* Returns an actual QMake environment information that is used for a single qmake run to retrieve QMake information.
*
* @return the actual QMake environment information
*/
QMakeEnvInfo getQMakeEnvInfo();
}

View file

@ -0,0 +1,49 @@
/*
* Copyright (c) 2013 QNX Software Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.cdt.qt.core.index;
import org.eclipse.cdt.core.settings.model.ICConfigurationDescription;
/**
* Represents a provider for IQMakeEnv which is used to specify an environment for qmake run.
* This class needs to be registered via org.eclipse.cdt.qt.core.qmakeEnvProvider extension point.
*/
public interface IQMakeEnvProvider {
/**
* Creates a QMake environment for a specific IController (aka a project configuration).
*
* @param controller the controller
* @return the IQMakeEnv instance that is used for qmake run;
* or null if this provider cannot create IQMakeEnv instance for the specified IController.
*/
IQMakeEnv createEnv(IController controller);
/**
* Represents a project configuration and provides a control over the environment.
*
* This class is not meant to be implemented.
*/
public interface IController {
/**
* Returns a project configuration for which a QMake environment should be supplied.
*
* @return the project configuration
*/
ICConfigurationDescription getConfiguration();
/**
* Request the controller to schedule a new qmake run to retrieve new QMake information.
* This method should be called when there is any change in IQMakeEnv that might affect resulting IQMakeEnvInfo.
*/
void scheduleUpdate();
}
}

View file

@ -0,0 +1,92 @@
/*
* Copyright (c) 2013 QNX Software Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.cdt.qt.core.index;
import java.util.List;
/**
* Represents a QMake information.
*
* Note that current implementation of does not handle support QMake 2.0 in full range so provided information might be incomplete.
*
* This class is not meant to be implemented.
*/
public interface IQMakeInfo {
/**
* Returns whether this information is valid. If invalid, then returned value of the other method is unspecified.
*
* @return true if this information is valid
*/
boolean isValid();
/**
* Returns a Qt version as provided by "qmake -query" command.
*
* @return the Qt version
*/
IQtVersion getQtVersion();
/**
* Returns a list of QMake files (.pro, .pri, .prf, ...) that are involved in resolving this information as retrieved
* via "qmake -E file.pro" command.
*
* @return the list of involved QMake files
*/
List<String> getInvolvedQMakeFiles();
/**
* Returns a list of Qt Import paths. Represents QT_IMPORT_PATH that is used by QDeclarativeEngine (aka QtQuick1) runtime to load QML modules.
*
* @return the list of Qt Import paths
*/
List<String> getQtImportPath();
/**
* Returns a list of Qt Qml paths that is used by QQmlEngine (aka QtQuick2) runtime to load QML modules.
*
* @return the list of Qt Qml paths
*/
List<String> getQtQmlPath();
/**
* Returns a list of include paths that are used for compilation of a related project.
*
* @return the list of include paths
*/
List<String> getIncludePath();
/**
* Returns a list of defines that are used for compilation of a related project i.e. specified via DEFINES QMake variable.
*
* @return the list of defines.
*/
List<String> getDefines();
/**
* Returns a list of source file paths i.e. specified via SOURCES QMake variable.
*
* @return the list of source file paths
*/
List<String> getSourceFiles();
/**
* Returns a list of header file paths i.e. specified via HEADERS QMake variable.
*
* @return the list of header file paths
*/
List<String> getHeaderFiles();
/**
* Returns a list of other file paths i.e. specified via OTHER_FILES QMake variable.
*
* @return the list of other file paths
*/
List<String> getOtherFiles();
}

View file

@ -0,0 +1,40 @@
/*
* Copyright (c) 2013 QNX Software Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.cdt.qt.core.index;
/**
* Represents provider of QMake information.
*
* This class is not meant to be implemented.
*/
public interface IQMakeProjectInfo {
/**
* Add a listener that notifies about possible changes of IQMakeInfo retrieved from getActualInfo() method.
*
* @param listener the listener
*/
void addListener(IQMakeProjectInfoListener listener);
/**
* Removes a listener that was added via addListener() method.
*
* @param listener the listener
*/
void removeListener(IQMakeProjectInfoListener listener);
/**
* Returns an actual QMake information.
*
* Note that this is a long-term operation and the method call is blocked until an actual QMake information is calculated.
*
* @return non-null IQMakeInfo instance representing the actual QMake information
*/
IQMakeInfo getActualInfo();
}

View file

@ -0,0 +1,21 @@
/*
* Copyright (c) 2013 QNX Software Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.cdt.qt.core.index;
/**
* A listener used for notifying that a QMake information provided by IQMakeProjectInfo might have changed.
*/
public interface IQMakeProjectInfoListener {
/**
* Notifies that a QMake information provided by IQMakeProjectInfo might have changed.
* A new QMake information can be read via IQMakeProjectInfo.getQMakeInfo() method.
*/
void qmakeInfoChanged();
}

View file

@ -0,0 +1,27 @@
/*
* Copyright (c) 2013 QNX Software Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.cdt.qt.core.index;
/**
* Represents a Qt version in form of major and minor number.
*/
public interface IQtVersion {
/**
* Returns major version number.
* @return the major version number
*/
int getMajor();
/**
* Returns minor version number.
* @return the minor version number
*/
int getMinor();
}

View file

@ -0,0 +1,81 @@
/*
* Copyright (c) 2013 QNX Software Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.cdt.qt.core.index;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.resources.IFile;
/**
* Holds data describing QMake environment (pro file, qmake file, env. vars.) for a specific QMake run provided by QMakeEnv instance.
*/
public final class QMakeEnvInfo {
private final IFile proFile;
private final String qmakeFilePath;
private final Map<String, String> environment;
private final Set<IFile> sensitiveFiles;
/**
* Creates QMakeEnvInfo.
*
* @param proFile the root-level .pro file
* @param qmakeFilePath the absolute path of qmake executable
* @param environment environment variables
* @param sensitiveFiles the list of IFile that needs to be tracked by IQMakeProjectInfo since their change might affect
* an environment for running qmake.
*/
public QMakeEnvInfo(IFile proFile, String qmakeFilePath, Map<String,String> environment, Collection<IFile> sensitiveFiles) {
this.proFile = proFile;
this.qmakeFilePath = qmakeFilePath;
this.environment = environment != null ? new HashMap<String,String>(environment) : Collections.<String,String>emptyMap();
this.sensitiveFiles = sensitiveFiles != null ? new HashSet<IFile>(sensitiveFiles) : Collections.<IFile>emptySet();
}
/**
* Returns IFile of .pro file.
*
* @return the .pro file
*/
public IFile getProFile() {
return proFile;
}
/**
* Returns an absolute path of qmake executable.
*
* @return the qmake path
*/
public String getQMakeFilePath() {
return qmakeFilePath;
}
/**
* Returns a map of environment variables that are used for qmake run.
*
* @return the environment
*/
public Map<String, String> getEnvironment() {
return environment;
}
/**
* Returns a list of IFile that might affect environment of qmake run.
*
* @return the list sensitive files
*/
public Set<IFile> getSensitiveFiles() {
return sensitiveFiles;
}
}

View file

@ -0,0 +1,33 @@
/*
* Copyright (c) 2013 QNX Software Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.cdt.qt.core.index;
import org.eclipse.cdt.internal.qt.core.index.QMakeProjectInfo;
import org.eclipse.core.resources.IProject;
/**
* A factory for QMakeProjectInfo instances.
*/
public final class QMakeProjectInfoFactory {
private QMakeProjectInfoFactory() {
}
/**
* Provides a IQMakeProjectInfo for an active project configuration
* in a specified project.
*
* @param project the project
* @return IQMakeProjectInfo representing an activate project configuration
* in the specified project.
*/
public static IQMakeProjectInfo getForActiveConfigurationIn(IProject project) {
return QMakeProjectInfo.getQMakeProjectInfoFor(project);
}
}