Merge remote-tracking branch 'origin/5.12' into 5.13

Change-Id: Ic7c790602e4ac3f4a0d3d4630441b28cf76f75fc
Qt Forward Merge Bot 2019-06-11 01:00:06 +02:00
commit 93f7a24df0
11 changed files with 252 additions and 231 deletions

View File

@ -514,5 +514,36 @@ Q_CONSTRUCTOR_FUNCTION(qt_apple_check_os_version);
// -------------------------------------------------------------------------
void QMacKeyValueObserver::addObserver()
{
[object addObserver:observer forKeyPath:keyPath
options:NSKeyValueObservingOptionNew context:callback.get()];
}
void QMacKeyValueObserver::removeObserver() {
if (object)
[object removeObserver:observer forKeyPath:keyPath context:callback.get()];
object = nil;
}
KeyValueObserver *QMacKeyValueObserver::observer = [[KeyValueObserver alloc] init];
QT_END_NAMESPACE
@implementation KeyValueObserver
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
change:(NSDictionary<NSKeyValueChangeKey, id> *)change context:(void *)context
{
Q_UNUSED(keyPath);
Q_UNUSED(object);
Q_UNUSED(change);
(*reinterpret_cast<QMacKeyValueObserver::Callback*>(context))();
}
@end
QT_BEGIN_NAMESPACE
// -------------------------------------------------------------------------
QT_END_NAMESPACE

View File

@ -67,6 +67,7 @@
#ifdef __OBJC__
#include <Foundation/Foundation.h>
#include <functional>
#endif
#include "qstring.h"
@ -334,6 +335,60 @@ public:
private:
id observer = nil;
};
QT_END_NAMESPACE
@interface QT_MANGLE_NAMESPACE(KeyValueObserver) : NSObject
@end
QT_NAMESPACE_ALIAS_OBJC_CLASS(KeyValueObserver);
QT_BEGIN_NAMESPACE
class Q_CORE_EXPORT QMacKeyValueObserver
{
public:
using Callback = std::function<void()>;
QMacKeyValueObserver() {}
// Note: QMacKeyValueObserver must not outlive the object observed!
QMacKeyValueObserver(id object, NSString *keyPath, Callback callback)
: object(object), keyPath(keyPath), callback(new Callback(callback)) { addObserver(); }
QMacKeyValueObserver(const QMacKeyValueObserver &other)
: QMacKeyValueObserver(other.object, other.keyPath, *other.callback.get()) {}
QMacKeyValueObserver(QMacKeyValueObserver &&other) { swap(other, *this); }
~QMacKeyValueObserver() { removeObserver(); }
QMacKeyValueObserver &operator=(const QMacKeyValueObserver &other) {
QMacKeyValueObserver tmp(other);
swap(tmp, *this);
return *this;
}
QMacKeyValueObserver &operator=(QMacKeyValueObserver &&other) {
QMacKeyValueObserver tmp(std::move(other));
swap(tmp, *this);
return *this;
}
void removeObserver();
private:
void swap(QMacKeyValueObserver &first, QMacKeyValueObserver &second) {
std::swap(first.object, second.object);
std::swap(first.keyPath, second.keyPath);
std::swap(first.callback, second.callback);
}
void addObserver();
id object = nil;
NSString *keyPath = nullptr;
std::unique_ptr<Callback> callback;
static KeyValueObserver *observer;
};
#endif
// -------------------------------------------------------------------------

View File

@ -97,35 +97,35 @@ QEnterEvent::~QEnterEvent()
/*!
\fn QPoint QEnterEvent::globalPos() const
Returns the global position of the widget \e{at the time of the event}.
Returns the global position of the mouse cursor \e{at the time of the event}.
*/
/*!
\fn int QEnterEvent::globalX() const
Returns the global position on the X-axis of the mouse cursor relative to the the widget.
Returns the global position on the X-axis of the mouse cursor \e{at the time of the event}.
*/
/*!
\fn int QEnterEvent::globalY() const
Returns the global position on the Y-axis of the mouse cursor relative to the the widget.
Returns the global position on the Y-axis of the mouse cursor \e{at the time of the event}.
*/
/*!
\fn QPoint QEnterEvent::localPos() const
\fn QPointF QEnterEvent::localPos() const
Returns the mouse cursor's position relative to the receiving widget.
*/
/*!
\fn QPoint QEnterEvent::pos() const
Returns the position of the mouse cursor in global screen coordinates.
Returns the position of the mouse cursor relative to the receiving widget.
*/
/*!
\fn QPoint QEnterEvent::screenPos() const
\fn QPointF QEnterEvent::screenPos() const
Returns the position of the mouse cursor relative to the receiving screen.
*/
/*!
\fn QPoint QEnterEvent::windowPos() const
\fn QPointF QEnterEvent::windowPos() const
Returns the position of the mouse cursor relative to the receiving window.
*/

