Merge remote-tracking branch 'origin/3.1'

Conflicts:
	qtcreator.pri
	qtcreator.qbs
	src/shared/qbs

Change-Id: Iba59e41db72e2afdf594f1f7003215d7d8d1e6d3
This commit is contained in:
Eike Ziller
2014-06-13 10:51:51 +02:00
28 changed files with 400 additions and 62 deletions
+52
View File
@@ -0,0 +1,52 @@
Qt Creator version 3.1.2 is a bugfix release.
The most important changes are listed in this document. For a complete
list of changes, see the Git log for the Qt Creator sources that
you can check out from the public Git repository. For example:
git clone git://gitorious.org/qt-creator/qt-creator.git
git log --cherry-pick --pretty=oneline v3.1.1..v3.1.2
General
* Fixed restoring of output pane button visibility
Editing
* Fixed crash with highlight definitions and indentation based folding enabled
(QTCREATORBUG-12172)
* Fixed setting current file when clicking on split view (QTCREATORBUG-12264)
Help
* Fixed that pressing F1 twice would not go to Help mode
(QTCREATORBUG-9093)
* Fixed filtering in topic chooser
QMake Projects
* Fixed adding files through context menu in case of multiple
resource files (QTCREATORBUG-12297)
* Fixed that resource files were no longer appearing in
Locator and search
Debugging
* GDB
* Worked around GDB crash with large object names
(QTCREATORBUG-12330)
C++ Support
* Fixed crash with anonymous unions with __attribute__
(QTCREATORBUG-12345)
Code Paster
* Fixed crash in case of invalid protocol setting (QTCREATORBUG-12364)
Beautifier
* Fixed problem on Mac when starting Qt Creator from Finder
(QTCREATORBUG-12057)
Platform Specific
Windows
* Fixed matching of paths in Locator (QTCREATORBUG-12007)
QNX
* Fixed font path on devices
-3
View File
@@ -1,5 +1,2 @@
[Paths]
# prefix must be one up because Qt makes it relative to the app's Contents/ path,
# even if that doesn't exist!
Prefix = ..
Plugins = ../../PlugIns
+3
View File
@@ -2263,6 +2263,9 @@
\endlist
If locator does not find some files, you can add them to the \c OTHER_FILES
variable in the .pro file to make them known to \QC.
\section1 Configuring Locator Filters
If the default filters do not match your use case, you can check whether you
+5
View File
@@ -199,6 +199,11 @@
\endlist
You can make additional files known to \QC, so that they become visible in
the \gui Projects view and known to the locator and search, but do not
affect the build system. Add the paths to the files to the \c OTHER_FILES
variable in the .pro file.
\section2 Viewing the File System
If you cannot see a file in the \gui Projects view, switch to the
+6 -6
View File
@@ -2003,12 +2003,6 @@ bool Parser::parseClassSpecifier(SpecifierListAST *&node)
NameAST *name = 0;
parseName(name);
if (! name && LA() == T_LBRACE && (LA(0) == T_CLASS || LA(0) == T_STRUCT || LA(0) == T_UNION || LA(0) == T_ENUM)) {
AnonymousNameAST *ast = new (_pool) AnonymousNameAST;
ast->class_token = classkey_token;
name = ast;
}
bool parsed = false;
const bool previousInFunctionBody = _inFunctionBody;
@@ -2025,6 +2019,12 @@ bool Parser::parseClassSpecifier(SpecifierListAST *&node)
}
if (LA() == T_COLON || LA() == T_LBRACE) {
if (!name) {
AnonymousNameAST *ast = new (_pool) AnonymousNameAST;
ast->class_token = classkey_token;
name = ast;
}
BaseSpecifierListAST *base_clause_list = 0;
if (LA() == T_COLON) {
@@ -216,8 +216,6 @@ DocumentManager::DocumentManager(QObject *parent)
{
d = new DocumentManagerPrivate;
m_instance = this;
connect(ICore::instance(), SIGNAL(contextChanged(QList<Core::IContext*>,Core::Context)),
this, SLOT(syncWithEditor(QList<Core::IContext*>)));
qApp->installEventFilter(this);
readSettings();
@@ -1129,22 +1127,6 @@ void DocumentManager::checkForReload()
// dump();
}
void DocumentManager::syncWithEditor(const QList<Core::IContext *> &context)
{
if (context.isEmpty())
return;
Core::IEditor *editor = Core::EditorManager::currentEditor();
if (!editor || editor->document()->isTemporary())
return;
foreach (IContext *c, context) {
if (editor->widget() == c->widget()) {
setCurrentFile(editor->document()->filePath());
break;
}
}
}
/*!
Adds the \a fileName to the list of recent files. Associates the file to
be reopened with the editor that has the specified \a editorId, if possible.
-1
View File
@@ -163,7 +163,6 @@ private slots:
void checkForNewFileName();
void checkForReload();
void changedFile(const QString &file);
void syncWithEditor(const QList<Core::IContext *> &context);
private:
explicit DocumentManager(QObject *parent);
@@ -526,6 +526,8 @@ void EditorManager::handleContextChange(const QList<Core::IContext *> &context)
d->m_scheduledCurrentEditor = editor;
QTimer::singleShot(0, m_instance, SLOT(setCurrentEditorFromContextChange()));
} else {
if (editor && !editor->document()->isTemporary())
DocumentManager::setCurrentFile(editor->document()->filePath());
updateActions();
}
}
@@ -1027,6 +1029,9 @@ void EditorManager::setCurrentEditorFromContextChange()
IEditor *newCurrent = d->m_scheduledCurrentEditor;
d->m_scheduledCurrentEditor = 0;
setCurrentEditor(newCurrent);
if (!newCurrent->document()->isTemporary())
DocumentManager::setCurrentFile(newCurrent->document()->filePath());
}
void EditorManager::closeEditor(Core::IEditor *editor, bool askAboutModifiedEditors)
@@ -49,14 +49,14 @@ QList<LocatorFilterEntry> BaseFileFilter::matchesFor(QFutureInterface<Core::Loca
updateFiles();
QList<LocatorFilterEntry> betterEntries;
QList<LocatorFilterEntry> goodEntries;
QString needle = trimWildcards(origEntry);
QString needle = trimWildcards(QDir::fromNativeSeparators(origEntry));
const QString lineNoSuffix = EditorManager::splitLineNumber(&needle);
QStringMatcher matcher(needle, Qt::CaseInsensitive);
const QChar asterisk = QLatin1Char('*');
QRegExp regexp(asterisk + needle+ asterisk, Qt::CaseInsensitive, QRegExp::Wildcard);
if (!regexp.isValid())
return betterEntries;
const QChar pathSeparator = QDir::separator();
const QChar pathSeparator(QLatin1Char('/'));
const bool hasPathSeparator = needle.contains(pathSeparator);
const bool hasWildcard = needle.contains(asterisk) || needle.contains(QLatin1Char('?'));
QStringList searchListPaths;
@@ -105,9 +105,9 @@ void Core::Internal::CorePlugin::test_basefilefilter_data()
const QChar pathSeparator = QDir::separator();
const MyTestDataDir testDir(QLatin1String("testdata_basic"));
const QStringList testFiles = QStringList()
<< QDir::toNativeSeparators(testDir.file(QLatin1String("file.cpp")))
<< QDir::toNativeSeparators(testDir.file(QLatin1String("main.cpp")))
<< QDir::toNativeSeparators(testDir.file(QLatin1String("subdir/main.cpp")));
<< QDir::fromNativeSeparators(testDir.file(QLatin1String("file.cpp")))
<< QDir::fromNativeSeparators(testDir.file(QLatin1String("main.cpp")))
<< QDir::fromNativeSeparators(testDir.file(QLatin1String("subdir/main.cpp")));
QStringList testFilesShort;
foreach (const QString &file, testFiles)
testFilesShort << Utils::FileUtils::shortNativePath(Utils::FileName::fromString(file));
+4
View File
@@ -31,6 +31,7 @@
#include "protocol.h"
#include <coreplugin/icore.h>
#include <utils/qtcassert.h>
#include <QPushButton>
#include <QSettings>
@@ -112,6 +113,7 @@ void PasteView::contentChanged()
void PasteView::protocolChanged(int p)
{
QTC_ASSERT(p >= 0 && p < m_protocols.size(), return);
const unsigned caps = m_protocols.at(p)->capabilities();
m_ui.uiDescription->setEnabled(caps & Protocol::PostDescriptionCapability);
m_ui.uiUsername->setEnabled(caps & Protocol::PostUserNameCapability);
@@ -215,6 +217,8 @@ void PasteView::accept()
void PasteView::setProtocol(const QString &protocol)
{
const int index = m_ui.protocolBox->findText(protocol);
if (index < 0)
return;
m_ui.protocolBox->setCurrentIndex(index);
if (index == m_ui.protocolBox->currentIndex())
protocolChanged(index); // Force enabling
@@ -1857,6 +1857,20 @@ void CppToolsPlugin::test_completion_data()
<< QLatin1String("val2")
<< QLatin1String("val3"));
QTest::newRow("nested_anonymous_with___attribute__") << _(
"struct Enclosing\n"
"{\n"
" struct __attribute__((aligned(8)))\n"
" {\n"
" int i;\n"
" };\n"
"};\n"
"Enclosing e;\n"
"@\n"
) << _("e.") << (QStringList()
<< QLatin1String("Enclosing")
<< QLatin1String("i"));
QTest::newRow("enum_inside_namespace") << _(
"namespace Ns\n"
"{\n"
@@ -852,7 +852,7 @@ void MiniProjectTargetSelector::doLayout(bool keepSize)
int oldSummaryLabelY = m_summaryLabel->y();
int kitAreaHeight = m_kitAreaWidget->isVisible() ? m_kitAreaWidget->sizeHint().height() : 0;
int kitAreaHeight = m_kitAreaWidget->isVisibleTo(this) ? m_kitAreaWidget->sizeHint().height() : 0;
// 1. Calculate the summary label height
int summaryLabelY = 1 + kitAreaHeight;
@@ -959,11 +959,9 @@ void MiniProjectTargetSelector::doLayout(bool keepSize)
setFixedSize(m_summaryLabel->width() + 1, heightWithoutKitArea + kitAreaHeight); //1 extra pixel for the border
}
if (isVisibleTo(parentWidget())) {
QPoint moveTo = statusBar->mapToGlobal(QPoint(0,0));
moveTo -= QPoint(0, height());
move(moveTo);
}
QPoint moveTo = statusBar->mapToGlobal(QPoint(0,0));
moveTo -= QPoint(0, height());
move(moveTo);
}
void MiniProjectTargetSelector::setActiveTarget(ProjectExplorer::ProjectConfiguration *pc)
@@ -1403,10 +1401,10 @@ void MiniProjectTargetSelector::activeRunConfigurationChanged(ProjectExplorer::R
void MiniProjectTargetSelector::setVisible(bool visible)
{
doLayout(false);
QWidget::setVisible(visible);
m_projectAction->setChecked(visible);
if (visible) {
doLayout(false);
if (!focusWidget() || !focusWidget()->isVisibleTo(this)) { // Does the second part actually work?
if (m_projectListWidget->isVisibleTo(this))
m_projectListWidget->setFocus();
@@ -1070,7 +1070,7 @@ bool QmakePriFileNode::renameFile(const QString &filePath, const QString &newFil
ProjectExplorer::FolderNode::AddNewInformation QmakePriFileNode::addNewInformation(const QStringList &files, Node *context) const
{
Q_UNUSED(files)
return ProjectExplorer::FolderNode::AddNewInformation(QFileInfo(path()).fileName(), context == this ? 120 : 90);
return ProjectExplorer::FolderNode::AddNewInformation(QFileInfo(path()).fileName(), context && context->projectNode() == this ? 120 : 90);
}
bool QmakePriFileNode::priFileWritable(const QString &path)
@@ -1577,7 +1577,7 @@ bool QmakeProFileNode::showInSimpleTree() const
ProjectExplorer::FolderNode::AddNewInformation QmakeProFileNode::addNewInformation(const QStringList &files, Node *context) const
{
Q_UNUSED(files)
return AddNewInformation(QFileInfo(path()).fileName(), context == this ? 120 : 100);
return AddNewInformation(QFileInfo(path()).fileName(), context && context->projectNode() == this ? 120 : 100);
}
bool QmakeProFileNode::showInSimpleTree(QmakeProjectType projectType) const
@@ -58,6 +58,7 @@
#include <qtsupport/profilereader.h>
#include <qtsupport/qtkitinformation.h>
#include <qtsupport/uicodemodelsupport.h>
#include <resourceeditor/resourcenode.h>
#include <QDebug>
#include <QDir>
@@ -255,6 +256,9 @@ void ProjectFilesVisitor::visitProjectNode(ProjectNode *projectNode)
void ProjectFilesVisitor::visitFolderNode(FolderNode *folderNode)
{
if (qobject_cast<ResourceEditor::ResourceTopLevelNode *>(folderNode))
m_files->files[ResourceType].push_back(folderNode->path());
foreach (FileNode *fileNode, folderNode->fileNodes()) {
const QString path = fileNode->path();
const int type = fileNode->fileType();
+1 -1
View File
@@ -266,7 +266,7 @@ ProjectExplorer::FolderNode::AddNewInformation ResourceTopLevelNode::addNewInfor
// two nodes would be responsible for '/'
// Thus also return a high priority for it
if (ResourceFolderNode *rfn = qobject_cast<ResourceFolderNode *>(context))
if (rfn->prefix() == QLatin1String("/"))
if (rfn->prefix() == QLatin1String("/") && rfn->parentFolderNode() == this)
p = 150;
}
+1
View File
@@ -44,6 +44,7 @@ TopicChooser::TopicChooser(QWidget *parent, const QString &keyword,
ui.setupUi(this);
setFocusProxy(ui.lineEdit);
ui.lineEdit->setFiltering(true);
ui.lineEdit->installEventFilter(this);
ui.lineEdit->setPlaceholderText(tr("Filter"));
ui.label->setText(tr("Choose a topic for <b>%1</b>:").arg(keyword));
+10 -4
View File
@@ -914,8 +914,11 @@ void QMakeEvaluator::visitProVariable(
m_featureRoots = 0;
else if (varName == statics.strQMAKESPEC) {
if (!values(varName).isEmpty()) {
m_qmakespec = values(varName).first().toQString();
m_featureRoots = 0;
QString spec = values(varName).first().toQString();
if (IoUtils::isAbsolutePath(spec)) {
m_qmakespec = spec;
m_featureRoots = 0;
}
}
}
#ifdef PROEVALUATOR_FULL
@@ -1129,8 +1132,11 @@ bool QMakeEvaluator::loadSpecInternal()
// the source of the qmake.conf at the end of the default/qmake.conf in
// the QMAKESPEC_ORIGINAL variable.
const ProString &orig_spec = first(ProKey("QMAKESPEC_ORIGINAL"));
if (!orig_spec.isEmpty())
m_qmakespec = orig_spec.toQString();
if (!orig_spec.isEmpty()) {
QString spec = orig_spec.toQString();
if (IoUtils::isAbsolutePath(spec))
m_qmakespec = spec;
}
# endif
#endif
valuesRef(ProKey("QMAKESPEC")) = ProString(m_qmakespec);
+39
View File
@@ -183,6 +183,8 @@ private slots:
void q_enum_1();
void incomplete_ast();
void unnamed_class();
void unnamed_class_data();
};
void tst_AST::gcc_attributes_1()
@@ -1743,6 +1745,43 @@ void tst_AST::incomplete_ast()
QVERIFY(ast);
}
static ClassSpecifierAST *classSpecifierInSimpleDeclaration(SimpleDeclarationAST *simpleDeclaration)
{
Q_ASSERT(simpleDeclaration);
SpecifierListAST *specifier = simpleDeclaration->decl_specifier_list;
Q_ASSERT(specifier);
Q_ASSERT(specifier->value);
return specifier->value->asClassSpecifier();
}
void tst_AST::unnamed_class()
{
QFETCH(QByteArray, source);
QVERIFY(!source.isEmpty());
QSharedPointer<TranslationUnit> unit(parseDeclaration(source));
QVERIFY(unit->ast());
SimpleDeclarationAST *simpleDeclaration = unit->ast()->asSimpleDeclaration();
QVERIFY(simpleDeclaration);
ClassSpecifierAST *clazz = classSpecifierInSimpleDeclaration(simpleDeclaration);
QVERIFY(clazz);
QVERIFY(clazz->name);
QVERIFY(clazz->name->asAnonymousName());
QCOMPARE(diag.errorCount, 0);
}
void tst_AST::unnamed_class_data()
{
QTest::addColumn<QByteArray>("source");
typedef QByteArray _;
QTest::newRow("unnamed-only") << _("class {};");
QTest::newRow("unnamed-derived") << _("class : B {};");
QTest::newRow("unnamed-__attribute__") << _("class __attribute__((aligned(8))){};");
}
void tst_AST::initTestCase()
{
control.setDiagnosticClient(&diag);
-2
View File
@@ -131,7 +131,6 @@
:Qt Creator.Compile Output_Core::OutputWindow {type='Core::OutputWindow' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow' windowTitle='Compile Output'}
:Qt Creator.DebugModeWidget_QSplitter {name='DebugModeWidget' type='QSplitter' visible='1' window=':Qt Creator_Core::Internal::MainWindow'}
:Qt Creator.Go to Help Mode_QToolButton {text='Go to Help Mode' type='QToolButton' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'}
:Qt Creator.Help_Search for:_QLineEdit {leftWidget=':Qt Creator.Search for:_QLabel' type='QLineEdit' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'}
:Qt Creator.Issues_QListView {type='QListView' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow' windowTitle='Issues'}
:Qt Creator.Project.Menu.File_QMenu {name='Project.Menu.File' type='QMenu'}
:Qt Creator.Project.Menu.Folder_QMenu {name='Project.Menu.Folder' type='QMenu' visible='1' window=':Qt Creator_Core::Internal::MainWindow'}
@@ -139,7 +138,6 @@
:Qt Creator.ReRun_QToolButton {toolTip='Re-run this run-configuration' type='QToolButton' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'}
:Qt Creator.Replace All_QToolButton {name='replaceAllButton' text='Replace All' type='QToolButton' visible='1' window=':Qt Creator_Core::Internal::MainWindow'}
:Qt Creator.Replace_QToolButton {name='replaceButton' text='Replace' type='QToolButton' visible='1' window=':Qt Creator_Core::Internal::MainWindow'}
:Qt Creator.Search for:_QLabel {text='Search for:' type='QLabel' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'}
:Qt Creator.Stop_QToolButton {text='Stop' type='QToolButton' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'}
:Qt Creator.replaceEdit_Utils::FilterLineEdit {name='replaceEdit' type='Utils::FancyLineEdit' visible='1' window=':Qt Creator_Core::Internal::MainWindow'}
:Qt Creator.scrollArea_QScrollArea {name='scrollArea' type='QScrollArea' visible='1' window=':Qt Creator_Core::Internal::MainWindow'}
+3 -4
View File
@@ -84,8 +84,7 @@ def waitForCompile(timeout=60000):
def dumpBuildIssues(listModel):
issueDump = []
for row in range(listModel.rowCount()):
index = listModel.index(row, 0)
for index in dumpIndices(listModel):
issueDump.extend([map(lambda role: index.data(role).toString(),
range(Qt.UserRole, Qt.UserRole + 6))])
return issueDump
@@ -165,8 +164,8 @@ def iterateBuildConfigs(kitCount, filter = ""):
def selectBuildConfig(targetCount, currentTarget, configName, afterSwitchTo=ViewConstants.EDIT):
switchViewTo(ViewConstants.PROJECTS)
switchToBuildOrRunSettingsFor(targetCount, currentTarget, ProjectSettings.BUILD)
selectFromCombo(":scrollArea.Edit build configuration:_QComboBox", configName)
progressBarWait(30000)
if selectFromCombo(":scrollArea.Edit build configuration:_QComboBox", configName) or targetCount > 1:
progressBarWait(30000)
return getQtInformationForBuildSettings(targetCount, True, afterSwitchTo)
# This will not trigger a rebuild. If needed, caller has to do this.
+1 -1
View File
@@ -81,7 +81,7 @@ def setBreakpointsForCurrentProject(filesAndLines):
for curFile,curLine in current.iteritems():
if not openDocument(curFile):
return False
editor = getEditorForFileSuffix(curFile)
editor = getEditorForFileSuffix(curFile, True)
if not placeCursorToLine(editor, curLine, True):
return False
invokeMenuItem("Debug", "Toggle Breakpoint")
+8 -1
View File
@@ -255,7 +255,7 @@ def verifyProperties(properties, expectedProps):
result[key] = None
return result
def getEditorForFileSuffix(curFile):
def getEditorForFileSuffix(curFile, treeViewSyntax=False):
cppEditorSuffixes = ["cpp", "cc", "CC", "h", "H", "cp", "cxx", "C", "c++", "inl", "moc", "qdoc",
"tcc", "tpp", "t++", "c", "cu", "m", "mm", "hh", "hxx", "h++", "hpp", "hp"]
qmlEditorSuffixes = ["qml", "qmlproject", "js", "qs", "qtt"]
@@ -263,6 +263,13 @@ def getEditorForFileSuffix(curFile):
glslEditorSuffixes= ["frag", "vert", "fsh", "vsh", "glsl", "shader", "gsh"]
pytEditorSuffixes = ["py", "pyw", "wsgi"]
suffix = __getFileSuffix__(curFile)
expected = os.path.basename(curFile)
if treeViewSyntax:
expected = simpleFileName(curFile)
mainWindow = waitForObject(":Qt Creator_Core::Internal::MainWindow")
if not waitFor("expected in str(mainWindow.windowTitle)", 5000):
test.fatal("Window title (%s) did not switch to expected file (%s)."
% (str(mainWindow.windowTitle), expected))
try:
if suffix in cppEditorSuffixes:
editor = waitForObject(":Qt Creator_CppEditor::Internal::CPPEditorWidget")
+6 -1
View File
@@ -603,7 +603,12 @@ def readFile(filename):
return content
def simpleFileName(navigatorFileName):
return ".".join(navigatorFileName.split(".")[-2:]).replace("\\","")
# try to find the last part of the given name, assume it's inside a (folder) structure
search = re.search(".*[^\\\\]\.(.*)$", navigatorFileName)
if search:
return search.group(1).replace("\\", "")
# it's just the filename
return navigatorFileName.replace("\\", "")
def clickOnTab(tabBarStr, tabText, timeout=5000):
if not waitFor("object.exists(tabBarStr)", timeout):
+7 -4
View File
@@ -96,10 +96,13 @@ def main():
mouseClick(waitForObject("{column='0' container=':Qt Creator_QHelpContentWidget' "
"text='Qt Reference Documentation' type='QModelIndex'}"))
# try to search keyword from list
searchLineEdit = getChildByClass(waitForObject("{type='QHelpSearchQueryWidget' unnamed='1' visible='1' "
"window=':Qt Creator_Core::Internal::MainWindow'}"),
"QLineEdit")
for searchKeyword,shouldFind in searchKeywordDictionary.items():
mouseClick(waitForObject(":Qt Creator.Help_Search for:_QLineEdit"))
replaceEditorContent(":Qt Creator.Help_Search for:_QLineEdit", searchKeyword)
type(waitForObject(":Qt Creator.Help_Search for:_QLineEdit"), "<Return>")
mouseClick(searchLineEdit)
replaceEditorContent(searchLineEdit, searchKeyword)
type(searchLineEdit, "<Return>")
progressBarWait(warn=False)
if shouldFind:
test.verify(waitFor("re.match('[1-9]\d* - [1-9]\d* of [1-9]\d* Hits',"
@@ -153,7 +156,7 @@ def main():
test.verify("sql" in str(__getSelectedText__()).lower(),
"sql advanced search result can be found")
# verify if simple search is properly disabled
test.verify(findObject(":Qt Creator.Help_Search for:_QLineEdit").enabled == False,
test.verify(not searchLineEdit.enabled,
"Verifying if simple search is not active in advanced mode.")
# exit
invokeMenuItem("File", "Exit")
+1 -1
View File
@@ -7,6 +7,6 @@ HOOK_SUB_PROCESSES=false
IMPLICITAUTSTART=0
LANGUAGE=Python
OBJECTMAP=../objects.map
TEST_CASES=tst_basic_cpp_support tst_delete_externally tst_edit_externally tst_memberoperator tst_modify_readonly tst_qml_editor tst_qml_indent tst_rename_macros tst_revert_changes tst_select_all
TEST_CASES=tst_basic_cpp_support tst_delete_externally tst_edit_externally tst_generic_highlighter tst_memberoperator tst_modify_readonly tst_qml_editor tst_qml_indent tst_rename_macros tst_revert_changes tst_select_all
VERSION=2
WRAPPERS=Qt
@@ -0,0 +1,217 @@
#############################################################################
##
## Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
## Contact: http://www.qt-project.org/legal
##
## This file is part of Qt Creator.
##
## Commercial License Usage
## Licensees holding valid commercial Qt licenses may use this file in
## accordance with the commercial license agreement provided with the
## Software or, alternatively, in accordance with the terms contained in
## a written agreement between you and Digia. For licensing terms and
## conditions see http://qt.digia.com/licensing. For further information
## use the contact form at http://qt.digia.com/contact-us.
##
## GNU Lesser General Public License Usage
## Alternatively, this file may be used under the terms of the GNU Lesser
## General Public License version 2.1 as published by the Free Software
## Foundation and appearing in the file LICENSE.LGPL included in the
## packaging of this file. Please review the following information to
## ensure the GNU Lesser General Public License version 2.1 requirements
## will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
##
## In addition, as a special exception, Digia gives you certain additional
## rights. These rights are described in the Digia Qt LGPL Exception
## version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
##
#############################################################################
source("../../shared/qtcreator.py")
def createFile(folder, filename):
__createProjectOrFileSelectType__(" General", "Text File", isProject = False)
replaceEditorContent(waitForObject("{name='nameLineEdit' visible='1' "
"type='Utils::FileNameValidatingLineEdit'}"), filename)
replaceEditorContent(waitForObject("{type='Utils::FancyLineEdit' unnamed='1' visible='1' "
"window=':New Text File_Utils::FileWizardDialog'}"), folder)
clickButton(waitForObject(":Next_QPushButton"))
__createProjectHandleLastPage__()
def clickTableGetPatternLineEdit(table, row):
clickItem(table, "%d/0" % row, 5, 5, 0, Qt.LeftButton)
return waitForObject("{name='patternsLineEdit' type='QLineEdit' visible='1'}")
def getOrModifyFilePatternsFor(mimeType, filter='', toBePresent=None):
toSuffixArray = lambda x : [pat.replace("*", "") for pat in x.split(";")]
result = []
invokeMenuItem("Tools", "Options...")
waitForObjectItem(":Options_QListView", "Environment")
clickItem(":Options_QListView", "Environment", 14, 15, 0, Qt.LeftButton)
waitForObject("{container=':Options.qt_tabwidget_tabbar_QTabBar' type='TabItem' "
"text='MIME Types'}")
clickOnTab(":Options.qt_tabwidget_tabbar_QTabBar", "MIME Types")
replaceEditorContent(waitForObject("{name='filterLineEdit' type='QLineEdit' visible='1'}"),
filter)
mimeTypeTable = waitForObject("{name='mimeTypesTableView' type='QTableView' visible='1'}")
model = mimeTypeTable.model()
if filter == '':
for row in range(model.rowCount()):
if str(model.data(model.index(row, 0)).toString()) == mimeType:
result = toSuffixArray(str(clickTableGetPatternLineEdit(mimeTypeTable, row).text))
break
clickButton(":Options.Cancel_QPushButton")
if result == ['']:
test.warning("MIME type '%s' seems to have no file patterns." % mimeType)
return result
waitFor('model.rowCount() == 1', 2000)
if model.rowCount() == 1:
patternsLineEd = clickTableGetPatternLineEdit(mimeTypeTable, 0)
patterns = str(patternsLineEd.text)
if toBePresent:
actualSuffixes = toSuffixArray(patterns)
toBeAddedSet = set(toBePresent).difference(set(actualSuffixes))
if toBeAddedSet:
patterns += ";*" + ";*".join(toBeAddedSet)
replaceEditorContent(patternsLineEd, patterns)
clickButton(":Options.OK_QPushButton")
try:
mBox = waitForObject("{type='QMessageBox' unnamed='1' visible='1' "
"text?='Conflicting pattern*'}", 2000)
conflictingSet = set(str(mBox.detailedText).replace("*", "").splitlines())
sendEvent("QCloseEvent", mBox)
if toBeAddedSet.intersection(conflictingSet):
test.fatal("At least one of the patterns to be added is already in use "
"for another MIME type.",
"Conflicting patterns: %s" % str(conflictingSet))
if conflictingSet.difference(toBeAddedSet):
test.fail("MIME type handling failed. (QTCREATORBUG-12149?)",
"Conflicting patterns: %s" % str(conflictingSet))
# re-check the patterns
result = getOrModifyFilePatternsFor(mimeType)
except:
result = toSuffixArray(patterns)
test.passes("Added suffixes")
return result
else:
result = toSuffixArray(patterns)
elif model.rowCount() > 1:
test.warning("MIME type '%s' has ambiguous results." % mimeType)
else:
test.log("MIME type '%s' seems to be unknown to the system." % mimeType)
clickButton(":Options.Cancel_QPushButton")
return result
def uncheckGenericHighlighterFallback():
invokeMenuItem("Tools", "Options...")
waitForObjectItem(":Options_QListView", "Text Editor")
clickItem(":Options_QListView", "Text Editor", 14, 15, 0, Qt.LeftButton)
waitForObject("{container=':Options.qt_tabwidget_tabbar_QTabBar' type='TabItem' "
"text='Generic Highlighter'}")
clickOnTab(":Options.qt_tabwidget_tabbar_QTabBar", "Generic Highlighter")
ensureChecked("{name='useFallbackLocation' text='Use fallback location' type='QCheckBox' "
"visible='1'}", False)
clickButton(":Options.OK_QPushButton")
def addHighlighterDefinition(language):
global tmpSettingsDir
test.log("Adding highlighter definitions for '%s'." % language)
invokeMenuItem("Tools", "Options...")
waitForObjectItem(":Options_QListView", "Text Editor")
clickItem(":Options_QListView", "Text Editor", 14, 15, 0, Qt.LeftButton)
waitForObject("{container=':Options.qt_tabwidget_tabbar_QTabBar' type='TabItem' "
"text='Generic Highlighter'}")
clickOnTab(":Options.qt_tabwidget_tabbar_QTabBar", "Generic Highlighter")
clickButton("{text='Download Definitions...' type='QPushButton' unnamed='1' visible='1'}")
table = waitForObject("{name='definitionsTable' type='QTableWidget' visible='1'}")
model = table.model()
for row in range(model.rowCount()):
if str(model.data(model.index(row, 0)).toString()) == language:
clickItem(table, "%d/0" % row, 5, 5, 0, Qt.LeftButton)
clickButton("{name='downloadButton' text='Download Selected Definitions' "
"type='QPushButton' visible='1'}")
# downloading happens asynchronously
languageFile = os.path.join(tmpSettingsDir, "QtProject", "qtcreator",
"generic-highlighter", "%s.xml" % language.lower())
test.verify(waitFor("os.path.exists(languageFile)", 10000),
"Verifying whether file has been downloaded and placed to settings.")
clickButton("{text='Download Definitions...' type='QPushButton' unnamed='1' "
"visible='1'}")
table = waitForObject("{name='definitionsTable' type='QTableWidget' visible='1'}")
model = table.model()
test.verify(str(model.data(model.index(row, 1))) != "",
"Verifying a definition has been downloaded.")
clickButton("{text='Close' type='QPushButton' unnamed='1' visible='1'}")
clickButton(":Options.OK_QPushButton")
return True
test.fail("Could not find the specified language (%s) to download a highlighter definition"
% language)
clickButton("{text='Close' type='QPushButton' unnamed='1' visible='1'}")
clickButton(":Options.OK_QPushButton")
return False
def hasSuffix(fileName, suffixPatterns):
for suffix in suffixPatterns:
if fileName.endswith(suffix):
return True
return False
def main():
miss = "A highlight definition was not found for this file. Would you like to try to find one?"
startApplication("qtcreator" + SettingsPath)
if not startedWithoutPluginError():
return
uncheckGenericHighlighterFallback()
patterns = getOrModifyFilePatternsFor("text/x-haskell", "haskell")
folder = tempDir()
filesToTest = ["Main.lhs", "Main.hs"]
code = ['module Main where', '', 'main :: IO ()', '', 'main = putStrLn "Hello World!"']
for current in filesToTest:
createFile(folder, current)
editor = getEditorForFileSuffix(current)
expectHint = hasSuffix(current, patterns)
mssg = "Verifying whether hint for missing highlight definition is present. (expected: %s)"
try:
waitForObject("{text='%s' type='QLabel' unnamed='1' visible='1' "
"window=':Qt Creator_Core::Internal::MainWindow'}" % miss, 2000)
test.verify(expectHint, mssg % str(expectHint))
except:
test.verify(not expectHint, mssg % str(expectHint))
# literate haskell: first character must be '>' otherwise it's a comment
if current.endswith(".lhs"):
typeLines(editor, [">" + line for line in code])
else:
typeLines(editor, code)
invokeMenuItem("File", "Save All")
invokeMenuItem("File", "Close All")
addedHighlighterDefinition = addHighlighterDefinition("Haskell")
patterns = getOrModifyFilePatternsFor('text/x-haskell', 'haskell', ['.lhs', '.hs'])
home = os.path.expanduser("~")
for current in filesToTest:
recentFile = os.path.join(folder, current)
if recentFile.startswith(home) and platform.system() in ('Linux', 'Darwin'):
recentFile = recentFile.replace(home, "~", 1)
invokeMenuItem("File", "Recent Files", recentFile)
editor = getEditorForFileSuffix(current)
try:
waitForObject("{text='%s' type='QLabel' unnamed='1' visible='1' "
"window=':Qt Creator_Core::Internal::MainWindow'}" % miss, 2000)
test.verify(not addedHighlighterDefinition and hasSuffix(current, patterns),
"Hint for missing highlight definition was present.")
except:
test.verify(addedHighlighterDefinition or not hasSuffix(current, patterns),
"Hint for missing highlight definition is not shown.")
placeCursorToLine(editor, '.*%s' % code[-1], True)
for _ in range(23):
type(editor, "<Left>")
type(editor, "<Return>")
if current.endswith(".lhs"):
type(editor, ">")
type(editor, "<Tab>")
invokeMenuItem("File", "Save All")
invokeMenuItem("File", "Exit")
@@ -58,7 +58,7 @@ def main():
test.fatal("Could not open file '%s'" % simpleFileName(file))
continue
test.log("Changing file '%s'" % simpleFileName(file))
typeLines(getEditorForFileSuffix(file), "")
typeLines(getEditorForFileSuffix(file, True), "")
# try to compile
clickButton(waitForObject(":*Qt Creator.Build Project_Core::Internal::FancyToolButton"))
try: