Merge remote-tracking branch 'origin/3.1'

Conflicts:
	qbs/imports/QtcTool.qbs
	src/plugins/git/giteditor.cpp
	src/plugins/qmldesigner/qmldesignerplugin.cpp

Change-Id: Icafd32f713effb1479480a0d1f61a01e429fbec0
This commit is contained in:
Oswald Buddenhagen
2014-03-18 14:46:29 +01:00
439 changed files with 4360 additions and 2764 deletions

View File

@@ -1,4 +1,4 @@
import qbs.base 1.0
import qbs 1.0
import QtcPlugin

View File

@@ -114,10 +114,12 @@ void AndroidAnalyzeSupport::handleRemoteOutput(const QByteArray &output)
void AndroidAnalyzeSupport::handleRemoteErrorOutput(const QByteArray &output)
{
const QString msg = QString::fromUtf8(output);
if (m_runControl)
m_runControl->logApplicationMessage(QString::fromUtf8(output), Utils::StdErrFormatSameLine);
m_runControl->logApplicationMessage(msg, Utils::StdErrFormatSameLine);
else
AndroidRunSupport::handleRemoteErrorOutput(output);
m_outputParser.processOutput(msg);
}
void AndroidAnalyzeSupport::remoteIsRunning()

View File

@@ -574,7 +574,9 @@ QVector<AndroidDeviceInfo> AndroidConfig::androidVirtualDevices() const
break;
if (line.contains(QLatin1String("Target:")))
dev.sdk = line.mid(line.lastIndexOf(QLatin1Char(' '))).remove(QLatin1Char(')')).toInt();
if (line.contains(QLatin1String("ABI:")))
if (line.contains(QLatin1String("Tag/ABI:")))
dev.cpuAbi = QStringList() << line.mid(line.lastIndexOf(QLatin1Char('/')) +1);
else if (line.contains(QLatin1String("ABI:")))
dev.cpuAbi = QStringList() << line.mid(line.lastIndexOf(QLatin1Char(' '))).trimmed();
}
// armeabi-v7a devices can also run armeabi code
@@ -884,8 +886,9 @@ void AndroidConfigurations::setConfig(const AndroidConfig &devConfigs)
m_instance->m_config = devConfigs;
m_instance->save();
m_instance->updateAutomaticKitList();
m_instance->updateAndroidDevice();
m_instance->updateToolChainList();
m_instance->updateAutomaticKitList();
emit m_instance->updated();
}
@@ -944,6 +947,32 @@ static bool equalKits(Kit *a, Kit *b)
&& QtSupport::QtKitInformation::qtVersion(a) == QtSupport::QtKitInformation::qtVersion(b);
}
void AndroidConfigurations::updateToolChainList()
{
QList<ToolChain *> existingToolChains = ToolChainManager::toolChains();
QList<ToolChain *> toolchains = AndroidToolChainFactory::createToolChainsForNdk(AndroidConfigurations::currentConfig().ndkLocation());
foreach (ToolChain *tc, toolchains) {
bool found = false;
for (int i = 0; i < existingToolChains.count(); ++i) {
if (*(existingToolChains.at(i)) == *tc) {
found = true;
break;
}
}
if (found)
delete tc;
else
ToolChainManager::registerToolChain(tc);
}
foreach (ToolChain *tc, existingToolChains) {
if (tc->type() == QLatin1String(Constants::ANDROID_TOOLCHAIN_TYPE)) {
if (!tc->isValid())
ToolChainManager::deregisterToolChain(tc);
}
}
}
void AndroidConfigurations::updateAutomaticKitList()
{
QList<AndroidToolChain *> toolchains;

View File

@@ -185,6 +185,7 @@ public:
static QString defaultDevice(ProjectExplorer::Project *project, const QString &abi); // serial number or avd name
public slots:
static void clearDefaultDevices(ProjectExplorer::Project *project);
static void updateToolChainList();
static void updateAutomaticKitList();
signals:

View File

@@ -248,7 +248,7 @@
<item>
<widget class="QRadioButton" name="ministroOption">
<property name="toolTip">
<string>Use the external Ministro application to download and maintain Qt libraries.</string>
<string>Uses the external Ministro application to download and maintain Qt libraries.</string>
</property>
<property name="text">
<string>Use Ministro service to install Qt</string>
@@ -261,7 +261,7 @@
<item>
<widget class="QRadioButton" name="temporaryQtOption">
<property name="toolTip">
<string>Push local Qt libraries to device. You must have Qt libraries compiled for that platform.
<string>Pushes local Qt libraries to device. You must have Qt libraries compiled for that platform.
The APK will not be usable on any other device.</string>
</property>
<property name="text">

View File

@@ -29,7 +29,7 @@
<item>
<widget class="QRadioButton" name="ministroOption">
<property name="toolTip">
<string>Use the external Ministro application to download and maintain Qt libraries.</string>
<string>Uses the external Ministro application to download and maintain Qt libraries.</string>
</property>
<property name="text">
<string>Use Ministro service to install Qt</string>
@@ -42,7 +42,7 @@
<item>
<widget class="QRadioButton" name="temporaryQtOption">
<property name="toolTip">
<string>Push local Qt libraries to device. You must have Qt libraries compiled for that platform.
<string>Pushes local Qt libraries to device. You must have Qt libraries compiled for that platform.
The APK will not be usable on any other device.</string>
</property>
<property name="text">

View File

@@ -33,6 +33,7 @@
#include <QPainter>
#include <QStyledItemDelegate>
#include <QToolTip>
using namespace Android;
using namespace Android::Internal;
@@ -386,6 +387,17 @@ AndroidDeviceDialog::AndroidDeviceDialog(int apiLevel, const QString &abi, QWidg
m_ui->defaultDeviceCheckBox->setText(tr("Always use this device for architecture %1").arg(abi));
m_ui->noDeviceFoundLabel->setText(tr("<p align=\"center\"><span style=\" font-size:16pt;\">"
"No Device Found</span></p>"
"<br/>"
"<p>Connect an Android device via USB and activate developer mode on it. "
"Some devices require the installation of a USB driver.</p>"
"<br/>"
"<p>The adb tool in the Android SDK lists all connected devices if run via &quot;adb devices&quot;.</p>"
));
connect(m_ui->missingLabel, SIGNAL(linkActivated(QString)),
this, SLOT(showHelp()));
connect(m_ui->refreshDevicesButton, SIGNAL(clicked()),
this, SLOT(refreshDeviceList()));
@@ -445,6 +457,8 @@ void AndroidDeviceDialog::refreshDeviceList()
newIndex = m_model->indexFor(devices.first().serialNumber);
m_ui->deviceView->setCurrentIndex(newIndex);
m_ui->stackedWidget->setCurrentIndex(devices.isEmpty() ? 1 : 0);
}
void AndroidDeviceDialog::createAvd()
@@ -470,3 +484,13 @@ void AndroidDeviceDialog::clickedOnView(const QModelIndex &idx)
}
}
}
void AndroidDeviceDialog::showHelp()
{
QPoint pos = m_ui->missingLabel->pos();
pos = m_ui->missingLabel->parentWidget()->mapToGlobal(pos);
QToolTip::showText(pos, tr("<p>Connect an Android device via USB and activate developer mode on it. "
"Some devices require the installation of a USB driver.</p>"
"<p>The adb tool in the Android SDK lists all connected devices if run via &quot;adb devices&quot;.</p>"),
this);
}