View File

@ -1358,6 +1358,8 @@ QTextCursor QTextDocument::find(const QString &subString, int from, FindFlags op
blockOffset = 0;
}
} else {
if (blockOffset == block.length() - 1)
--blockOffset; // make sure to skip end-of-paragraph character
while (block.isValid()) {
if (findInBlock(block, subString, blockOffset, options, &cursor))
return cursor;

View File

@ -87,7 +87,7 @@ private:
QMacNotificationObserver m_systemColorObserver;
mutable QHash<QPlatformTheme::Palette, QPalette*> m_palettes;
mutable QHash<QPlatformTheme::Font, QFont*> m_fonts;
QT_MANGLE_NAMESPACE(QCocoaThemeAppAppearanceObserver) *m_appearanceObserver;
QMacKeyValueObserver m_appearanceObserver;
};
QT_END_NAMESPACE

View File

@ -80,57 +80,22 @@
#include <CoreServices/CoreServices.h>
#if QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_14)
@interface QT_MANGLE_NAMESPACE(QCocoaThemeAppAppearanceObserver) : NSObject
@property (readonly, nonatomic) QCocoaTheme *theme;
- (instancetype)initWithTheme:(QCocoaTheme *)theme;
@end
QT_NAMESPACE_ALIAS_OBJC_CLASS(QCocoaThemeAppAppearanceObserver);
@implementation QCocoaThemeAppAppearanceObserver
- (instancetype)initWithTheme:(QCocoaTheme *)theme
{
if ((self = [super init])) {
_theme = theme;
[NSApp addObserver:self forKeyPath:@"effectiveAppearance" options:NSKeyValueObservingOptionNew context:nullptr];
}
return self;
}
- (void)dealloc
{
[NSApp removeObserver:self forKeyPath:@"effectiveAppearance"];
[super dealloc];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
change:(NSDictionary<NSKeyValueChangeKey, id> *)change context:(void *)context
{
Q_UNUSED(change);
Q_UNUSED(context);
Q_ASSERT(object == NSApp);
Q_ASSERT([keyPath isEqualToString:@"effectiveAppearance"]);
if (__builtin_available(macOS 10.14, *))
NSAppearance.currentAppearance = NSApp.effectiveAppearance;
self.theme->handleSystemThemeChange();
}
@end
#endif // QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_14)
QT_BEGIN_NAMESPACE
const char *QCocoaTheme::name = "cocoa";
QCocoaTheme::QCocoaTheme()
: m_systemPalette(nullptr), m_appearanceObserver(nil)
: m_systemPalette(nullptr)
{
#if QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_14)
if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSMojave)
m_appearanceObserver = [[QCocoaThemeAppAppearanceObserver alloc] initWithTheme:this];
if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSMojave) {
m_appearanceObserver = QMacKeyValueObserver(NSApp, @"effectiveAppearance", [this] {
if (__builtin_available(macOS 10.14, *))
NSAppearance.currentAppearance = NSApp.effectiveAppearance;
handleSystemThemeChange();
});
}
#endif
m_systemColorObserver = QMacNotificationObserver(nil,
@ -141,9 +106,6 @@ QCocoaTheme::QCocoaTheme()
QCocoaTheme::~QCocoaTheme()
{
if (m_appearanceObserver)
[m_appearanceObserver release];
reset();
qDeleteAll(m_fonts);
}

View File

@ -144,41 +144,6 @@ static QWindow *qt_getWindow(const QWidget *widget)
return widget ? widget->window()->windowHandle() : 0;
}
@interface QT_MANGLE_NAMESPACE(NotificationReceiver) : NSObject
@end
QT_NAMESPACE_ALIAS_OBJC_CLASS(NotificationReceiver);
@implementation NotificationReceiver
{
QMacStylePrivate *privateStyle;
}
- (instancetype)initWithPrivateStyle:(QMacStylePrivate *)style
{
if (self = [super init])
privateStyle = style;
return self;
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
change:(NSDictionary<NSKeyValueChangeKey, id> *)change context:(void *)context
{
Q_UNUSED(keyPath);
Q_UNUSED(object);
Q_UNUSED(change);
Q_UNUSED(context);
Q_ASSERT([keyPath isEqualToString:@"effectiveAppearance"]);
Q_ASSERT(object == NSApp);
for (NSView *b : privateStyle->cocoaControls)
[b release];
privateStyle->cocoaControls.clear();
}
@end
@interface QT_MANGLE_NAMESPACE(QIndeterminateProgressIndicator) : NSProgressIndicator
@property (readonly, nonatomic) NSInteger animators;
@ -2080,7 +2045,6 @@ void QMacStylePrivate::resolveCurrentNSView(QWindow *window) const
QMacStyle::QMacStyle()
: QCommonStyle(*new QMacStylePrivate)
{
Q_D(QMacStyle);
QMacAutoReleasePool pool;
static QMacNotificationObserver scrollbarStyleObserver(nil,
@ -2093,26 +2057,21 @@ QMacStyle::QMacStyle()
QCoreApplication::sendEvent(o, &event);
});
d->receiver = [[NotificationReceiver alloc] initWithPrivateStyle:d];
#if QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_14)
Q_D(QMacStyle);
// FIXME: Tie this logic into theme change, or even polish/unpolish
if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSMojave) {
[NSApplication.sharedApplication addObserver:d->receiver forKeyPath:@"effectiveAppearance"
options:NSKeyValueObservingOptionNew context:nullptr];
d->appearanceObserver = QMacKeyValueObserver(NSApp, @"effectiveAppearance", [&d] {
for (NSView *b : d->cocoaControls)
[b release];
d->cocoaControls.clear();
});
}
#endif
}
QMacStyle::~QMacStyle()
{
Q_D(QMacStyle);
QMacAutoReleasePool pool;
#if QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_14)
if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSMojave)
[NSApplication.sharedApplication removeObserver:d->receiver forKeyPath:@"effectiveAppearance"];
#endif
[d->receiver release];
}
void QMacStyle::polish(QPalette &)

