1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the test suite of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29
30#include <QtTest/QtTest>
31
32
33#include "qlabel.h"
34#include <qapplication.h>
35#include <qboxlayout.h>
36#include <qlabel.h>
37#include <qlineedit.h>
38#include <qmovie.h>
39#include <qpicture.h>
40#include <qmessagebox.h>
41#include <private/qlabel_p.h>
42
43class Widget : public QWidget
44{
45 Q_OBJECT
46public:
47 QList<QEvent::Type> events;
48
49protected:
50 bool event(QEvent *ev) override {
51 events.append(t: ev->type());
52 return QWidget::event(event: ev);
53 }
54
55};
56
57class tst_QLabel : public QObject
58{
59 Q_OBJECT
60
61private Q_SLOTS:
62 void initTestCase();
63 void cleanupTestCase();
64 void init();
65 void cleanup();
66
67 void getSetCheck();
68 void setText_data();
69 void setText();
70 void setTextFormat();
71#ifndef Q_OS_MAC
72 void setBuddy();
73#endif
74 void setNum();
75 void clear();
76 void wordWrap();
77 void eventPropagation_data();
78 void eventPropagation();
79 void focusPolicy();
80
81 void task190318_sizes();
82
83 void sizeHint();
84
85 void task226479_movieResize();
86 void emptyPixmap();
87
88 void unicodeText_data();
89 void unicodeText();
90
91 void mnemonic_data();
92 void mnemonic();
93 void selection();
94
95#ifndef QT_NO_CONTEXTMENU
96 void taskQTBUG_7902_contextMenuCrash();
97#endif
98
99 void taskQTBUG_48157_dprPixmap();
100 void taskQTBUG_48157_dprMovie();
101
102private:
103 QLabel *testWidget;
104 QPointer<Widget> test_box;
105 QPointer<QLabel> test_label;
106};
107
108// Testing get/set functions
109void tst_QLabel::getSetCheck()
110{
111 QLabel obj1;
112 // bool QLabel::wordWrap()
113 // void QLabel::setWordWrap(bool)
114 obj1.setWordWrap(false);
115 QCOMPARE(false, obj1.wordWrap());
116 obj1.setWordWrap(true);
117 QCOMPARE(true, obj1.wordWrap());
118
119 // QWidget * QLabel::buddy()
120 // void QLabel::setBuddy(QWidget *)
121 QWidget *var2 = new QWidget();
122 obj1.setBuddy(var2);
123 QCOMPARE(var2, obj1.buddy());
124 obj1.setBuddy((QWidget *)0);
125 QCOMPARE((QWidget *)0, obj1.buddy());
126 delete var2;
127
128 // QMovie * QLabel::movie()
129 // void QLabel::setMovie(QMovie *)
130 QMovie *var3 = new QMovie;
131 obj1.setMovie(var3);
132 QCOMPARE(var3, obj1.movie());
133 obj1.setMovie((QMovie *)0);
134 QCOMPARE((QMovie *)0, obj1.movie());
135 delete var3;
136}
137
138void tst_QLabel::initTestCase()
139{
140 // Create the test class
141 testWidget = new QLabel(0);
142 testWidget->resize( w: 200, h: 200 );
143 testWidget->show();
144}
145
146void tst_QLabel::cleanupTestCase()
147{
148 delete testWidget;
149 testWidget = 0;
150 delete test_box;
151}
152
153void tst_QLabel::init()
154{
155 testWidget->setTextFormat( Qt::AutoText );
156 testWidget->setBuddy( 0 );
157 testWidget->setIndent( 0 );
158 testWidget->setAlignment( Qt::AlignLeft | Qt::AlignVCenter );
159 testWidget->setScaledContents( false );
160}
161
162void tst_QLabel::cleanup()
163{
164 if (QTest::currentTestFunction() == QLatin1String("setBuddy")) {
165 testWidget->show();
166
167 delete test_box; // this should delete tst_labl and test_edit as well.
168 }
169}
170
171// Set buddy doesn't make much sense on OS X
172#ifndef Q_OS_MAC
173void tst_QLabel::setBuddy()
174{
175 testWidget->hide();
176
177 test_box = new Widget;
178 test_label= new QLabel( test_box );
179 test_label->setText( "&Test with a buddy" );
180 QWidget *test_edit = new QLineEdit( test_box );
181 QWidget *test_edit2 = new QLineEdit( test_box );
182 QVBoxLayout *layout = new QVBoxLayout(test_box);
183 layout->addWidget(test_label);
184 layout->addWidget(test_edit);
185 layout->addWidget(test_edit2);
186 test_box->show();
187 qApp->setActiveWindow(test_box);
188 QVERIFY(test_box->isActiveWindow());
189
190 test_label->setBuddy( test_edit );
191 test_label->setFocus();
192 QVERIFY( !test_edit->hasFocus() );
193 QTest::keyClick( widget: test_box, key: 't', modifier: Qt::AltModifier );
194 QVERIFY( test_edit->hasFocus() );
195
196 // Setting a new buddy should disconnect the old one's destroyed() signal
197 test_label->setBuddy(test_edit2);
198 delete test_edit;
199 QCOMPARE(test_label->buddy(), test_edit2);
200
201 // And deleting our own buddy should disconnect and not crash
202 delete test_edit2;
203 QTest::keyClick(widget: test_box, key: 't', modifier: Qt::AltModifier );
204
205 delete test_box;
206}
207#endif
208
209void tst_QLabel::setText_data()
210{
211 QTest::addColumn<QString>(name: "txt");
212 QTest::addColumn<QString>(name: "font");
213
214 QString prefix = "";
215#ifdef Q_OS_WIN32
216 prefix = "win32_";
217#endif
218
219 QTest::newRow( dataTag: QString(prefix + "data0").toLatin1() ) << QString("This is a single line") << QString("Helvetica");
220 QTest::newRow( dataTag: QString(prefix + "data1").toLatin1() ) << QString("This is the first line\nThis is the second line") << QString("Courier");
221 QTest::newRow( dataTag: QString(prefix + "data2").toLatin1() ) << QString("This is the first line\nThis is the second line\nThis is the third line") << QString("Helvetica");
222 QTest::newRow( dataTag: QString(prefix + "data3").toLatin1() ) << QString("This is <b>bold</b> richtext") << QString("Courier");
223 QTest::newRow( dataTag: QString(prefix + "data4").toLatin1() ) << QString("I Have a &shortcut") << QString("Helvetica");
224}
225
226void tst_QLabel::setText()
227{
228 QFETCH( QString, txt );
229 QFETCH( QString, font );
230 QFont f( font, 8 );
231 testWidget->setFont( f );
232 testWidget->setText( txt );
233 QCOMPARE( testWidget->text(), txt );
234}
235
236void tst_QLabel::setTextFormat()
237{
238 // lets' start with the simple stuff...
239 testWidget->setTextFormat( Qt::PlainText );
240 QVERIFY( testWidget->textFormat() == Qt::PlainText );
241
242 testWidget->setTextFormat( Qt::RichText );
243 QVERIFY( testWidget->textFormat() == Qt::RichText );
244
245 testWidget->setTextFormat( Qt::AutoText );
246 QVERIFY( testWidget->textFormat() == Qt::AutoText );
247}
248
249void tst_QLabel::setNum()
250{
251 testWidget->setText( "This is a text" );
252 testWidget->setNum( 12 );
253 QCOMPARE( testWidget->text(), QString("12") );
254 testWidget->setNum( 12.345 );
255 QCOMPARE( testWidget->text(), QString("12.345") );
256}
257
258void tst_QLabel::clear()
259{
260 const QString TEXT = "blah blah";
261 testWidget->setText(TEXT);
262 QCOMPARE(testWidget->text(), TEXT);
263 testWidget->clear();
264 QVERIFY(testWidget->text().isEmpty());
265}
266
267void tst_QLabel::wordWrap()
268{
269 QLabel label;
270
271 QVERIFY(!label.wordWrap());
272
273 label.setText("Plain Text");
274 QVERIFY(!label.wordWrap());
275
276 label.setText("<b>rich text</b>");
277 QVERIFY(!label.wordWrap());
278
279 label.setWordWrap(false);
280 label.setText("<b>rich text</b>");
281 QVERIFY(!label.wordWrap());
282}
283
284void tst_QLabel::eventPropagation_data()
285{
286 QTest::addColumn<QString>(name: "text");
287 QTest::addColumn<int>(name: "textInteractionFlags");
288 QTest::addColumn<int>(name: "focusPolicy");
289 QTest::addColumn<bool>(name: "propagation");
290
291 QTest::newRow(dataTag: "plain text1") << QString("plain text") << int(Qt::LinksAccessibleByMouse) << int(Qt::NoFocus) << true;
292 QTest::newRow(dataTag: "plain text2") << QString("plain text") << (int)Qt::TextSelectableByKeyboard << (int)Qt::ClickFocus << true;
293 QTest::newRow(dataTag: "plain text3") << QString("plain text") << (int)Qt::TextSelectableByMouse << (int)Qt::ClickFocus << false;
294 QTest::newRow(dataTag: "plain text4") << QString("plain text") << (int)Qt::NoTextInteraction << (int)Qt::NoFocus << true;
295 QTest::newRow(dataTag: "rich text1") << QString("<b>rich text</b>") << (int)Qt::LinksAccessibleByMouse << (int)Qt::NoFocus << true;
296 QTest::newRow(dataTag: "rich text2") << QString("<b>rich text</b>") << (int)Qt::TextSelectableByKeyboard << (int)Qt::ClickFocus << true;
297 QTest::newRow(dataTag: "rich text3") << QString("<b>rich text</b>") << (int)Qt::TextSelectableByMouse << (int)Qt::ClickFocus << false;
298 QTest::newRow(dataTag: "rich text4") << QString("<b>rich text</b>") << (int)Qt::NoTextInteraction << (int)Qt::NoFocus << true;
299 QTest::newRow(dataTag: "rich text5") << QString("<b>rich text</b>") << (int)Qt::LinksAccessibleByKeyboard << (int)Qt::StrongFocus << true;
300
301 if (!test_box)
302 test_box = new Widget;
303 if (!test_label)
304 test_label = new QLabel(test_box);
305}
306
307void tst_QLabel::eventPropagation()
308{
309 QFETCH(QString, text);
310 QFETCH(int, textInteractionFlags);
311 QFETCH(int, focusPolicy);
312 QFETCH(bool, propagation);
313
314 // plain text (accepts mouse event _only_ when label selectable by mouse)
315 test_label->setText(text);
316 test_box->events.clear();
317 test_label->setTextInteractionFlags(Qt::TextInteractionFlags(textInteractionFlags));
318 QCOMPARE(int(test_label->focusPolicy()), focusPolicy);
319 QTest::mousePress(widget: test_label, button: Qt::LeftButton);
320 QVERIFY(test_box->events.contains(QEvent::MouseButtonPress) == propagation); // should have propagated!
321}
322
323void tst_QLabel::focusPolicy()
324{
325 delete test_label;
326 test_label = new QLabel;
327 QCOMPARE(test_label->focusPolicy(), Qt::NoFocus); // default
328 test_label->setFocusPolicy(Qt::StrongFocus);
329 test_label->setText("Whatever"); // setting text should not change the focus policy
330 QCOMPARE(test_label->focusPolicy(), Qt::StrongFocus);
331 test_label->setTextInteractionFlags(Qt::TextSelectableByKeyboard); // this should
332 QCOMPARE(test_label->focusPolicy(), Qt::ClickFocus);
333 test_label->setFocusPolicy(Qt::StrongFocus);
334 test_label->setText("Whatever"); // setting text should not change the focus policy
335 QCOMPARE(test_label->focusPolicy(), Qt::StrongFocus);
336 test_label->setTextInteractionFlags(Qt::NoTextInteraction);
337 QCOMPARE(test_label->focusPolicy(), Qt::NoFocus);
338 test_label->setFocusPolicy(Qt::StrongFocus);
339 test_label->setTextInteractionFlags(Qt::NoTextInteraction);
340 QCOMPARE(test_label->focusPolicy(), Qt::StrongFocus); // is not touched since value didn't change
341 delete test_label;
342}
343
344void tst_QLabel::task190318_sizes()
345{
346 QLabel label(" ");
347 QSize ms(500,600);
348 label.setMinimumSize(ms);
349 QCOMPARE(label.minimumSize(), ms);
350 QCOMPARE(label.sizeHint(), ms);
351 QCOMPARE(label.minimumSizeHint(), ms);
352}
353
354void tst_QLabel::sizeHint()
355{
356 QLabel label(QLatin1String("Test"));
357 label.setIndent(0);
358 label.setMargin(0);
359 label.setContentsMargins(left: 0, top: 0, right: 0, bottom: 0);
360 label.setAlignment(Qt::AlignVCenter);
361 int h = label.sizeHint().height();
362
363 QLabel l1(QLatin1String("Test"));
364 l1.setIndent(0);
365 l1.setMargin(0);
366 l1.setContentsMargins(left: 0, top: 0, right: 0, bottom: 0);
367 l1.setAlignment(Qt::AlignVCenter);
368 l1.setTextInteractionFlags(Qt::TextSelectableByMouse); // will now use qtextcontrol
369 int h1 = l1.sizeHint().height();
370 QCOMPARE(h1, h);
371
372}
373
374void tst_QLabel::task226479_movieResize()
375{
376 class Label : public QLabel {
377 protected:
378 void paintEvent(QPaintEvent *e)
379 {
380 paintedRegion += e->region();
381 QLabel::paintEvent(e);
382 }
383
384 public:
385 QRegion paintedRegion;
386 };
387
388 Label label;
389 label.resize(w: 350,h: 350);
390 label.show();
391 QMovie *movie = new QMovie( &label );
392 label.setMovie(movie);
393 QVERIFY(QTest::qWaitForWindowExposed(&label));
394 movie->setFileName(QFINDTESTDATA("red.png"));
395 movie->start();
396 QTest::qWait(ms: 50);
397 movie->stop();
398 label.paintedRegion = QRegion();
399 movie->setFileName(QFINDTESTDATA("green.png"));
400 movie->start();
401
402 QTRY_COMPARE(label.paintedRegion , QRegion(label.rect()) );
403}
404
405void tst_QLabel::emptyPixmap()
406{
407 //task 197919
408 QLabel label1, label2, label3, label4;
409 label2.setPixmap(QPixmap("/tmp/idonotexist"));
410 QMovie movie;
411 label3.setMovie(&movie);
412 label4.setPicture(QPicture());
413 QCOMPARE(label1.sizeHint(), label2.sizeHint());
414 QCOMPARE(label1.sizeHint(), label3.sizeHint());
415 QCOMPARE(label1.sizeHint(), label4.sizeHint());
416}
417
418/**
419 Test for QTBUG-4848 - unicode data corrupting QLabel display
420*/
421void tst_QLabel::unicodeText_data()
422{
423 QTest::addColumn<QString>(name: "text");
424 QTest::addColumn<QString>(name: "languageName");
425
426 /*
427 The "glass" phrase in Thai was the initial report for bug QTBUG-4848, was
428 originally found on http://www.columbia.edu/kermit/utf8.html.
429
430 The phrase is from an internet tradition regarding a striking phrase
431 that is translated into many different languages. The utf8 strings
432 below were generated by using http://translate.google.com.
433
434 The glass phrase in Thai contains the ้ว character which manifests bug
435 QTBUG-4848
436
437 The last long phrase is an excerpt from Churchills "on the beaches"
438 speech, also translated using http://translate.google.com.
439 */
440
441 QTest::newRow(dataTag: "english") << QString::fromUtf8(str: "I can eat glass and it doesn't hurt me.") << QString("english");
442 QTest::newRow(dataTag: "thai") << QString::fromUtf8(str: "ฉันจะกินแก้วและไม่เจ็บฉัน") << QString("thai");
443 QTest::newRow(dataTag: "chinese") << QString::fromUtf8(str: "我可以吃玻璃,并没有伤害我。") << QString("chinese");
444 QTest::newRow(dataTag: "arabic") << QString::fromUtf8(str: "أستطيع أكل الزجاج ، وأنه لا يؤذيني.") << QString("arabic");
445 QTest::newRow(dataTag: "russian") << QString::fromUtf8(str: "Я могу есть стекло, и не больно.") << QString("russian");
446 QTest::newRow(dataTag: "korean") << QString::fromUtf8(str: "유리를 먹을 수있는, 그리고 그게 날 다치게하지 않습니다.") << QString("korean");
447 QTest::newRow(dataTag: "greek") << QString::fromUtf8(str: "Μπορώ να φάτε γυαλί και δεν μου κάνει κακό.") << QString("greek");
448 QTest::newRow(dataTag: "german") << QString::fromUtf8(str: "Ich kann Glas essen und es macht mich nicht heiß.") << QString("german");
449
450 QTest::newRow(dataTag: "thai_long") << QString::fromUtf8(str: "เราจะต่อสู้ในทะเลและมหาสมุทร. เราจะต่อสู้ด้วยความมั่นใจเติบโตและความเจริญเติบโตในอากาศเราจะปกป้องเกาะของเราค่าใช้จ่ายใดๆอาจ."
451 "เราจะต่อสู้บนชายหาดเราจะต่อสู้ในบริเวณเชื่อมโยงไปถึงเราจะต่อสู้ในช่องและในถนนที่เราจะต่อสู้ในภูเขานั้นเราจะไม่ยอม.")
452 << QString("thai_long");
453}
454
455void tst_QLabel::unicodeText()
456{
457 const QString testDataPath("testdata/unicodeText");
458 QFETCH(QString, text);
459 QFETCH(QString, languageName);
460 QFrame frame;
461 QVBoxLayout *layout = new QVBoxLayout();
462 QLabel *label = new QLabel(text, &frame);
463 layout->addWidget(label);
464 layout->setContentsMargins(left: 8, top: 8, right: 8, bottom: 8);
465 frame.setLayout(layout);
466 frame.show();
467 QVERIFY(QTest::qWaitForWindowExposed(&frame));
468 QVERIFY(frame.isVisible()); // was successfully sized and shown
469 testWidget->show();
470}
471
472void tst_QLabel::mnemonic_data()
473{
474 QTest::addColumn<QString>(name: "text");
475 QTest::addColumn<QString>(name: "expectedDocText");
476 QTest::addColumn<QString>(name: "expectedShortcutCursor");
477
478 QTest::newRow(dataTag: "1") << QString("Normal") << QString("Normal") << QString();
479 QTest::newRow(dataTag: "2") << QString("&Simple") << QString("Simple") << QString("S");
480 QTest::newRow(dataTag: "3") << QString("Also &simple") << QString("Also simple") << QString("s");
481 QTest::newRow(dataTag: "4") << QString("&&With &Double &&amp;") << QString("&With Double &amp;") << QString("D");
482 QTest::newRow(dataTag: "5") << QString("Hep&&Hop") << QString("Hep&Hop") << QString("");
483 QTest::newRow(dataTag: "6") << QString("Hep&&&Hop") << QString("Hep&Hop") << QString("H");
484}
485
486
487void tst_QLabel::mnemonic()
488{
489 // this test that the mnemonics appears correctly when the label has a text control.
490
491 QFETCH(QString, text);
492 QFETCH(QString, expectedDocText);
493 QFETCH(QString, expectedShortcutCursor);
494
495 QWidget w;
496 QHBoxLayout *hbox = new QHBoxLayout;
497 QLabel *lab = new QLabel(text);
498 //lab->setText("plop &plop");
499 QLineEdit *lineedit = new QLineEdit;
500 lab->setBuddy(lineedit);
501 lab->setTextInteractionFlags(Qt::TextSelectableByMouse);
502
503 hbox->addWidget(lab);
504 hbox->addWidget(lineedit);
505 hbox->addWidget(new QLineEdit);
506 w.setLayout(hbox);
507 w.show();
508 QVERIFY(QTest::qWaitForWindowExposed(&w));
509
510 QLabelPrivate *d = static_cast<QLabelPrivate *>(QObjectPrivate::get(o: lab));
511 QVERIFY(d->control);
512 QCOMPARE(d->control->document()->toPlainText(), expectedDocText);
513 QCOMPARE(d->shortcutCursor.selectedText(), expectedShortcutCursor);
514}
515
516void tst_QLabel::selection()
517{
518 QLabel label;
519 label.setText("Hello world");
520
521 label.setTextInteractionFlags(Qt::TextSelectableByMouse);
522
523 QVERIFY(!label.hasSelectedText());
524 QCOMPARE(label.selectedText(), QString());
525 QCOMPARE(label.selectionStart(), -1);
526
527 label.setSelection(0, 4);
528 QVERIFY(label.hasSelectedText());
529 QCOMPARE(label.selectedText(), QString::fromLatin1("Hell"));
530 QCOMPARE(label.selectionStart(), 0);
531
532 label.setSelection(6, 5);
533 QVERIFY(label.hasSelectedText());
534 QCOMPARE(label.selectedText(), QString::fromLatin1("world"));
535 QCOMPARE(label.selectionStart(), 6);
536}
537
538#ifndef QT_NO_CONTEXTMENU
539void tst_QLabel::taskQTBUG_7902_contextMenuCrash()
540{
541 QLabel *w = new QLabel("Test or crash?");
542 w->setTextInteractionFlags(Qt::TextSelectableByMouse);
543 w->show();
544 QVERIFY(QTest::qWaitForWindowExposed(w));
545
546 QTimer ti;
547 w->connect(sender: &ti, SIGNAL(timeout()), receiver: w, SLOT(deleteLater()));
548 ti.start(msec: 300);
549
550 QContextMenuEvent *cme = new QContextMenuEvent(QContextMenuEvent::Mouse, w->rect().center());
551 qApp->postEvent(receiver: w, event: cme);
552
553 QTest::qWait(ms: 350);
554 // No crash, it's allright.
555}
556#endif
557
558void tst_QLabel::taskQTBUG_48157_dprPixmap()
559{
560 QLabel label;
561 QPixmap pixmap;
562 pixmap.load(QFINDTESTDATA(QStringLiteral("red@2x.png")));
563 QCOMPARE(pixmap.devicePixelRatio(), 2.0);
564 label.setPixmap(pixmap);
565 QCOMPARE(label.sizeHint(), pixmap.rect().size() / pixmap.devicePixelRatio());
566}
567
568void tst_QLabel::taskQTBUG_48157_dprMovie()
569{
570 QLabel label;
571 QMovie movie;
572 movie.setFileName(QFINDTESTDATA(QStringLiteral("red@2x.png")));
573 movie.start();
574 QCOMPARE(movie.currentPixmap().devicePixelRatio(), 2.0);
575 label.setMovie(&movie);
576 QCOMPARE(label.sizeHint(), movie.currentPixmap().size() / movie.currentPixmap().devicePixelRatio());
577}
578
579QTEST_MAIN(tst_QLabel)
580#include "tst_qlabel.moc"
581

source code of qtbase/tests/auto/widgets/widgets/qlabel/tst_qlabel.cpp