View File

@@ -62,6 +62,7 @@ private slots:
void refreshDeviceList();
void createAvd();
void clickedOnView(const QModelIndex &idx);
void showHelp();
private:
AndroidDeviceModel *m_model;
Ui::AndroidDeviceDialog *m_ui;

View File

@@ -6,36 +6,29 @@
<rect>
<x>0</x>
<y>0</y>
<width>618</width>
<height>400</height>
<width>636</width>
<height>438</height>
</rect>
</property>
<property name="windowTitle">
<string>Select Android Device</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="0">
<widget class="QPushButton" name="refreshDevicesButton">
<property name="text">
<string>Refresh Device List</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="createAVDButton">
<property name="text">
<string>Create Android Virtual Device</string>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<item row="3" column="0" colspan="2">
<widget class="QCheckBox" name="defaultDeviceCheckBox">
<property name="text">
<string>Always use this device for architecture %1</string>
</property>
</widget>
</item>
<item row="3" column="2">
<item row="2" column="1">
<widget class="QPushButton" name="createAVDButton">
<property name="text">
<string>Create Android Virtual Device</string>
</property>
</widget>
</item>
<item row="4" column="2">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
@@ -45,16 +38,64 @@
</property>
</widget>
</item>
<item row="0" column="0" colspan="3">
<widget class="QTreeView" name="deviceView">
<property name="minimumSize">
<size>
<width>600</width>
<height>300</height>
</size>
<item row="2" column="0">
<widget class="QPushButton" name="refreshDevicesButton">
<property name="text">
<string>Refresh Device List</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="3">
<widget class="QStackedWidget" name="stackedWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="devicesPage">
<layout class="QGridLayout" name="gridLayout_3">
<item row="1" column="0">
<widget class="QTreeView" name="deviceView">
<property name="minimumSize">
<size>
<width>600</width>
<height>300</height>
</size>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="missingLabel">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;aaa&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0057ae;&quot;&gt;My device is missing&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="noDevicesPage">
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="noDeviceFoundLabel">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<resources/>

View File

@@ -39,6 +39,7 @@
#include <coreplugin/documentmanager.h>
#include <coreplugin/messagemanager.h>
#include <coreplugin/icore.h>
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/session.h>
#include <projectexplorer/target.h>
@@ -631,7 +632,7 @@ bool AndroidManager::createAndroidTemplatesIfNecessary(ProjectExplorer::Target *
}
if (forceUpdate)
QMessageBox::warning(0, tr("Warning"), tr("Android files have been updated automatically."));
QMessageBox::warning(Core::ICore::dialogParent(), tr("Warning"), tr("Android files have been updated automatically."));
return true;
}

View File