View File

@ -149,7 +149,6 @@ Q_FORWARD_DECLARE_MUTABLE_CG_TYPE(CGContext);
Q_FORWARD_DECLARE_OBJC_CLASS(NSView);
Q_FORWARD_DECLARE_OBJC_CLASS(NSCell);
Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(NotificationReceiver));
QT_BEGIN_NAMESPACE
@ -288,13 +287,14 @@ public:
static QVector<QPointer<QObject> > scrollBars;
mutable QPointer<QFocusFrame> focusWidget;
QT_MANGLE_NAMESPACE(NotificationReceiver) *receiver;
mutable NSView *backingStoreNSView;
mutable QHash<CocoaControl, NSView *> cocoaControls;
mutable QHash<CocoaControl, NSCell *> cocoaCells;
QFont smallSystemFont;
QFont miniSystemFont;
QMacKeyValueObserver appearanceObserver;
};
QT_END_NAMESPACE

View File

@ -1001,7 +1001,7 @@ void Generator::generateMetacall()
needUser |= p.user.endsWith(')');
}
fprintf(out, "\n#ifndef QT_NO_PROPERTIES\n ");
fprintf(out, "\n#ifndef QT_NO_PROPERTIES\n ");
if (needElse)
fprintf(out, "else ");
fprintf(out,

View File

@ -319,6 +319,15 @@ void tst_QTextDocument::find_data()
QTest::newRow("nbsp") << "Hello" + QString(QChar(QChar::Nbsp)) +"World" << " " << int(QTextDocument::FindCaseSensitively) << 0 << 5 << 6;
QTest::newRow("from-the-end") << "Hello World" << "Hello World" << int(QTextDocument::FindCaseSensitively| QTextDocument::FindBackward) << 11 << 0 << 11;
QTest::newRow("bw-cross-paras-1") << "a1\na2\nb1" << "a" << int(QTextDocument::FindBackward) << 7 << 3 << 4;
QTest::newRow("bw-cross-paras-2") << "a1\na2\nb1" << "a" << int(QTextDocument::FindBackward) << 6 << 3 << 4;
QTest::newRow("bw-cross-paras-3") << "a1\na2\nb1" << "a" << int(QTextDocument::FindBackward) << 5 << 3 << 4;
QTest::newRow("bw-cross-paras-4") << "a1\na2\nb1" << "a" << int(QTextDocument::FindBackward) << 3 << 0 << 1;
QTest::newRow("bw-cross-paras-5") << "xa\n\nb1" << "a" << int(QTextDocument::FindBackward) << 5 << 1 << 2;
QTest::newRow("bw-cross-paras-6") << "xa\n\nb1" << "a" << int(QTextDocument::FindBackward) << 4 << 1 << 2;
QTest::newRow("bw-cross-paras-7") << "xa\n\nb1" << "a" << int(QTextDocument::FindBackward) << 3 << 1 << 2;
QTest::newRow("bw-cross-paras-8") << "xa\n\nb1" << "a" << int(QTextDocument::FindBackward) << 2 << 1 << 2;
}
void tst_QTextDocument::find()

View File

@ -38,47 +38,50 @@
#include "../../../../shared/filesystem.h"
#include <memory>
Q_DECLARE_METATYPE(QCompleter::CompletionMode)
using namespace QTestPrivate;
class CsvCompleter : public QCompleter
{
Q_OBJECT
public:
CsvCompleter(QObject *parent = 0) : QCompleter(parent), csv(true) { }
using QCompleter::QCompleter;
QString pathFromIndex(const QModelIndex& sourceIndex) const;
QString pathFromIndex(const QModelIndex& sourceIndex) const override;
void setCsvCompletion(bool set) { csv = set; }
protected:
QStringList splitPath(const QString &path) const {
QStringList splitPath(const QString &path) const override
{
return csv ? path.split(QLatin1Char(',')) : QCompleter::splitPath(path);
}
private:
bool csv;
bool csv = true;
};
QString CsvCompleter::pathFromIndex(const QModelIndex& si) const
QString CsvCompleter::pathFromIndex(const QModelIndex &sourceIndex) const
{
if (!csv)
return QCompleter::pathFromIndex(si);
return QCompleter::pathFromIndex(sourceIndex);
if (!si.isValid())
if (!sourceIndex.isValid())
return QString();
QModelIndex idx = si;
QModelIndex idx = sourceIndex;
QStringList list;
do {
QString t = model()->data(idx, completionRole()).toString();
list.prepend(t);
QModelIndex parent = idx.parent();
idx = parent.sibling(parent.row(), si.column());
idx = parent.sibling(parent.row(), sourceIndex.column());
} while (idx.isValid());
if (list.count() == 1)
return list[0];
return list.join(',');
return list.count() == 1 ? list.constFirst() : list.join(QLatin1Char(','));
}
class tst_QCompleter : public QObject
@ -154,15 +157,14 @@ private:
};
void setSourceModel(ModelType);
CsvCompleter *completer;
CsvCompleter *completer = nullptr;
QTreeWidget *treeWidget;
const int completionColumn;
const int columnCount;
const int completionColumn = 0;
const int columnCount = 3;
};
tst_QCompleter::tst_QCompleter() : completer(0), completionColumn(0), columnCount(3)
tst_QCompleter::tst_QCompleter() : treeWidget(new QTreeWidget)
{
treeWidget = new QTreeWidget;
treeWidget->move(100, 100);
treeWidget->setColumnCount(columnCount);
}
@ -184,11 +186,11 @@ void tst_QCompleter::setSourceModel(ModelType type)
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 5; j++) {
parent = new QTreeWidgetItem(treeWidget);
const QString text = QString::asprintf("%c%i", i == 0 ? 'P' : 'p', j);
const QString text = QLatin1Char(i == 0 ? 'P' : 'p') + QString::number(j);
parent->setText(completionColumn, text);
for (int k = 0; k < 5; k++) {
child = new QTreeWidgetItem(parent);
QString t = QString::asprintf("c%i", k) + text;
QString t = QLatin1Char('c') + QString::number(k) + text;
child->setText(completionColumn, t);
}
}
@ -203,11 +205,11 @@ void tst_QCompleter::setSourceModel(ModelType type)
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 2; j++) {
parent = new QTreeWidgetItem(treeWidget);
const QString text = QString::asprintf("%c%i", j == 0 ? 'P' : 'p', i);
const QString text = QLatin1Char(j == 0 ? 'P' : 'p') + QString::number(i);
parent->setText(completionColumn, text);
for (int k = 0; k < 5; k++) {
child = new QTreeWidgetItem(parent);
QString t = QString::asprintf("c%i", k) + text;
QString t = QLatin1Char('c') + QString::number(k) + text;
child->setText(completionColumn, t);
}
}
@ -229,7 +231,7 @@ void tst_QCompleter::setSourceModel(ModelType type)
case FILESYSTEM_MODEL:
completer->setCsvCompletion(false);
{
QFileSystemModel *m = new QFileSystemModel(completer);
auto m = new QFileSystemModel(completer);
m->setRootPath("/");
completer->setModel(m);
}
@ -237,13 +239,14 @@ void tst_QCompleter::setSourceModel(ModelType type)
break;
default:
qDebug() << "Invalid type";
break;
}
}
void tst_QCompleter::filter(bool assync)
{
QFETCH(QString, filterText);
QFETCH(QString, step);
QFETCH(const QString, step);
QFETCH(QString, completion);
QFETCH(QString, completionText);
@ -252,33 +255,43 @@ void tst_QCompleter::filter(bool assync)
return;
}
int times = 0;
retry:
int result = -1;
const int attempts = assync ? 10 : 1;
for (int times = 0; times < attempts; ++times) {
completer->setCompletionPrefix(filterText);
completer->setCompletionPrefix(filterText);
for (int i = 0; i < step.length(); i++) {
int row = completer->currentRow();
switch (step[i].toUpper().toLatin1()) {
case 'P': --row; break;
case 'N': ++row; break;
case 'L': row = completer->completionCount() - 1; break;
case 'F': row = 0; break;
default:
QFAIL(qPrintable(QString(
"Problem with 'step' value in test data: %1 (only P, N, L and F are allowed)."
).arg(step[i])));
for (QChar s : step) {
int row = completer->currentRow();
switch (s.toUpper().toLatin1()) {
case 'P':
--row;
break;
case 'N':
++row;
break;
case 'L':
row = completer->completionCount() - 1;
break;
case 'F':
row = 0;
break;
default:
QFAIL(qPrintable(QString(
"Problem with 'step' value in test data: %1 (only P, N, L and F are allowed)."
).arg(s)));
}
completer->setCurrentRow(row);
}
completer->setCurrentRow(row);
result = QString::compare(completer->currentCompletion(), completionText,
completer->caseSensitivity());
if (result == 0)
break;
if (assync)
QTest::qWait(50 * times);
}
int r = QString::compare(completer->currentCompletion(), completionText, completer->caseSensitivity());
if (assync && r && times < 10) {
times++;
QTest::qWait(50*times);
goto retry;
}
QVERIFY(!r);
QCOMPARE(result, 0);
}
// Testing get/set functions
@ -844,8 +857,7 @@ void tst_QCompleter::sortedEngineMapFromSource()
QModelIndex si1, si2, pi;
QAbstractItemModel *sourceModel = completer->model();
const QAbstractProxyModel *completionModel =
qobject_cast<const QAbstractProxyModel *>(completer->completionModel());
auto completionModel = qobject_cast<const QAbstractProxyModel *>(completer->completionModel());
// Fitering ON
// empty
@ -915,8 +927,7 @@ void tst_QCompleter::unsortedEngineMapFromSource()
QModelIndex si, si2, si3, pi;
QAbstractItemModel *sourceModel = completer->model();
const QAbstractProxyModel *completionModel =
qobject_cast<const QAbstractProxyModel *>(completer->completionModel());
auto completionModel = qobject_cast<const QAbstractProxyModel *>(completer->completionModel());
si = sourceModel->index(6, completionColumn); // "P3"
QCOMPARE(si.data().toString(), QLatin1String("P3"));
@ -997,8 +1008,7 @@ void tst_QCompleter::historySearch()
completer->setCaseSensitivity(Qt::CaseSensitive);
setSourceModel(HISTORY_MODEL);
const QAbstractProxyModel *completionModel =
qobject_cast<const QAbstractProxyModel *>(completer->completionModel());
auto completionModel = qobject_cast<const QAbstractProxyModel *>(completer->completionModel());
// "p3,c3p3" and "p2,c4p2" are added in the tree root
@ -1046,7 +1056,7 @@ void tst_QCompleter::setters()
{
delete completer;
completer = new CsvCompleter;
QVERIFY(completer->popup() != 0);
QVERIFY(completer->popup() != nullptr);
QPointer<QDirModel> dirModel = new QDirModel(completer);
QAbstractItemModel *oldModel = completer->model();
completer->setModel(dirModel);
@ -1055,28 +1065,28 @@ void tst_QCompleter::setters()
completer->setPopup(new QListView);
QCOMPARE(completer->popup()->model(), completer->completionModel());
completer->setModel(new QStringListModel(completer));
QVERIFY(dirModel == 0); // must have been deleted
QVERIFY(dirModel == nullptr); // must have been deleted
completer->setModel(0);
completer->setWidget(0);
completer->setModel(nullptr);
completer->setWidget(nullptr);
}
void tst_QCompleter::modelDeletion()
{
delete completer;
completer = new CsvCompleter;
QStringList list;
list << "item1" << "item2" << "item3";
QStringListModel *listModel = new QStringListModel(list);
const QStringList list = {"item1", "item2", "item3"};
std::unique_ptr<QStringListModel> listModel(new QStringListModel(list));
completer->setCompletionPrefix("i");
completer->setModel(listModel);
completer->setModel(listModel.get());
QCOMPARE(completer->completionCount(), 3);
QScopedPointer<QListView> view(new QListView);
std::unique_ptr<QListView> view(new QListView);
view->setWindowTitle(QLatin1String(QTest::currentTestFunction()));
view->setModel(completer->completionModel());
delete listModel;
listModel.reset();
view->move(200, 200);
view->show();
qApp->processEvents();
QCoreApplication::processEvents();
view.reset();
QCOMPARE(completer->completionCount(), 0);
QCOMPARE(completer->currentRow(), -1);
@ -1090,6 +1100,7 @@ void tst_QCompleter::multipleWidgets()
completer.setCompletionMode(QCompleter::InlineCompletion);
QWidget window;
window.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
window.move(200, 200);
window.show();
QApplication::setActiveWindow(&window);
@ -1098,7 +1109,7 @@ void tst_QCompleter::multipleWidgets()
QFocusEvent focusIn(QEvent::FocusIn);
QFocusEvent focusOut(QEvent::FocusOut);
QComboBox *comboBox = new QComboBox(&window);
auto comboBox = new QComboBox(&window);
comboBox->setEditable(true);
comboBox->setCompleter(&completer);
comboBox->setFocus();
@ -1114,7 +1125,7 @@ void tst_QCompleter::multipleWidgets()
comboBox->clearEditText();
QCOMPARE(comboBox->currentText(), QString("")); // combo box text must not change!
QLineEdit *lineEdit = new QLineEdit(&window);
auto lineEdit = new QLineEdit(&window);
lineEdit->setCompleter(&completer);
lineEdit->show();
lineEdit->setFocus();
@ -1129,29 +1140,28 @@ void tst_QCompleter::multipleWidgets()
void tst_QCompleter::focusIn()
{
QStringList list;
list << "item1" << "item2" << "item2";
QCompleter completer(list);
QCompleter completer({"item1", "item2", "item2"});
QWidget window;
window.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
window.move(200, 200);
window.show();
window.activateWindow();
QApplication::setActiveWindow(&window);
QVERIFY(QTest::qWaitForWindowActive(&window));
QComboBox *comboBox = new QComboBox(&window);
auto comboBox = new QComboBox(&window);
comboBox->setEditable(true);
comboBox->setCompleter(&completer);
comboBox->show();
comboBox->lineEdit()->setText("it");
QLineEdit *lineEdit = new QLineEdit(&window);
auto lineEdit = new QLineEdit(&window);
lineEdit->setCompleter(&completer);
lineEdit->setText("it");
lineEdit->show();
QLineEdit *lineEdit2 = new QLineEdit(&window); // has no completer!
auto lineEdit2 = new QLineEdit(&window); // has no completer!
lineEdit2->show();
comboBox->setFocus();
@ -1190,12 +1200,13 @@ void tst_QCompleter::dynamicSortOrder()
void tst_QCompleter::disabledItems()
{
QLineEdit lineEdit;
QStandardItemModel *model = new QStandardItemModel(&lineEdit);
lineEdit.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
auto model = new QStandardItemModel(&lineEdit);
QStandardItem *suggestions = new QStandardItem("suggestions");
suggestions->setEnabled(false);
model->appendRow(suggestions);
model->appendRow(new QStandardItem("suggestions Enabled"));
QCompleter *completer = new QCompleter(model, &lineEdit);
auto completer = new QCompleter(model, &lineEdit);
QSignalSpy spy(completer, QOverload<const QString &>::of(&QCompleter::activated));
lineEdit.setCompleter(completer);
lineEdit.move(200, 200);
@ -1206,42 +1217,40 @@ void tst_QCompleter::disabledItems()
QTest::keyPress(&lineEdit, Qt::Key_U);
QAbstractItemView *view = lineEdit.completer()->popup();
QVERIFY(view->isVisible());
QTest::mouseClick(view->viewport(), Qt::LeftButton, 0, view->visualRect(view->model()->index(0, 0)).center());
QTest::mouseClick(view->viewport(), Qt::LeftButton, {}, view->visualRect(view->model()->index(0, 0)).center());
QCOMPARE(spy.count(), 0);
QVERIFY(view->isVisible());
QTest::mouseClick(view->viewport(), Qt::LeftButton, 0, view->visualRect(view->model()->index(1, 0)).center());
QTest::mouseClick(view->viewport(), Qt::LeftButton, {}, view->visualRect(view->model()->index(1, 0)).center());
QCOMPARE(spy.count(), 1);
QVERIFY(!view->isVisible());
}
void tst_QCompleter::task178797_activatedOnReturn()
{
QStringList words;
words << "foobar1" << "foobar2";
QLineEdit ledit;
setFrameless(&ledit);
QCompleter *completer = new QCompleter(words, &ledit);
auto completer = new QCompleter({"foobar1", "foobar2"}, &ledit);
ledit.setCompleter(completer);
QSignalSpy spy(completer, QOverload<const QString &>::of(&QCompleter::activated));
QCOMPARE(spy.count(), 0);
ledit.move(200, 200);
ledit.show();
qApp->setActiveWindow(&ledit);
QApplication::setActiveWindow(&ledit);
QVERIFY(QTest::qWaitForWindowActive(&ledit));
QTest::keyClick(&ledit, Qt::Key_F);
qApp->processEvents();
QTRY_VERIFY(qApp->activePopupWidget());
QTest::keyClick(qApp->activePopupWidget(), Qt::Key_Down);
qApp->processEvents();
QTest::keyClick(qApp->activePopupWidget(), Qt::Key_Return);
qApp->processEvents();
QCoreApplication::processEvents();
QTRY_VERIFY(QApplication::activePopupWidget());
QTest::keyClick(QApplication::activePopupWidget(), Qt::Key_Down);
QCoreApplication::processEvents();
QTest::keyClick(QApplication::activePopupWidget(), Qt::Key_Return);
QCoreApplication::processEvents();
QCOMPARE(spy.count(), 1);
}
class task189564_StringListModel : public QStringListModel
{
const QString omitString;
Qt::ItemFlags flags(const QModelIndex &index) const
Qt::ItemFlags flags(const QModelIndex &index) const override
{
Qt::ItemFlags flags = Qt::ItemIsEnabled;
if (data(index, Qt::DisplayRole).toString() != omitString)
@ -1249,7 +1258,7 @@ class task189564_StringListModel : public QStringListModel
return flags;
}
public:
task189564_StringListModel(const QString &omitString, QObject *parent = 0)
explicit task189564_StringListModel(const QString &omitString, QObject *parent = nullptr)
: QStringListModel(parent)
, omitString(omitString)
{
@ -1315,8 +1324,7 @@ void tst_QCompleter::task246056_setCompletionPrefix()
QTest::keyPress(comboBox.completer()->popup(), Qt::Key_Down);
QTest::keyPress(comboBox.completer()->popup(), Qt::Key_Enter); // don't crash!
QCOMPARE(spy.count(), 1);
QList<QVariant> arguments = spy.at(0);
QModelIndex index = arguments.at(0).value<QModelIndex>();
const auto index = spy.at(0).constFirst().toModelIndex();
QVERIFY(!index.isValid());
}
@ -1331,7 +1339,7 @@ public:
completer->setWidget(this);
}
void keyPressEvent (QKeyEvent *e)
void keyPressEvent (QKeyEvent *e) override
{
completer->popup();
QTextEdit::keyPressEvent(e);
@ -1344,11 +1352,11 @@ class task250064_Widget : public QWidget
public:
task250064_Widget() : m_textEdit(new task250064_TextEdit)
{
QTabWidget *tabWidget = new QTabWidget;
auto tabWidget = new QTabWidget;
tabWidget->setFocusPolicy(Qt::ClickFocus);
tabWidget->addTab(m_textEdit, "untitled");
QVBoxLayout *layout = new QVBoxLayout(this);
auto layout = new QVBoxLayout(this);
layout->addWidget(tabWidget);
m_textEdit->setPlainText("bla bla bla");
@ -1357,7 +1365,7 @@ public:
void setCompletionModel()
{
m_textEdit->completer->setModel(0);
m_textEdit->completer->setModel(nullptr);
}
QTextEdit *textEdit() const { return m_textEdit; }
@ -1369,6 +1377,7 @@ private:
void tst_QCompleter::task250064_lostFocus()
{
task250064_Widget widget;
widget.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
widget.show();
QApplication::setActiveWindow(&widget);
QVERIFY(QTest::qWaitForWindowActive(&widget));
@ -1382,33 +1391,33 @@ void tst_QCompleter::task250064_lostFocus()
void tst_QCompleter::task253125_lineEditCompletion_data()
{
QTest::addColumn<QStringList>("list");
QTest::addColumn<int>("completionMode");
QTest::addColumn<QCompleter::CompletionMode>("completionMode");
QStringList list = QStringList()
<< "alpha" << "beta" << "gamma" << "delta" << "epsilon" << "zeta"
<< "eta" << "theta" << "iota" << "kappa" << "lambda" << "mu"
<< "nu" << "xi" << "omicron" << "pi" << "rho" << "sigma"
<< "tau" << "upsilon" << "phi" << "chi" << "psi" << "omega";
QStringList list = {"alpha", "beta", "gamma", "delta", "epsilon", "zeta",
"eta", "theta", "iota", "kappa", "lambda", "mu",
"nu", "xi", "omicron", "pi", "rho", "sigma",
"tau", "upsilon", "phi", "chi", "psi", "omega"};
QTest::newRow("Inline") << list << (int)QCompleter::InlineCompletion;
QTest::newRow("Filtered") << list << (int)QCompleter::PopupCompletion;
QTest::newRow("Unfiltered") << list << (int)QCompleter::UnfilteredPopupCompletion;
QTest::newRow("Inline") << list << QCompleter::InlineCompletion;
QTest::newRow("Filtered") << list << QCompleter::PopupCompletion;
QTest::newRow("Unfiltered") << list << QCompleter::UnfilteredPopupCompletion;
}
void tst_QCompleter::task253125_lineEditCompletion()
{
QFETCH(QStringList, list);
QFETCH(int, completionMode);
QFETCH(QCompleter::CompletionMode, completionMode);
QStringListModel *model = new QStringListModel;
model->setStringList(list);
std::unique_ptr<QStringListModel> model(new QStringListModel(list));
QCompleter *completer = new QCompleter(list);
completer->setModel(model);
completer->setCompletionMode((QCompleter::CompletionMode)completionMode);
std::unique_ptr<QCompleter> completer(new QCompleter(list));
completer->setModel(model.get());
completer->setCompletionMode(completionMode);
QLineEdit edit;
edit.setCompleter(completer);
edit.setWindowTitle(QLatin1String(QTest::currentTestFunction()) + QLatin1String("::")
+ QLatin1String(QTest::currentDataTag()));
edit.setCompleter(completer.get());
edit.move(200, 200);
edit.show();
edit.setFocus();
@ -1550,9 +1559,6 @@ void tst_QCompleter::task253125_lineEditCompletion()
QTest::keyClick(edit.completer()->popup(), Qt::Key_Enter);
QCOMPARE(edit.text(), QString("zz"));
delete completer;
delete model;
}
void tst_QCompleter::task247560_keyboardNavigation()
@ -1570,6 +1576,7 @@ void tst_QCompleter::task247560_keyboardNavigation()
completer.setCompletionColumn(1);
QLineEdit edit;
edit.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
edit.setCompleter(&completer);
edit.move(200, 200);
edit.show();
@ -1677,6 +1684,7 @@ void tst_QCompleter::QTBUG_14292_filesystem()
QVERIFY(fs.createDirectory(QLatin1String(testDir2)));
QLineEdit edit;
edit.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
QCompleter comp;
comp.setModel(&model);
edit.setCompleter(&comp);
@ -1739,16 +1747,14 @@ void tst_QCompleter::QTBUG_14292_filesystem()
void tst_QCompleter::QTBUG_52028_tabAutoCompletes()
{
QStringList words;
words << "foobar1" << "foobar2" << "hux";
QWidget w;
w.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
w.setLayout(new QVBoxLayout);
QComboBox cbox;
cbox.setEditable(true);
cbox.setInsertPolicy(QComboBox::NoInsert);
cbox.addItems(words);
cbox.addItems({"foobar1", "foobar2", "hux"});
cbox.completer()->setCaseSensitivity(Qt::CaseInsensitive);
cbox.completer()->setCompletionMode(QCompleter::PopupCompletion);
@ -1756,8 +1762,8 @@ void tst_QCompleter::QTBUG_52028_tabAutoCompletes()
w.layout()->addWidget(&cbox);
// Adding a line edit is a good reason for tab to do something unrelated
QLineEdit le;
w.layout()->addWidget(&le);
auto le = new QLineEdit;
w.layout()->addWidget(le);
const auto pos = QApplication::desktop()->availableGeometry(&w).topLeft() + QPoint(200,200);
w.move(pos);
@ -1778,30 +1784,27 @@ void tst_QCompleter::QTBUG_52028_tabAutoCompletes()
QEXPECT_FAIL("", "QTBUG-52028 will not be fixed today.", Abort);
QCOMPARE(cbox.currentText(), QLatin1String("hux"));
QCOMPARE(activatedSpy.count(), 0);
QVERIFY(!le.hasFocus());
QVERIFY(!le->hasFocus());
}
void tst_QCompleter::QTBUG_51889_activatedSentTwice()
{
QStringList words;
words << "foobar1" << "foobar2" << "bar" <<"hux";
QWidget w;
w.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
w.setLayout(new QVBoxLayout);
QComboBox cbox;
setFrameless(&cbox);
cbox.setEditable(true);
cbox.setInsertPolicy(QComboBox::NoInsert);
cbox.addItems(words);
cbox.addItems({"foobar1", "foobar2", "bar", "hux"});
cbox.completer()->setCaseSensitivity(Qt::CaseInsensitive);
cbox.completer()->setCompletionMode(QCompleter::PopupCompletion);
w.layout()->addWidget(&cbox);
QLineEdit le;
w.layout()->addWidget(&le);
w.layout()->addWidget(new QLineEdit);
const auto pos = QApplication::desktop()->availableGeometry(&w).topLeft() + QPoint(200,200);
w.move(pos);