@@ -66,6 +66,7 @@
#include <QPushButton>
#include <QFileDialog>
#include <QTimer>
#include <QCheckBox>
using namespace ProjectExplorer;
using namespace Android;
@@ -278,16 +279,21 @@ void AndroidManifestEditorWidget::initializePage()
{
QGridLayout *layout = new QGridLayout(permissionsGroupBox);
m_defaultPermissonsCheckBox = new QCheckBox(this);
m_defaultPermissonsCheckBox->setText(tr("Include default permissions and features for Qt modules."));
m_defaultPermissonsCheckBox->setTristate(true);
layout->addWidget(m_defaultPermissonsCheckBox, 0, 0);
m_permissionsModel = new PermissionsModel(this);
m_permissionsListView = new QListView(permissionsGroupBox);
m_permissionsListView->setModel(m_permissionsModel);
m_permissionsListView->setMinimumSize(QSize(0, 200));
layout->addWidget(m_permissionsListView, 0, 0, 3, 1);
layout->addWidget(m_permissionsListView, 1, 0, 3, 1);
m_removePermissionButton = new QPushButton(permissionsGroupBox);
m_removePermissionButton->setText(tr("Remove"));
layout->addWidget(m_removePermissionButton, 0, 1);
layout->addWidget(m_removePermissionButton, 1, 1);
m_permissionsComboBox = new QComboBox(permissionsGroupBox);
m_permissionsComboBox->insertItems(0, QStringList()
@@ -423,14 +429,17 @@ void AndroidManifestEditorWidget::initializePage()
<< QLatin1String("android.permission.WRITE_USER_DICTIONARY")
);
m_permissionsComboBox->setEditable(true);
layout->addWidget(m_permissionsComboBox, 4, 0);
layout->addWidget(m_permissionsComboBox, 5, 0);
m_addPermissionButton = new QPushButton(permissionsGroupBox);
m_addPermissionButton->setText(tr("Add"));
layout->addWidget(m_addPermissionButton, 4, 1);
layout->addWidget(m_addPermissionButton, 5, 1);
permissionsGroupBox->setLayout(layout);
connect(m_defaultPermissonsCheckBox, SIGNAL(stateChanged(int)),
this, SLOT(defaultPermissionCheckBoxClicked()));
connect(m_addPermissionButton, SIGNAL(clicked()),
this, SLOT(addPermission()));
connect(m_removePermissionButton, SIGNAL(clicked()),
@@ -791,6 +800,29 @@ void AndroidManifestEditorWidget::syncToWidgets(const QDomDocument &doc)
m_mIconPath.clear();
m_hIconPath.clear();
disconnect(m_defaultPermissonsCheckBox, SIGNAL(stateChanged(int)),
this, SLOT(defaultPermissionCheckBoxClicked()));
m_defaultPermissonsCheckBox->setChecked(false);
QDomNodeList manifestChilds = manifest.childNodes();
bool foundPermissionComment = false;
bool foundFeatureComment = false;
for (int i = 0; i < manifestChilds.size(); ++i) {
const QDomNode &child = manifestChilds.at(i);
if (child.isComment()) {
QDomComment comment = child.toComment();
if (comment.data().trimmed() == QLatin1String("%%INSERT_PERMISSIONS"))
foundPermissionComment = true;
else if (comment.data().trimmed() == QLatin1String("%%INSERT_FEATURES"))
foundFeatureComment = true;
}
}
m_defaultPermissonsCheckBox->setCheckState(Qt::CheckState(foundFeatureComment + foundPermissionComment));
connect(m_defaultPermissonsCheckBox, SIGNAL(stateChanged(int)),
this, SLOT(defaultPermissionCheckBoxClicked()));
QStringList permissions;
QDomElement permissionElem = manifest.firstChildElement(QLatin1String("uses-permission"));
while (!permissionElem.isNull()) {
@@ -805,53 +837,6 @@ void AndroidManifestEditorWidget::syncToWidgets(const QDomDocument &doc)
m_dirty = false;
}
void setUsesSdk(QDomDocument &doc, QDomElement &manifest, int minimumSdk, int targetSdk)
{
QDomElement usesSdk = manifest.firstChildElement(QLatin1String("uses-sdk"));
if (usesSdk.isNull()) { // doesn't exist yet
if (minimumSdk == 0 && targetSdk == 0) {
// and doesn't need to exist
} else {
usesSdk = doc.createElement(QLatin1String("uses-sdk"));
if (minimumSdk != 0)
usesSdk.setAttribute(QLatin1String("android:minSdkVersion"), minimumSdk);
if (targetSdk != 0)
usesSdk.setAttribute(QLatin1String("android:targetSdkVersion"), targetSdk);
manifest.appendChild(usesSdk);
}
} else {
if (minimumSdk == 0 && targetSdk == 0) {
// We might be able to remove the whole element
// check if there are other attributes
QDomNamedNodeMap usesSdkAttributes = usesSdk.attributes();
bool keepNode = false;
for (int i = 0; i < usesSdkAttributes.size(); ++i) {
if (usesSdkAttributes.item(i).nodeName() != QLatin1String("android:minSdkVersion")
&& usesSdkAttributes.item(i).nodeName() != QLatin1String("android:targetSdkVersion")) {
keepNode = true;
break;
}
}
if (keepNode) {
usesSdk.removeAttribute(QLatin1String("android:minSdkVersion"));
usesSdk.removeAttribute(QLatin1String("android:targetSdkVersion"));
} else {
manifest.removeChild(usesSdk);
}
} else {
if (minimumSdk == 0)
usesSdk.removeAttribute(QLatin1String("android:minSdkVersion"));
else
usesSdk.setAttribute(QLatin1String("android:minSdkVersion"), minimumSdk);
if (targetSdk == 0)
usesSdk.removeAttribute(QLatin1String("android:targetSdkVersion"));
else
usesSdk.setAttribute(QLatin1String("android:targetSdkVersion"), targetSdk);
}
}
}
int extractVersion(const QString &string)
{
if (!string.startsWith(QLatin1String("API")))
@@ -868,78 +853,360 @@ int extractVersion(const QString &string)
void AndroidManifestEditorWidget::syncToEditor()
{
QDomDocument doc;
if (!doc.setContent(m_textEditorWidget->toPlainText())) {
// This should not happen
updateInfoBar();
return;
QString result;
QXmlStreamReader reader(m_textEditorWidget->toPlainText());
reader.setNamespaceProcessing(false);
QXmlStreamWriter writer(&result);
writer.setAutoFormatting(true);
writer.setAutoFormattingIndent(4);
while (!reader.atEnd()) {
reader.readNext();
if (reader.hasError()) {
// This should not happen
updateInfoBar();
return;
} else {
if (reader.name() == QLatin1String("manifest"))
parseManifest(reader, writer);
else if (reader.isStartElement())
parseUnknownElement(reader, writer);
else
writer.writeCurrentToken(reader);
}
}
QDomElement manifest = doc.documentElement();
manifest.setAttribute(QLatin1String("package"), m_packageNameLineEdit->text());
manifest.setAttribute(QLatin1String("android:versionCode"), m_versionCode->value());
manifest.setAttribute(QLatin1String("android:versionName"), m_versionNameLinedit->text());
if (!m_appNameInStringsXml) {
QDomElement application = manifest.firstChildElement(QLatin1String("application"));
application.setAttribute(QLatin1String("android:label"), m_appNameLineEdit->text());
}
setUsesSdk(doc, manifest, extractVersion(m_androidMinSdkVersion->currentText()),
extractVersion(m_androidTargetSdkVersion->currentText()));
setAndroidAppLibName(doc, manifest.firstChildElement(QLatin1String("application"))
.firstChildElement(QLatin1String("activity")),
m_targetLineEdit->currentText());
// permissions
QDomElement permissionElem = manifest.firstChildElement(QLatin1String("uses-permission"));
while (!permissionElem.isNull()) {
manifest.removeChild(permissionElem);
permissionElem = manifest.firstChildElement(QLatin1String("uses-permission"));
}
foreach (const QString &permission, m_permissionsModel->permissions()) {
permissionElem = doc.createElement(QLatin1String("uses-permission"));
permissionElem.setAttribute(QLatin1String("android:name"), permission);
manifest.appendChild(permissionElem);
}
bool ensureIconAttribute = !m_lIconPath.isEmpty()
|| !m_mIconPath.isEmpty()
|| !m_hIconPath.isEmpty();
if (ensureIconAttribute) {
QDomElement applicationElem = manifest.firstChildElement(QLatin1String("application"));
applicationElem.setAttribute(QLatin1String("android:icon"), QLatin1String("@drawable/icon"));
}
QString newText = doc.toString(4);
if (newText == m_textEditorWidget->toPlainText())
if (result == m_textEditorWidget->toPlainText())
return;
m_textEditorWidget->setPlainText(newText);
m_textEditorWidget->setPlainText(result);
m_textEditorWidget->document()->setModified(true);
m_dirty = false;
}
bool AndroidManifestEditorWidget::setAndroidAppLibName(QDomDocument document, QDomElement activity, const QString &name)
namespace {
QXmlStreamAttributes modifyXmlStreamAttributes(const QXmlStreamAttributes &input, const QStringList &keys,
const QStringList values, const QStringList &remove = QStringList())
{
QDomElement metadataElem = activity.firstChildElement(QLatin1String("meta-data"));
while (!metadataElem.isNull()) {
if (metadataElem.attribute(QLatin1String("android:name")) == QLatin1String("android.app.lib_name")) {
metadataElem.setAttribute(QLatin1String("android:value"), name);
return true;
}
metadataElem = metadataElem.nextSiblingElement(QLatin1String("meta-data"));
Q_ASSERT(keys.size() == values.size());
QXmlStreamAttributes result;
result.reserve(input.size());
foreach (const QXmlStreamAttribute &attribute, input) {
const QString &name = attribute.qualifiedName().toString();
if (remove.contains(name))
continue;
int index = keys.indexOf(name);
if (index == -1)
result.push_back(attribute);
else
result.push_back(QXmlStreamAttribute(name,
values.at(index)));
}
for (int i = 0; i < keys.size(); ++i) {
if (!result.hasAttribute(keys.at(i)))
result.push_back(QXmlStreamAttribute(keys.at(i), values.at(i)));
}
return result;
}
} // end namespace
void AndroidManifestEditorWidget::parseManifest(QXmlStreamReader &reader, QXmlStreamWriter &writer)
{
Q_ASSERT(reader.isStartElement());
writer.writeStartElement(reader.name().toString());
QXmlStreamAttributes attributes = reader.attributes();
QStringList keys = QStringList()
<< QLatin1String("package")
<< QLatin1String("android:versionCode")
<< QLatin1String("android:versionName");
QStringList values = QStringList()
<< m_packageNameLineEdit->text()
<< QString::number(m_versionCode->value())
<< m_versionNameLinedit->text();
QXmlStreamAttributes result = modifyXmlStreamAttributes(attributes, keys, values);
writer.writeAttributes(result);
QSet<QString> permissions = m_permissionsModel->permissions().toSet();
bool foundUsesSdk = false;
bool foundPermissionComment = false;
bool foundFeatureComment = false;
reader.readNext();
while (!reader.atEnd()) {
if (reader.name() == QLatin1String("application")) {
parseApplication(reader, writer);
} else if (reader.name() == QLatin1String("uses-sdk")) {
parseUsesSdk(reader, writer);
foundUsesSdk = true;
} else if (reader.name() == QLatin1String("uses-permission")) {
permissions.remove(parseUsesPermission(reader, writer, permissions));
} else if (reader.isEndElement()) {
if (!foundUsesSdk) {
int minimumSdk = extractVersion(m_androidMinSdkVersion->currentText());
int targetSdk = extractVersion(m_androidTargetSdkVersion->currentText());
if (minimumSdk == 0 && targetSdk == 0) {
// and doesn't need to exist
} else {
writer.writeEmptyElement(QLatin1String("uses-sdk"));
if (minimumSdk != 0)
writer.writeAttribute(QLatin1String("android:minSdkVersion"),
QString::number(minimumSdk));
if (targetSdk != 0)
writer.writeAttribute(QLatin1String("android:targetSdkVersion"),
QString::number(targetSdk));
}
}
if (!foundPermissionComment && m_defaultPermissonsCheckBox->checkState() == Qt::Checked)
writer.writeComment(QLatin1String(" %%INSERT_PERMISSIONS "));
if (!foundFeatureComment && m_defaultPermissonsCheckBox->checkState() == Qt::Checked)
writer.writeComment(QLatin1String(" %%INSERT_FEATURES "));
if (!permissions.isEmpty()) {
foreach (const QString &permission, permissions) {
writer.writeEmptyElement(QLatin1String("uses-permission"));
writer.writeAttribute(QLatin1String("android:name"), permission);
}
}
writer.writeCurrentToken(reader);
return;
} else if (reader.isComment()) {
QString commentText = parseComment(reader, writer);
if (commentText == QLatin1String("%%INSERT_PERMISSIONS"))
foundPermissionComment = true;
else if (commentText == QLatin1String("%%INSERT_FEATURES"))
foundFeatureComment = true;
} else if (reader.isStartElement()) {
parseUnknownElement(reader, writer);
} else {
writer.writeCurrentToken(reader);
}
reader.readNext();
}
}
void AndroidManifestEditorWidget::parseApplication(QXmlStreamReader &reader, QXmlStreamWriter &writer)
{
Q_ASSERT(reader.isStartElement());
writer.writeStartElement(reader.name().toString());
QXmlStreamAttributes attributes = reader.attributes();
QStringList keys;
QStringList values;
if (!m_appNameInStringsXml) {
keys << QLatin1String("android:label");
values << m_appNameLineEdit->text();
}
bool ensureIconAttribute = !m_lIconPath.isEmpty()
|| !m_mIconPath.isEmpty()
|| !m_hIconPath.isEmpty();
if (ensureIconAttribute) {
keys << QLatin1String("android:icon");
values << QLatin1String("@drawable/icon");
}
QXmlStreamAttributes result = modifyXmlStreamAttributes(attributes, keys, values);
writer.writeAttributes(result);
reader.readNext();
while (!reader.atEnd()) {
if (reader.isEndElement()) {
writer.writeCurrentToken(reader);
return;
} else if (reader.isStartElement()) {
if (reader.name() == QLatin1String("activity"))
parseActivity(reader, writer);
else
parseUnknownElement(reader, writer);
} else {
writer.writeCurrentToken(reader);
}
reader.readNext();
}
}
void AndroidManifestEditorWidget::parseActivity(QXmlStreamReader &reader, QXmlStreamWriter &writer)
{
Q_ASSERT(reader.isStartElement());
writer.writeCurrentToken(reader);
reader.readNext();
bool found = false;
while (!reader.atEnd()) {
if (reader.isEndElement()) {
if (!found) {
writer.writeEmptyElement(QLatin1String("meta-data"));
writer.writeAttribute(QLatin1String("android:name"),
QLatin1String("android.app.lib_name"));
writer.writeAttribute(QLatin1String("android:value"),
m_targetLineEdit->currentText());
}
writer.writeCurrentToken(reader);
return;
} else if (reader.isStartElement()) {
if (reader.name() == QLatin1String("meta-data"))
found = parseMetaData(reader, writer) || found; // ORDER MATTERS
else
parseUnknownElement(reader, writer);
} else {
writer.writeCurrentToken(reader);
}
reader.readNext();
}
}
bool AndroidManifestEditorWidget::parseMetaData(QXmlStreamReader &reader, QXmlStreamWriter &writer)
{
Q_ASSERT(reader.isStartElement());
bool found = false;
QXmlStreamAttributes attributes = reader.attributes();
QXmlStreamAttributes result;
if (attributes.value(QLatin1String("android:name")) == QLatin1String("android.app.lib_name")) {
QStringList keys = QStringList() << QLatin1String("android:value");
QStringList values = QStringList() << m_targetLineEdit->currentText();
result = modifyXmlStreamAttributes(attributes, keys, values);
found = true;
} else {
result = attributes;
}
writer.writeStartElement(QLatin1String("meta-data"));
writer.writeAttributes(result);
reader.readNext();
while (!reader.atEnd()) {
if (reader.isEndElement()) {
writer.writeCurrentToken(reader);
return found;
} else if (reader.isStartElement()) {
parseUnknownElement(reader, writer);
} else {
writer.writeCurrentToken(reader);
}
reader.readNext();
}
return found; // should never be reached
}
void AndroidManifestEditorWidget::parseUsesSdk(QXmlStreamReader &reader, QXmlStreamWriter & writer)
{
int minimumSdk = extractVersion(m_androidMinSdkVersion->currentText());
int targetSdk = extractVersion(m_androidTargetSdkVersion->currentText());
QStringList keys;
QStringList values;
QStringList remove;
if (minimumSdk == 0) {
remove << QLatin1String("android:minSdkVersion");
} else {
keys << QLatin1String("android:minSdkVersion");
values << QString::number(minimumSdk);
}
if (targetSdk == 0) {
remove << QLatin1String("android:targetSdkVersion");
} else {
keys << QLatin1String("android:targetSdkVersion");
values << QString::number(targetSdk);
}
QXmlStreamAttributes result = modifyXmlStreamAttributes(reader.attributes(),
keys, values, remove);
bool removeUseSdk = result.isEmpty();
if (!removeUseSdk) {
writer.writeStartElement(reader.name().toString());
writer.writeAttributes(result);
}
reader.readNext();
while (!reader.atEnd()) {
if (reader.isEndElement()) {
if (!removeUseSdk)
writer.writeCurrentToken(reader);
return;
} else {
if (removeUseSdk) {
removeUseSdk = false;
writer.writeStartElement(QLatin1String("uses-sdk"));
}
if (reader.isStartElement())
parseUnknownElement(reader, writer);
else
writer.writeCurrentToken(reader);
}
reader.readNext();
}
}
QString AndroidManifestEditorWidget::parseUsesPermission(QXmlStreamReader &reader, QXmlStreamWriter &writer, const QSet<QString> permissions)
{
Q_ASSERT(reader.isStartElement());
QString permissionName = reader.attributes().value(QLatin1String("android:name")).toString();
bool writePermission = permissions.contains(permissionName);
if (writePermission)
writer.writeCurrentToken(reader);
reader.readNext();
while (!reader.atEnd()) {
if (reader.isEndElement()) {
if (writePermission)
writer.writeCurrentToken(reader);
return permissionName;
} else if (reader.isStartElement()) {
parseUnknownElement(reader, writer);
} else {
writer.writeCurrentToken(reader);
}
reader.readNext();
}
return permissionName; // should not be reached
}
QString AndroidManifestEditorWidget::parseComment(QXmlStreamReader &reader, QXmlStreamWriter &writer)
{
QString commentText = reader.text().toString().trimmed();
if (commentText == QLatin1String("%%INSERT_PERMISSIONS")
|| commentText == QLatin1String("%%INSERT_FEATURES")) {
if (m_defaultPermissonsCheckBox->checkState() == Qt::Unchecked)
return commentText;
writer.writeCurrentToken(reader);
return commentText;
}
writer.writeCurrentToken(reader);
return QString();
}
void AndroidManifestEditorWidget::parseUnknownElement(QXmlStreamReader &reader, QXmlStreamWriter &writer)
{
Q_ASSERT(reader.isStartElement());
writer.writeCurrentToken(reader);
reader.readNext();
while (!reader.atEnd()) {
if (reader.isEndElement()) {
writer.writeCurrentToken(reader);
return;
} else if (reader.isStartElement()) {
parseUnknownElement(reader, writer);
} else {
writer.writeCurrentToken(reader);
}
reader.readNext();
}
QDomElement elem = document.createElement(QLatin1String("meta-data"));
elem.setAttribute(QLatin1String("android:name"), QLatin1String("android.app.lib_name"));
elem.setAttribute(QLatin1String("android:value"), name);
activity.appendChild(elem);
return true;
}
QString AndroidManifestEditorWidget::iconPath(const QString &baseDir, IconDPI dpi)
@@ -1021,6 +1288,13 @@ void AndroidManifestEditorWidget::setHDPIIcon()
setDirty(true);
}
void AndroidManifestEditorWidget::defaultPermissionCheckBoxClicked()
{
if (m_defaultPermissonsCheckBox->checkState() == Qt::PartiallyChecked)
m_defaultPermissonsCheckBox->setChecked(Qt::Checked);
setDirty(true);
}
void AndroidManifestEditorWidget::updateAddRemovePermissionButtons()
{
QStringList permissions = m_permissionsModel->permissions();

View File

@@ -39,6 +39,7 @@
#include <QTimer>
QT_BEGIN_NAMESPACE
class QCheckBox;
class QDomDocument;
class QDomElement;
class QComboBox;
@@ -48,6 +49,8 @@ class QLineEdit;
class QListView;
class QSpinBox;
class QToolButton;
class QXmlStreamReader;
class QXmlStreamWriter;
QT_END_NAMESPACE
namespace Core { class IEditor; }
@@ -120,6 +123,7 @@ private slots:
void setLDPIIcon();
void setMDPIIcon();
void setHDPIIcon();
void defaultPermissionCheckBoxClicked();
void addPermission();
void removePermission();
void updateAddRemovePermissionButtons();
@@ -137,7 +141,6 @@ private:
void syncToEditor();
bool checkDocument(QDomDocument doc, QString *errorMessage, int *errorLine, int *errorColumn);
bool setAndroidAppLibName(QDomDocument document, QDomElement activity, const QString &name);
enum IconDPI { LowDPI, MediumDPI, HighDPI };
QIcon icon(const QString &baseDir, IconDPI dpi);
QString iconPath(const QString &baseDir, IconDPI dpi);
@@ -147,6 +150,15 @@ private:
void hideInfoBar();
Q_SLOT void updateTargetComboBox();
void parseManifest(QXmlStreamReader &reader, QXmlStreamWriter &writer);
void parseApplication(QXmlStreamReader &reader, QXmlStreamWriter &writer);
void parseActivity(QXmlStreamReader &reader, QXmlStreamWriter &writer);
bool parseMetaData(QXmlStreamReader &reader, QXmlStreamWriter &writer);
void parseUsesSdk(QXmlStreamReader &reader, QXmlStreamWriter &writer);
QString parseUsesPermission(QXmlStreamReader &reader, QXmlStreamWriter &writer, const QSet<QString> permissions);
QString parseComment(QXmlStreamReader &reader, QXmlStreamWriter &writer);
void parseUnknownElement(QXmlStreamReader &reader, QXmlStreamWriter &writer);
bool m_dirty; // indicates that we need to call syncToEditor()
bool m_stayClean;
bool m_setAppName;
@@ -173,6 +185,7 @@ private:
QString m_hIconPath;
// Permissions
QCheckBox *m_defaultPermissonsCheckBox;
PermissionsModel *m_permissionsModel;
QListView *m_permissionsListView;
QPushButton *m_addPermissionButton;

View File

@@ -45,7 +45,7 @@
<item row="0" column="0" colspan="2">
<widget class="QPushButton" name="readInfoPushButton">
<property name="toolTip">
<string>Automatically check required Qt libraries from compiled application</string>
<string>Automatically check required Qt libraries from compiled application.</string>
</property>
<property name="text">
<string>Read information from application (must be compiled)</string>

View File

@@ -183,6 +183,7 @@ void AndroidRunner::checkPID()
emit remoteProcessStarted(-1, -1);
}
m_wasStarted = true;
logcatReadStandardOutput();
}
}
@@ -350,22 +351,17 @@ void AndroidRunner::stop()
m_adbLogcatProcess.waitForFinished();
}
void AndroidRunner::logcatReadStandardError()
void AndroidRunner::logcatProcess(const QByteArray &text, QByteArray &buffer, bool onlyError)
{
emit remoteErrorOutput(m_adbLogcatProcess.readAllStandardError());
}
void AndroidRunner::logcatReadStandardOutput()
{
QList<QByteArray> lines = m_adbLogcatProcess.readAllStandardOutput().split('\n');
QList<QByteArray> lines = text.split('\n');
// lines always contains at least one item
lines[0].prepend(m_logcat);
lines[0].prepend(buffer);
if (!lines.last().endsWith('\n')) {
// incomplete line
m_logcat = lines.last();
buffer = lines.last();
lines.removeLast();
} else {
m_logcat.clear();
buffer.clear();
}
QByteArray pid(QString::fromLatin1("%1):").arg(m_processPID).toLatin1());
@@ -375,7 +371,8 @@ void AndroidRunner::logcatReadStandardOutput()
if (line.endsWith('\r'))
line.chop(1);
line.append('\n');
if (line.startsWith("E/")
if (onlyError || line.startsWith("F/")
|| line.startsWith("E/")
|| line.startsWith("D/Qt")
|| line.startsWith("W/"))
emit remoteErrorOutput(line);
@@ -385,6 +382,18 @@ void AndroidRunner::logcatReadStandardOutput()
}
}
void AndroidRunner::logcatReadStandardError()
{
if (m_processPID != -1)
logcatProcess(m_adbLogcatProcess.readAllStandardError(), m_stderrBuffer, true);
}
void AndroidRunner::logcatReadStandardOutput()
{
if (m_processPID != -1)
logcatProcess(m_adbLogcatProcess.readAllStandardOutput(), m_stdoutBuffer, false);
}
void AndroidRunner::adbKill(qint64 pid)
{
{

View File

@@ -82,6 +82,7 @@ private:
void forceStop();
QByteArray runPs();
void findPs();
void logcatProcess(const QByteArray &text, QByteArray &buffer, bool onlyError);
private:
QProcess m_adbLogcatProcess;
@@ -89,7 +90,8 @@ private:
bool m_wasStarted;
int m_tries;
QByteArray m_logcat;
QByteArray m_stdoutBuffer;
QByteArray m_stderrBuffer;
QString m_intentName;
QString m_packageName;
QString m_deviceSerialNumber;

View File

@@ -62,31 +62,6 @@ QWidget *AndroidSettingsPage::widget()
void AndroidSettingsPage::apply()
{
m_widget->saveSettings();
QList<ToolChain *> existingToolChains = ToolChainManager::toolChains();
QList<ToolChain *> toolchains = AndroidToolChainFactory::createToolChainsForNdk(AndroidConfigurations::currentConfig().ndkLocation());
foreach (ToolChain *tc, toolchains) {
bool found = false;
for (int i = 0; i < existingToolChains.count(); ++i) {
if (*(existingToolChains.at(i)) == *tc) {
found = true;
break;
}
}
if (found)
delete tc;
else
ToolChainManager::registerToolChain(tc);
}
foreach (ToolChain *tc, existingToolChains) {
if (tc->type() == QLatin1String(Constants::ANDROID_TOOLCHAIN_TYPE)) {
if (!tc->isValid())
ToolChainManager::deregisterToolChain(tc);
}
}
AndroidConfigurations::updateAutomaticKitList();
}
void AndroidSettingsPage::finish()

View File

@@ -216,7 +216,7 @@ void AndroidSettingsWidget::check(AndroidSettingsWidget::Mode mode)
m_javaState = NotSet;
} else {
Utils::FileName bin = m_androidConfig.openJDKLocation();
bin.appendPath(QLatin1String("bin"));
bin.appendPath(QLatin1String("bin/javac" QTC_HOST_EXE_SUFFIX));
if (!m_androidConfig.openJDKLocation().toFileInfo().exists()
|| !bin.toFileInfo().exists())
m_javaState = Error;

View File

@@ -95,7 +95,7 @@ void ChooseProFilePage::nodeSelected(int index)
// ChooseDirectoryPage
//
ChooseDirectoryPage::ChooseDirectoryPage(CreateAndroidManifestWizard *wizard)
: m_wizard(wizard), m_androidPackageSourceDir(0)
: m_wizard(wizard), m_androidPackageSourceDir(0), m_complete(true)
{
QString androidPackageDir = m_wizard->node()->singleVariableValue(QmakeProjectManager::AndroidPackageSourceDir);
@@ -104,28 +104,68 @@ ChooseDirectoryPage::ChooseDirectoryPage(CreateAndroidManifestWizard *wizard)
label->setWordWrap(true);
fl->addRow(label);
m_sourceDirectoryWarning = new QLabel(this);
m_sourceDirectoryWarning->setVisible(false);
m_sourceDirectoryWarning->setText(tr("The Android package source directory can not be the same as the project directory."));
m_sourceDirectoryWarning->setWordWrap(true);
m_warningIcon = new QLabel(this);
m_warningIcon->setVisible(false);
m_warningIcon->setPixmap(QPixmap(QLatin1String(":/projectexplorer/images/compile_error.png")));
m_warningIcon->setWordWrap(true);
m_warningIcon->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
QHBoxLayout *hbox = new QHBoxLayout;
hbox->addWidget(m_warningIcon);
hbox->addWidget(m_sourceDirectoryWarning);
hbox->setAlignment(m_warningIcon, Qt::AlignTop);
fl->addRow(hbox);
m_androidPackageSourceDir = new Utils::PathChooser(this);
m_androidPackageSourceDir->setExpectedKind(Utils::PathChooser::Directory);
fl->addRow(tr("Android package source directory:"), m_androidPackageSourceDir);
if (androidPackageDir.isEmpty()) {
label->setText(tr("Select the Android package source directory. "
label->setText(tr("Select the Android package source directory.\n\n"
"The files in the Android package source directory are copied to the build directory's "
"Android directory and the default files are overwritten."));
m_androidPackageSourceDir->setPath(QFileInfo(m_wizard->node()->path()).absolutePath().append(QLatin1String("/android")));
connect(m_androidPackageSourceDir, SIGNAL(changed(QString)),
this, SLOT(checkPackageSourceDir()));
} else {
label->setText(tr("The Android manifest file will be created in the ANDROID_PACKAGE_SOURCE_DIR set in the .pro file."));
m_androidPackageSourceDir->setPath(androidPackageDir);
m_androidPackageSourceDir->setReadOnly(true);
}
m_wizard->setDirectory(m_androidPackageSourceDir->path());
connect(m_androidPackageSourceDir, SIGNAL(pathChanged(QString)),
m_wizard, SLOT(setDirectory(QString)));
}
void ChooseDirectoryPage::checkPackageSourceDir()
{
QString projectDir = QFileInfo(m_wizard->node()->path()).absolutePath();
QString newDir = m_androidPackageSourceDir->path();
bool isComplete = QFileInfo(projectDir) != QFileInfo(newDir);
m_sourceDirectoryWarning->setVisible(!isComplete);
m_warningIcon->setVisible(!isComplete);
if (isComplete != m_complete) {
m_complete = isComplete;
emit completeChanged();
}
}
bool ChooseDirectoryPage::isComplete() const
{
return m_complete;
}
//
// CreateAndroidManifestWizard
//

View File

@@ -34,6 +34,7 @@
QT_BEGIN_NAMESPACE
class QComboBox;
class QLabel;
QT_END_NAMESPACE
namespace ProjectExplorer { class Target; }
@@ -70,9 +71,16 @@ class ChooseDirectoryPage : public QWizardPage
Q_OBJECT
public:
ChooseDirectoryPage(CreateAndroidManifestWizard *wizard);
protected:
bool isComplete() const;
private slots:
void checkPackageSourceDir();
private:
CreateAndroidManifestWizard *m_wizard;
Utils::PathChooser *m_androidPackageSourceDir;
QLabel *m_sourceDirectoryWarning;
QLabel *m_warningIcon;
bool m_complete;
};
class CreateAndroidManifestWizard : public Utils::Wizard