From c1c52b5cd22655999a9abc6bce709e15b598d2c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Mon, 3 Aug 2009 14:31:10 +0200 Subject: Preserved fill rule for perspective mapped strokes in raster engine. Task-number: 254407 Reviewed-by: Gunnar --- src/gui/painting/qoutlinemapper.cpp | 2 ++ src/gui/painting/qtransform.cpp | 1 + 2 files changed, 3 insertions(+) diff --git a/src/gui/painting/qoutlinemapper.cpp b/src/gui/painting/qoutlinemapper.cpp index 401fad92f..d2943788f 100644 --- a/src/gui/painting/qoutlinemapper.cpp +++ b/src/gui/painting/qoutlinemapper.cpp @@ -225,6 +225,8 @@ void QOutlineMapper::endOutline() } } path = QTransform(m_m11, m_m12, m_m13, m_m21, m_m22, m_m23, m_dx, m_dy, m_m33).map(path); + if (!(m_outline.flags & QT_FT_OUTLINE_EVEN_ODD_FILL)) + path.setFillRule(Qt::WindingFill); uint old_txop = m_txop; m_txop = QTransform::TxNone; if (path.isEmpty()) diff --git a/src/gui/painting/qtransform.cpp b/src/gui/painting/qtransform.cpp index dcb894725..6a3392848 100644 --- a/src/gui/painting/qtransform.cpp +++ b/src/gui/painting/qtransform.cpp @@ -1459,6 +1459,7 @@ static QPainterPath mapProjective(const QTransform &transform, const QPainterPat if (path.elementCount() > 0 && lastMoveTo != last) lineTo_clipped(result, transform, last, lastMoveTo, needsMoveTo, false); + result.setFillRule(path.fillRule()); return result; } -- cgit v1.2.3 From c05a595cde1327edea3a72c6fa13d2351c02805d Mon Sep 17 00:00:00 2001 From: Jason McDonald Date: Tue, 4 Aug 2009 13:38:51 +1000 Subject: Fix obsolete license headers Reviewed-by: Trust Me --- doc/src/examples/frozencolumn.qdoc | 4 ++-- doc/src/qsqldatatype-table.qdoc | 4 ++-- examples/itemviews/frozencolumn/freezetablewidget.cpp | 4 ++-- examples/itemviews/frozencolumn/freezetablewidget.h | 5 ++--- examples/itemviews/frozencolumn/main.cpp | 5 ++--- 5 files changed, 10 insertions(+), 12 deletions(-) diff --git a/doc/src/examples/frozencolumn.qdoc b/doc/src/examples/frozencolumn.qdoc index e5a3b595f..9d89478a5 100644 --- a/doc/src/examples/frozencolumn.qdoc +++ b/doc/src/examples/frozencolumn.qdoc @@ -1,7 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) +** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the documentation of the Qt Toolkit. ** @@ -34,7 +34,7 @@ ** met: http://www.gnu.org/copyleft/gpl.html. ** ** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. +** contact the sales department at http://www.qtsoftware.com/contact. ** $QT_END_LICENSE$ ** ****************************************************************************/ diff --git a/doc/src/qsqldatatype-table.qdoc b/doc/src/qsqldatatype-table.qdoc index 5ab641369..60c9dcf47 100644 --- a/doc/src/qsqldatatype-table.qdoc +++ b/doc/src/qsqldatatype-table.qdoc @@ -1,7 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) +** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the documentation of the Qt Toolkit. ** @@ -34,7 +34,7 @@ ** met: http://www.gnu.org/copyleft/gpl.html. ** ** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. +** contact the sales department at http://www.qtsoftware.com/contact. ** $QT_END_LICENSE$ ** ****************************************************************************/ diff --git a/examples/itemviews/frozencolumn/freezetablewidget.cpp b/examples/itemviews/frozencolumn/freezetablewidget.cpp index 7a9a8dfa3..432676341 100644 --- a/examples/itemviews/frozencolumn/freezetablewidget.cpp +++ b/examples/itemviews/frozencolumn/freezetablewidget.cpp @@ -1,7 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) +** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the examples of the Qt Toolkit. ** @@ -34,7 +34,7 @@ ** met: http://www.gnu.org/copyleft/gpl.html. ** ** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. +** contact the sales department at http://www.qtsoftware.com/contact. ** $QT_END_LICENSE$ ** ****************************************************************************/ diff --git a/examples/itemviews/frozencolumn/freezetablewidget.h b/examples/itemviews/frozencolumn/freezetablewidget.h index 2abae47d2..f7b8e432e 100644 --- a/examples/itemviews/frozencolumn/freezetablewidget.h +++ b/examples/itemviews/frozencolumn/freezetablewidget.h @@ -1,7 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) +** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the examples of the Qt Toolkit. ** @@ -34,12 +34,11 @@ ** met: http://www.gnu.org/copyleft/gpl.html. ** ** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. +** contact the sales department at http://www.qtsoftware.com/contact. ** $QT_END_LICENSE$ ** ****************************************************************************/ - #ifndef FREEZETABLEWIDGET_H #define FREEZETABLEWIDGET_H diff --git a/examples/itemviews/frozencolumn/main.cpp b/examples/itemviews/frozencolumn/main.cpp index fdefd7365..9f6a63743 100644 --- a/examples/itemviews/frozencolumn/main.cpp +++ b/examples/itemviews/frozencolumn/main.cpp @@ -1,7 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) +** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the examples of the Qt Toolkit. ** @@ -34,12 +34,11 @@ ** met: http://www.gnu.org/copyleft/gpl.html. ** ** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. +** contact the sales department at http://www.qtsoftware.com/contact. ** $QT_END_LICENSE$ ** ****************************************************************************/ - #include #include #include -- cgit v1.2.3 From e83f77cbc22be5e37de1e7a8ec2c55e66f7b51d9 Mon Sep 17 00:00:00 2001 From: Morten Sorvig Date: Tue, 4 Aug 2009 09:31:56 +0200 Subject: Build on snow leopard. Don't error out when building qmake, just let it build a 64-bit binary (even for carbon) RebBy: Richard Moe Gustavsen --- src/corelib/global/qglobal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h index f650bd25f..e05c05d85 100644 --- a/src/corelib/global/qglobal.h +++ b/src/corelib/global/qglobal.h @@ -279,7 +279,7 @@ namespace QT_NAMESPACE {} # endif #endif -#if defined(Q_OS_MAC64) && !defined(QT_MAC_USE_COCOA) +#if defined(Q_OS_MAC64) && !defined(QT_MAC_USE_COCOA) && !defined(QT_BUILD_QMAKE) #error "You are building a 64-bit application, but using a 32-bit version of Qt. Check your build configuration." #endif -- cgit v1.2.3 From 232569c52844a4f661fe55001015ad5da5097ce7 Mon Sep 17 00:00:00 2001 From: Alexis Menard Date: Tue, 4 Aug 2009 13:05:05 +0200 Subject: Fix ancestor flags that are not correctly update when reparenting. updateAncestorFlags was not reseting the flags if you change the parent that have for instance itemsClipChildrenToShape to a new one that doesn't have that flag. Task-number:258956 Reviewed-by:bnilsen --- src/gui/graphicsview/qgraphicsitem.cpp | 23 ++++++++++++----------- tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp | 16 ++++++++++++++++ 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index aa3798120..7b650d27a 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -638,18 +638,19 @@ void QGraphicsItemPrivate::updateAncestorFlag(QGraphicsItem::GraphicsItemFlag ch return; } - // Inherit the enabled-state from our parents. - if ((parent && ((parent->d_ptr->ancestorFlags & flag) - || (int(parent->d_ptr->flags & childFlag) == childFlag) - || (childFlag == -1 && parent->d_ptr->handlesChildEvents)))) { - enabled = true; - ancestorFlags |= flag; - } - - // Top-level root items don't have any ancestors, so there are no - // ancestor flags either. - if (!parent) + if (parent) { + // Inherit the enabled-state from our parents. + if ((parent->d_ptr->ancestorFlags & flag) || (int(parent->d_ptr->flags & childFlag) == childFlag) || (childFlag == -1 && parent->d_ptr->handlesChildEvents)) { + enabled = true; + ancestorFlags |= flag; + } else { + ancestorFlags &= ~flag; + } + } else { + // Top-level root items don't have any ancestors, so there are no + // ancestor flags either. ancestorFlags = 0; + } } else { // Don't set or propagate the ancestor flag if it's already correct. if (((ancestorFlags & flag) && enabled) || (!(ancestorFlags & flag) && !enabled)) diff --git a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp index 90c463698..ded8aca44 100644 --- a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp +++ b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp @@ -665,6 +665,22 @@ void tst_QGraphicsItem::flags() QApplication::sendEvent(&scene, &event5); QCOMPARE(item->pos(), QPointF(10, 10)); } + { + QGraphicsItem* clippingParent = new QGraphicsRectItem; + clippingParent->setFlag(QGraphicsItem::ItemClipsChildrenToShape, true); + + QGraphicsItem* nonClippingParent = new QGraphicsRectItem; + nonClippingParent->setFlag(QGraphicsItem::ItemClipsChildrenToShape, false); + + QGraphicsItem* child = new QGraphicsRectItem(nonClippingParent); + QVERIFY(!child->isClipped()); + + child->setParentItem(clippingParent); + QVERIFY(child->isClipped()); + + child->setParentItem(nonClippingParent); + QVERIFY(!child->isClipped()); + } } void tst_QGraphicsItem::toolTip() -- cgit v1.2.3 From 2764dc0a0f4f8f6c87e716817ae99a7b57cdd23e Mon Sep 17 00:00:00 2001 From: Alexis Menard Date: Tue, 4 Aug 2009 14:13:57 +0200 Subject: Fix indentation. Reviewed-by:TrustMe --- src/gui/graphicsview/qgraphicsitem.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index 7b650d27a..40331fbc4 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -640,7 +640,9 @@ void QGraphicsItemPrivate::updateAncestorFlag(QGraphicsItem::GraphicsItemFlag ch if (parent) { // Inherit the enabled-state from our parents. - if ((parent->d_ptr->ancestorFlags & flag) || (int(parent->d_ptr->flags & childFlag) == childFlag) || (childFlag == -1 && parent->d_ptr->handlesChildEvents)) { + if ((parent->d_ptr->ancestorFlags & flag) + || (int(parent->d_ptr->flags & childFlag) == childFlag) + || (childFlag == -1 && parent->d_ptr->handlesChildEvents)) { enabled = true; ancestorFlags |= flag; } else { -- cgit v1.2.3 From ed375675d4a4f6fd63edeb242e23c87b3de4be6f Mon Sep 17 00:00:00 2001 From: Jens Bache-Wiig Date: Tue, 21 Jul 2009 13:37:43 +0200 Subject: Fix: Gtk native dialogs do not repaint when zero-timers are used The problem was that our glib timers were given too high priority, effectively starving the Gtk event loop. By assigning our timer source, G_PRIORITY_DEFAULT_IDLE we ensure that all gtk+ events are handled first, thus allowing the native dialogs to respond and repaint properly. Task-number: 258433 Reviewed-by: bhughes --- src/corelib/kernel/qeventdispatcher_glib.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/corelib/kernel/qeventdispatcher_glib.cpp b/src/corelib/kernel/qeventdispatcher_glib.cpp index 7610631e1..2bbe560cb 100644 --- a/src/corelib/kernel/qeventdispatcher_glib.cpp +++ b/src/corelib/kernel/qeventdispatcher_glib.cpp @@ -263,6 +263,7 @@ QEventDispatcherGlibPrivate::QEventDispatcherGlibPrivate(GMainContext *context) (void) new (&timerSource->timerList) QTimerInfoList(); timerSource->processEventsFlags = QEventLoop::AllEvents; g_source_set_can_recurse(&timerSource->source, true); + g_source_set_priority(&timerSource->source, G_PRIORITY_DEFAULT_IDLE); g_source_attach(&timerSource->source, mainContext); } -- cgit v1.2.3 From c9a449af8d17e493950a63ca3f8a22232968c47e Mon Sep 17 00:00:00 2001 From: Jens Bache-Wiig Date: Tue, 4 Aug 2009 16:54:07 +0200 Subject: Make file extension case insensitive with the Gtk+ file dialog The Qt dialog treats extension filters as case insensitive where the default behavior of the Gtk+ file dialog is to be case sensitive. The GtkFileFilter allows only simple glob syntax to be used so we basically rewrite the extension string from .xyz to .[xX][yY][zZ]. Task-number: 259155 Reviewed-by: joao --- src/gui/styles/gtksymbols.cpp | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/gui/styles/gtksymbols.cpp b/src/gui/styles/gtksymbols.cpp index be9b10a2d..b2c53f3ff 100644 --- a/src/gui/styles/gtksymbols.cpp +++ b/src/gui/styles/gtksymbols.cpp @@ -733,7 +733,24 @@ static void setupGtkFileChooser(GtkWidget* gtkFileChooser, QWidget *parent, QGtk::gtk_file_filter_set_name(gtkFilter, qPrintable(name.isEmpty() ? extensions.join(QLS(", ")) : name)); foreach (const QString &fileExtension, extensions) { - QGtk::gtk_file_filter_add_pattern (gtkFilter, qPrintable(fileExtension)); + // Note Gtk file dialogs are by default case sensitive + // and only supports basic glob syntax so we + // rewrite .xyz to .[xX][yY][zZ] + QString caseInsensitive; + for (int i = 0 ; i < fileExtension.length() ; ++i) { + QChar ch = fileExtension.at(i); + if (ch.isLetter()) { + caseInsensitive.append( + QLatin1Char('[') + + ch.toLower() + + ch.toUpper() + + QLatin1Char(']')); + } else { + caseInsensitive.append(ch); + } + } + QGtk::gtk_file_filter_add_pattern (gtkFilter, qPrintable(caseInsensitive)); + } QGtk::gtk_file_chooser_add_filter((GtkFileChooser*)gtkFileChooser, gtkFilter); if (selectedFilter && (rawfilter == *selectedFilter)) -- cgit v1.2.3 From a4ede01350b506c9908241f0b9002f560cc0949f Mon Sep 17 00:00:00 2001 From: Bill King Date: Wed, 5 Aug 2009 13:21:00 +1000 Subject: Fixes casing issue in the PSQL driver. The record and primaryIndex functions don't take into account that psql treats different casing as different entities when enquoted. --- src/sql/drivers/psql/qsql_psql.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sql/drivers/psql/qsql_psql.cpp b/src/sql/drivers/psql/qsql_psql.cpp index c61c526d9..4fd0c11f4 100644 --- a/src/sql/drivers/psql/qsql_psql.cpp +++ b/src/sql/drivers/psql/qsql_psql.cpp @@ -940,7 +940,7 @@ QSqlIndex QPSQLDriver::primaryIndex(const QString& tablename) const case QPSQLDriver::Version6: stmt = QLatin1String("select pg_att1.attname, int(pg_att1.atttypid), pg_cl.relname " "from pg_attribute pg_att1, pg_attribute pg_att2, pg_class pg_cl, pg_index pg_ind " - "where lower(pg_cl.relname) = '%1_pkey' " + "where pg_cl.relname = '%1_pkey' " "and pg_cl.oid = pg_ind.indexrelid " "and pg_att2.attrelid = pg_ind.indexrelid " "and pg_att1.attrelid = pg_ind.indrelid " @@ -951,7 +951,7 @@ QSqlIndex QPSQLDriver::primaryIndex(const QString& tablename) const case QPSQLDriver::Version71: stmt = QLatin1String("select pg_att1.attname, pg_att1.atttypid::int, pg_cl.relname " "from pg_attribute pg_att1, pg_attribute pg_att2, pg_class pg_cl, pg_index pg_ind " - "where lower(pg_cl.relname) = '%1_pkey' " + "where pg_cl.relname = '%1_pkey' " "and pg_cl.oid = pg_ind.indexrelid " "and pg_att2.attrelid = pg_ind.indexrelid " "and pg_att1.attrelid = pg_ind.indrelid " @@ -1016,7 +1016,7 @@ QSqlRecord QPSQLDriver::record(const QString& tablename) const "pg_attribute.attnotnull, pg_attribute.attlen, pg_attribute.atttypmod, " "int(pg_attribute.attrelid), pg_attribute.attnum " "from pg_class, pg_attribute " - "where lower(pg_class.relname) = '%1' " + "where pg_class.relname = '%1' " "and pg_attribute.attnum > 0 " "and pg_attribute.attrelid = pg_class.oid "); break; @@ -1025,7 +1025,7 @@ QSqlRecord QPSQLDriver::record(const QString& tablename) const "pg_attribute.attnotnull, pg_attribute.attlen, pg_attribute.atttypmod, " "pg_attribute.attrelid::int, pg_attribute.attnum " "from pg_class, pg_attribute " - "where lower(pg_class.relname) = '%1' " + "where pg_class.relname = '%1' " "and pg_attribute.attnum > 0 " "and pg_attribute.attrelid = pg_class.oid "); break; @@ -1036,7 +1036,7 @@ QSqlRecord QPSQLDriver::record(const QString& tablename) const "from pg_class, pg_attribute " "left join pg_attrdef on (pg_attrdef.adrelid = " "pg_attribute.attrelid and pg_attrdef.adnum = pg_attribute.attnum) " - "where lower(pg_class.relname) = '%1' " + "where pg_class.relname = '%1' " "and pg_attribute.attnum > 0 " "and pg_attribute.attrelid = pg_class.oid " "order by pg_attribute.attnum "); -- cgit v1.2.3 From 7e8e53cded4622ac35ff115e26e074de6722d1a0 Mon Sep 17 00:00:00 2001 From: Bill King Date: Wed, 5 Aug 2009 13:38:44 +1000 Subject: Get more database tests working/passing. --- tests/auto/qsqldatabase/tst_databases.h | 12 +++++++++++- tests/auto/qsqldatabase/tst_qsqldatabase.cpp | 10 +++++++--- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/tests/auto/qsqldatabase/tst_databases.h b/tests/auto/qsqldatabase/tst_databases.h index 8ee74df33..ad7047149 100644 --- a/tests/auto/qsqldatabase/tst_databases.h +++ b/tests/auto/qsqldatabase/tst_databases.h @@ -219,7 +219,7 @@ public: // addDb( "QMYSQL3", "testdb", "troll", "trond", "horsehead.nokia.troll.no", 3307 ); // addDb( "QMYSQL3", "testdb", "troll", "trond", "horsehead.nokia.troll.no", 3308, "CLIENT_COMPRESS=1;CLIENT_SSL=1" ); // MySQL 4.1.1 // addDb( "QMYSQL3", "testdb", "troll", "trond", "horsehead.nokia.troll.no", 3309, "CLIENT_COMPRESS=1;CLIENT_SSL=1" ); // MySQL 5.0.18 Linux -// addDb( "QMYSQL3", "testdb", "troll", "trond", "iceblink.nokia.troll.no" ); // MySQL 5.0.13 Windows +// addDb( "QMYSQL3", "testdb", "troll", "trond", "silence.nokia.troll.no" ); // MySQL 5.1.36 Windows // addDb( "QMYSQL3", "testdb", "testuser", "Ee4Gabf6_", "mysql4-nokia.trolltech.com.au" ); // MySQL 4.1.22-2.el4 linux // addDb( "QMYSQL3", "testdb", "testuser", "Ee4Gabf6_", "mysql5-nokia.trolltech.com.au" ); // MySQL 5.0.45-7.el5 linux @@ -481,6 +481,16 @@ public: return QString(); } + static QString getPSQLVersion( const QSqlDatabase &db ) + { + QSqlQuery q(db); + q.exec( "select version()" ); + if(q.next()) + return q.value( 0 ).toString(); + else + return QString(); + } + QStringList dbNames; int counter; }; diff --git a/tests/auto/qsqldatabase/tst_qsqldatabase.cpp b/tests/auto/qsqldatabase/tst_qsqldatabase.cpp index ff62741a8..de4fe8f55 100644 --- a/tests/auto/qsqldatabase/tst_qsqldatabase.cpp +++ b/tests/auto/qsqldatabase/tst_qsqldatabase.cpp @@ -1057,6 +1057,7 @@ void tst_QSqlDatabase::recordMySQL() int major = tst_Databases::getMySqlVersion( db ).section( QChar('.'), 0, 0 ).toInt(); int minor = tst_Databases::getMySqlVersion( db ).section( QChar('.'), 1, 1 ).toInt(); int revision = tst_Databases::getMySqlVersion( db ).section( QChar('.'), 2, 2 ).toInt(); + int vernum = (major << 16) + (minor << 8) + revision; #ifdef QT3_SUPPORT /* The below is broken in mysql below 5.0.15 @@ -1064,7 +1065,7 @@ void tst_QSqlDatabase::recordMySQL() specifically: Before MySQL 5.0.15, the pad value is space. Values are right-padded with space on insert, and trailing spaces are removed on select. */ - if ( major >5 || ( major == 5 && minor > 0) || ( major == 5 && minor == 0 && revision >= 15) ) { + if( vernum >= ((5 << 16) + 15) ) { bin10 = FieldDef("binary(10)", QVariant::ByteArray, QByteArray(Q3CString("123abc "))); varbin10 = FieldDef("varbinary(10)", QVariant::ByteArray, QByteArray(Q3CString("123abcv "))); } @@ -1594,6 +1595,11 @@ void tst_QSqlDatabase::bug_249059() QSqlDatabase db = QSqlDatabase::database(dbName); CHECK_DATABASE(db); + QString version=tst_Databases::getPSQLVersion( db ); + double ver=version.section(QChar::fromLatin1('.'),0,1).toDouble(); + if (ver < 7.3) + QSKIP("Test requires PostgreSQL >= 7.3", SkipSingle); + QSqlQuery q(db); QString tableName = qTableName("bug_249059"); QVERIFY_SQL(q, exec(QString("CREATE TABLE %1 (dt timestamp, t time)").arg(tableName))); @@ -2006,8 +2012,6 @@ void tst_QSqlDatabase::mysql_multiselect() CHECK_DATABASE(db); QSqlQuery q(db); - QVERIFY_SQL(q, exec("select version()")); - QVERIFY_SQL(q, next()); QString version=tst_Databases::getMySqlVersion( db ); double ver=version.section(QChar::fromLatin1('.'),0,1).toDouble(); if (ver < 4.1) -- cgit v1.2.3 From e7052de274f6a201be628441d144dbbef5868948 Mon Sep 17 00:00:00 2001 From: Justin McPherson Date: Wed, 5 Aug 2009 14:26:56 +1000 Subject: Merge AudioServices into mainline. --- bin/syncqt | 1 + config.tests/unix/alsa/alsa.pro | 4 + config.tests/unix/alsa/alsatest.cpp | 6 + configure | 36 +- configure.exe | Bin 1896493 -> 1134080 bytes demos/qtdemo/xml/examples.xml | 5 + doc/src/examples-overview.qdoc | 11 + doc/src/examples.qdoc | 8 + doc/src/examples/audiodevices.qdoc | 54 ++ doc/src/examples/audioinput.qdoc | 54 ++ doc/src/examples/audiooutput.qdoc | 52 ++ examples/examples.pro | 1 + examples/multimedia/README | 34 + examples/multimedia/audio/audio.pro | 10 + .../multimedia/audio/audiodevices/audiodevices.cpp | 272 ++++++ .../multimedia/audio/audiodevices/audiodevices.h | 79 ++ .../multimedia/audio/audiodevices/audiodevices.pro | 12 + .../audio/audiodevices/audiodevicesbase.ui | 255 ++++++ examples/multimedia/audio/audiodevices/main.cpp | 55 ++ .../multimedia/audio/audioinput/audioinput.cpp | 376 +++++++++ examples/multimedia/audio/audioinput/audioinput.h | 144 ++++ .../multimedia/audio/audioinput/audioinput.pro | 12 + examples/multimedia/audio/audioinput/main.cpp | 55 ++ .../multimedia/audio/audiooutput/audiooutput.cpp | 280 +++++++ .../multimedia/audio/audiooutput/audiooutput.h | 112 +++ .../multimedia/audio/audiooutput/audiooutput.pro | 11 + examples/multimedia/audio/audiooutput/main.cpp | 56 ++ examples/multimedia/multimedia.pro | 8 + mkspecs/features/qt.prf | 3 +- src/corelib/global/qglobal.h | 14 + src/multimedia/audio/audio.pri | 56 ++ src/multimedia/audio/qaudio.cpp | 102 +++ src/multimedia/audio/qaudio.h | 71 ++ src/multimedia/audio/qaudio_mac.cpp | 142 ++++ src/multimedia/audio/qaudio_mac_p.h | 144 ++++ src/multimedia/audio/qaudiodevicefactory.cpp | 250 ++++++ src/multimedia/audio/qaudiodevicefactory_p.h | 100 +++ src/multimedia/audio/qaudiodeviceid.cpp | 168 ++++ src/multimedia/audio/qaudiodeviceid.h | 94 +++ src/multimedia/audio/qaudiodeviceid_p.h | 82 ++ src/multimedia/audio/qaudiodeviceinfo.cpp | 270 ++++++ src/multimedia/audio/qaudiodeviceinfo.h | 102 +++ src/multimedia/audio/qaudiodeviceinfo_alsa_p.cpp | 394 +++++++++ src/multimedia/audio/qaudiodeviceinfo_alsa_p.h | 113 +++ src/multimedia/audio/qaudiodeviceinfo_mac_p.cpp | 357 ++++++++ src/multimedia/audio/qaudiodeviceinfo_mac_p.h | 97 +++ src/multimedia/audio/qaudiodeviceinfo_win32_p.cpp | 378 +++++++++ src/multimedia/audio/qaudiodeviceinfo_win32_p.h | 108 +++ src/multimedia/audio/qaudioengine.cpp | 343 ++++++++ src/multimedia/audio/qaudioengine.h | 131 +++ src/multimedia/audio/qaudioengineplugin.cpp | 54 ++ src/multimedia/audio/qaudioengineplugin.h | 93 +++ src/multimedia/audio/qaudioformat.cpp | 335 ++++++++ src/multimedia/audio/qaudioformat.h | 103 +++ src/multimedia/audio/qaudioinput.cpp | 400 +++++++++ src/multimedia/audio/qaudioinput.h | 108 +++ src/multimedia/audio/qaudioinput_alsa_p.cpp | 688 +++++++++++++++ src/multimedia/audio/qaudioinput_alsa_p.h | 151 ++++ src/multimedia/audio/qaudioinput_mac_p.cpp | 930 +++++++++++++++++++++ src/multimedia/audio/qaudioinput_mac_p.h | 171 ++++ src/multimedia/audio/qaudioinput_win32_p.cpp | 540 ++++++++++++ src/multimedia/audio/qaudioinput_win32_p.h | 154 ++++ src/multimedia/audio/qaudiooutput.cpp | 403 +++++++++ src/multimedia/audio/qaudiooutput.h | 109 +++ src/multimedia/audio/qaudiooutput_alsa_p.cpp | 706 ++++++++++++++++ src/multimedia/audio/qaudiooutput_alsa_p.h | 159 ++++ src/multimedia/audio/qaudiooutput_mac_p.cpp | 700 ++++++++++++++++ src/multimedia/audio/qaudiooutput_mac_p.h | 171 ++++ src/multimedia/audio/qaudiooutput_win32_p.cpp | 502 +++++++++++ src/multimedia/audio/qaudiooutput_win32_p.h | 154 ++++ src/multimedia/multimedia.pro | 11 + src/plugins/audio/audio.pro | 3 + src/plugins/plugins.pro | 1 + src/src.pro | 4 + tests/auto/auto.pro | 4 + tests/auto/qaudiodeviceid/qaudiodeviceid.pro | 7 + tests/auto/qaudiodeviceid/tst_qaudiodeviceid.cpp | 98 +++ tests/auto/qaudiodeviceinfo/qaudiodeviceinfo.pro | 7 + .../auto/qaudiodeviceinfo/tst_qaudiodeviceinfo.cpp | 159 ++++ tests/auto/qaudioformat/qaudioformat.pro | 7 + tests/auto/qaudioformat/tst_qaudioformat.cpp | 180 ++++ tests/auto/qaudioinput/qaudioinput.pro | 7 + tests/auto/qaudioinput/tst_qaudioinput.cpp | 120 +++ tests/auto/qaudiooutput/4.wav | Bin 0 -> 5538 bytes tests/auto/qaudiooutput/qaudiooutput.pro | 12 + tests/auto/qaudiooutput/tst_qaudiooutput.cpp | 156 ++++ tests/auto/tests.xml | 8 + tools/configure/configureapp.cpp | 15 + 88 files changed, 12950 insertions(+), 2 deletions(-) create mode 100644 config.tests/unix/alsa/alsa.pro create mode 100644 config.tests/unix/alsa/alsatest.cpp create mode 100644 doc/src/examples/audiodevices.qdoc create mode 100644 doc/src/examples/audioinput.qdoc create mode 100644 doc/src/examples/audiooutput.qdoc create mode 100644 examples/multimedia/README create mode 100644 examples/multimedia/audio/audio.pro create mode 100644 examples/multimedia/audio/audiodevices/audiodevices.cpp create mode 100644 examples/multimedia/audio/audiodevices/audiodevices.h create mode 100644 examples/multimedia/audio/audiodevices/audiodevices.pro create mode 100644 examples/multimedia/audio/audiodevices/audiodevicesbase.ui create mode 100644 examples/multimedia/audio/audiodevices/main.cpp create mode 100644 examples/multimedia/audio/audioinput/audioinput.cpp create mode 100644 examples/multimedia/audio/audioinput/audioinput.h create mode 100644 examples/multimedia/audio/audioinput/audioinput.pro create mode 100644 examples/multimedia/audio/audioinput/main.cpp create mode 100644 examples/multimedia/audio/audiooutput/audiooutput.cpp create mode 100644 examples/multimedia/audio/audiooutput/audiooutput.h create mode 100644 examples/multimedia/audio/audiooutput/audiooutput.pro create mode 100644 examples/multimedia/audio/audiooutput/main.cpp create mode 100644 examples/multimedia/multimedia.pro create mode 100644 src/multimedia/audio/audio.pri create mode 100644 src/multimedia/audio/qaudio.cpp create mode 100644 src/multimedia/audio/qaudio.h create mode 100644 src/multimedia/audio/qaudio_mac.cpp create mode 100644 src/multimedia/audio/qaudio_mac_p.h create mode 100644 src/multimedia/audio/qaudiodevicefactory.cpp create mode 100644 src/multimedia/audio/qaudiodevicefactory_p.h create mode 100644 src/multimedia/audio/qaudiodeviceid.cpp create mode 100644 src/multimedia/audio/qaudiodeviceid.h create mode 100644 src/multimedia/audio/qaudiodeviceid_p.h create mode 100644 src/multimedia/audio/qaudiodeviceinfo.cpp create mode 100644 src/multimedia/audio/qaudiodeviceinfo.h create mode 100644 src/multimedia/audio/qaudiodeviceinfo_alsa_p.cpp create mode 100644 src/multimedia/audio/qaudiodeviceinfo_alsa_p.h create mode 100644 src/multimedia/audio/qaudiodeviceinfo_mac_p.cpp create mode 100644 src/multimedia/audio/qaudiodeviceinfo_mac_p.h create mode 100644 src/multimedia/audio/qaudiodeviceinfo_win32_p.cpp create mode 100644 src/multimedia/audio/qaudiodeviceinfo_win32_p.h create mode 100644 src/multimedia/audio/qaudioengine.cpp create mode 100644 src/multimedia/audio/qaudioengine.h create mode 100644 src/multimedia/audio/qaudioengineplugin.cpp create mode 100644 src/multimedia/audio/qaudioengineplugin.h create mode 100644 src/multimedia/audio/qaudioformat.cpp create mode 100644 src/multimedia/audio/qaudioformat.h create mode 100644 src/multimedia/audio/qaudioinput.cpp create mode 100644 src/multimedia/audio/qaudioinput.h create mode 100644 src/multimedia/audio/qaudioinput_alsa_p.cpp create mode 100644 src/multimedia/audio/qaudioinput_alsa_p.h create mode 100644 src/multimedia/audio/qaudioinput_mac_p.cpp create mode 100644 src/multimedia/audio/qaudioinput_mac_p.h create mode 100644 src/multimedia/audio/qaudioinput_win32_p.cpp create mode 100644 src/multimedia/audio/qaudioinput_win32_p.h create mode 100644 src/multimedia/audio/qaudiooutput.cpp create mode 100644 src/multimedia/audio/qaudiooutput.h create mode 100644 src/multimedia/audio/qaudiooutput_alsa_p.cpp create mode 100644 src/multimedia/audio/qaudiooutput_alsa_p.h create mode 100644 src/multimedia/audio/qaudiooutput_mac_p.cpp create mode 100644 src/multimedia/audio/qaudiooutput_mac_p.h create mode 100644 src/multimedia/audio/qaudiooutput_win32_p.cpp create mode 100644 src/multimedia/audio/qaudiooutput_win32_p.h create mode 100644 src/multimedia/multimedia.pro create mode 100644 src/plugins/audio/audio.pro create mode 100644 tests/auto/qaudiodeviceid/qaudiodeviceid.pro create mode 100644 tests/auto/qaudiodeviceid/tst_qaudiodeviceid.cpp create mode 100644 tests/auto/qaudiodeviceinfo/qaudiodeviceinfo.pro create mode 100644 tests/auto/qaudiodeviceinfo/tst_qaudiodeviceinfo.cpp create mode 100644 tests/auto/qaudioformat/qaudioformat.pro create mode 100644 tests/auto/qaudioformat/tst_qaudioformat.cpp create mode 100644 tests/auto/qaudioinput/qaudioinput.pro create mode 100644 tests/auto/qaudioinput/tst_qaudioinput.cpp create mode 100644 tests/auto/qaudiooutput/4.wav create mode 100644 tests/auto/qaudiooutput/qaudiooutput.pro create mode 100644 tests/auto/qaudiooutput/tst_qaudiooutput.cpp diff --git a/bin/syncqt b/bin/syncqt index 6c4de6ad1..589659f46 100755 --- a/bin/syncqt +++ b/bin/syncqt @@ -43,6 +43,7 @@ my %modules = ( # path to module name map "QtDBus" => "$basedir/src/dbus", "QtWebKit" => "$basedir/src/3rdparty/webkit/WebCore", "phonon" => "$basedir/src/phonon", + "QtMultimedia" => "$basedir/src/multimedia", ); my %moduleheaders = ( # restrict the module headers to those found in relative path "QtWebKit" => "../WebKit/qt/Api", diff --git a/config.tests/unix/alsa/alsa.pro b/config.tests/unix/alsa/alsa.pro new file mode 100644 index 000000000..4931d38ea --- /dev/null +++ b/config.tests/unix/alsa/alsa.pro @@ -0,0 +1,4 @@ +SOURCES = alsatest.cpp +LIBS+=-lasound +CONFIG -= qt dylib +mac:CONFIG -= app_bundle diff --git a/config.tests/unix/alsa/alsatest.cpp b/config.tests/unix/alsa/alsatest.cpp new file mode 100644 index 000000000..af2f5d91f --- /dev/null +++ b/config.tests/unix/alsa/alsatest.cpp @@ -0,0 +1,6 @@ +#include +int main(int argc,char **argv) +{ + return 0; +} + diff --git a/configure b/configure index 095d04083..1d1f82694 100755 --- a/configure +++ b/configure @@ -609,6 +609,7 @@ CFG_NOBUILD_PARTS="" CFG_RELEASE_QMAKE=no CFG_PHONON=auto CFG_PHONON_BACKEND=yes +CFG_MULTIMEDIA=yes CFG_SVG=yes CFG_WEBKIT=auto # (yes|no|auto) @@ -709,6 +710,7 @@ OPT_VERBOSE=no OPT_HELP= CFG_SILENT=no CFG_GRAPHICS_SYSTEM=default +CFG_ALSA=auto # initalize variables used for installation QT_INSTALL_PREFIX= @@ -848,7 +850,7 @@ while [ "$#" -gt 0 ]; do VAL=no ;; #Qt style yes options - -incremental|-qvfb|-profile|-shared|-static|-sm|-xinerama|-xshape|-xshape|-xinput|-reduce-exports|-pch|-separate-debug-info|-stl|-freetype|-xcursor|-xfixes|-xrandr|-xrender|-mitshm|-fontconfig|-xkb|-nis|-qdbus|-dbus|-dbus-linked|-glib|-gstreamer|-gtkstyle|-cups|-iconv|-largefile|-h|-help|-v|-verbose|-debug|-release|-fast|-accessibility|-confirm-license|-gnumake|-framework|-qt3support|-debug-and-release|-exceptions|-cocoa|-universal|-prefix-install|-silent|-armfpa|-optimized-qmake|-dwarf2|-reduce-relocations|-sse|-openssl|-openssl-linked|-ptmalloc|-xmlpatterns|-phonon|-phonon-backend|-svg|-webkit|-scripttools|-rpath|-force-pkg-config) + -incremental|-qvfb|-profile|-shared|-static|-sm|-xinerama|-xshape|-xshape|-xinput|-reduce-exports|-pch|-separate-debug-info|-stl|-freetype|-xcursor|-xfixes|-xrandr|-xrender|-mitshm|-fontconfig|-xkb|-nis|-qdbus|-dbus|-dbus-linked|-glib|-gstreamer|-gtkstyle|-cups|-iconv|-largefile|-h|-help|-v|-verbose|-debug|-release|-fast|-accessibility|-confirm-license|-gnumake|-framework|-qt3support|-debug-and-release|-exceptions|-cocoa|-universal|-prefix-install|-silent|-armfpa|-optimized-qmake|-dwarf2|-reduce-relocations|-sse|-openssl|-openssl-linked|-ptmalloc|-xmlpatterns|-phonon|-phonon-backend|-multimedia|-svg|-webkit|-scripttools|-rpath|-force-pkg-config) VAR=`echo $1 | sed "s,^-\(.*\),\1,"` VAL=yes ;; @@ -1976,6 +1978,13 @@ while [ "$#" -gt 0 ]; do UNKNOWN_OPT=yes fi ;; + multimedia) + if [ "$VAL" = "yes" ] || [ "$VAL" = "no" ]; then + CFG_MULTIMEDIA="$VAL" + else + UNKNOWN_OPT=yes + fi + ;; *) UNKNOWN_OPT=yes ;; @@ -3152,6 +3161,7 @@ Usage: $relconf [-h] [-prefix ] [-prefix-install] [-bindir ] [-libdir [-no-optimized-qmake] [-optimized-qmake] [-no-xmlpatterns] [-xmlpatterns] [-no-phonon] [-phonon] [-no-phonon-backend] [-phonon-backend] [-no-openssl] [-openssl] [-openssl-linked] + [-no-multimedia] [-multimedia] [-no-gtkstyle] [-gtkstyle] [-no-svg] [-svg] [-no-webkit] [-webkit] [-no-scripttools] [-scripttools] @@ -3292,6 +3302,9 @@ fi -no-phonon-backend.. Do not build the platform phonon plugin. + -phonon-backend..... Build the platform phonon plugin. + -no-multimedia ..... Do not build the multimedia module. + * -multimedia ........ Build the multimedia module. + -no-svg ............ Do not build the SVG module. + -svg ............... Build the SVG module. @@ -5664,6 +5677,14 @@ if [ "$CFG_PTMALLOC" != "no" ]; then QMakeVar add QMAKE_LFLAGS "$outpath/lib/libptmalloc3.a" fi +if [ "$CFG_ALSA" = "auto" ]; then + if "$unixtests/compile.test" "$XQMAKESPEC" "$QMAKE_CONFIG" $OPT_VERBOSE "$relpath" "$outpath" config.tests/unix/alsa "alsa" $L_FLAGS $I_FLAGS $l_FLAGS; then + CFG_ALSA=yes + else + CFG_ALSA=no + fi +fi + #------------------------------------------------------------------------------- # ask for all that hasn't been auto-detected or specified in the arguments #------------------------------------------------------------------------------- @@ -6104,6 +6125,10 @@ if [ "$CFG_EXCEPTIONS" != "no" ]; then QTCONFIG_CONFIG="$QTCONFIG_CONFIG exceptions" fi +if [ "$CFG_ALSA" = "yes" ]; then + QT_CONFIG="$QT_CONFIG alsa" +fi + # # Some Qt modules are too advanced in C++ for some old compilers # Detect here the platforms where they are known to work. @@ -6275,6 +6300,12 @@ else QCONFIG_FLAGS="$QCONFIG_FLAGS QT_NO_SCRIPTTOOLS" fi +if [ "$CFG_MULTIMEDIA" = "yes" ]; then + QT_CONFIG="$QT_CONFIG multimedia" +else + QCONFIG_FLAGS="$QCONFIG_FLAGS QT_NO_MULTIMEDIA" +fi + if [ "$CFG_EXCEPTIONS" = "no" ]; then case "$COMPILER" in g++*) @@ -6776,6 +6807,7 @@ fi [ "$CFG_XFIXES" = "runtime" ] && QCONFIG_FLAGS="$QCONFIG_FLAGS QT_RUNTIME_XFIXES" [ "$CFG_XRANDR" = "runtime" ] && QCONFIG_FLAGS="$QCONFIG_FLAGS QT_RUNTIME_XRANDR" [ "$CFG_XINPUT" = "runtime" ] && QCONFIG_FLAGS="$QCONFIG_FLAGS QT_RUNTIME_XINPUT" +[ "$CFG_ALSA" = "no" ] && QCONFIG_FLAGS="$QCONFIG_FLAGS QT_NO_ALSA" # sort QCONFIG_FLAGS for neatness if we can [ '!' -z "$AWK" ] && QCONFIG_FLAGS=`echo $QCONFIG_FLAGS | $AWK '{ gsub(" ", "\n"); print }' | sort | uniq` @@ -7135,6 +7167,7 @@ echo "QtConcurrent code.... $CFG_CONCURRENT" echo "QtScriptTools module $CFG_SCRIPTTOOLS" echo "QtXmlPatterns module $CFG_XMLPATTERNS" echo "Phonon module ....... $CFG_PHONON" +echo "Multimedia module ... $CFG_MULTIMEDIA" echo "SVG module .......... $CFG_SVG" echo "WebKit module ....... $CFG_WEBKIT" echo "STL support ......... $CFG_STL" @@ -7285,6 +7318,7 @@ if [ "$PLATFORM_MAC" = "yes" ] && [ "$CFG_FRAMEWORK" = "yes" ] && [ "$CFG_DEBUG" echo "NOTE: Mac OS X frameworks implicitly build debug and release Qt libraries." echo fi +echo "alsa support ........ $CFG_ALSA" echo sepath=`echo "$relpath" | sed -e 's/\\./\\\\./g'` diff --git a/configure.exe b/configure.exe index 322819ef2..cf5885a16 100644 Binary files a/configure.exe and b/configure.exe differ diff --git a/demos/qtdemo/xml/examples.xml b/demos/qtdemo/xml/examples.xml index 006bfd07e..1b0b53392 100644 --- a/demos/qtdemo/xml/examples.xml +++ b/demos/qtdemo/xml/examples.xml @@ -154,6 +154,11 @@ + + + + + diff --git a/doc/src/examples-overview.qdoc b/doc/src/examples-overview.qdoc index 4313c436d..3db4a455d 100644 --- a/doc/src/examples-overview.qdoc +++ b/doc/src/examples-overview.qdoc @@ -238,6 +238,17 @@ These examples demonstrate the basic techniques used to take advantage of OpenGL in Qt applications. + \section1 \l{Qt Examples#Multimedia}{Multimedia} + + \l{Qt Examples#Multimedia} + + Qt provides low-level audio support on linux,windows and mac platforms by default and + an audio plugin API to allow developers to implement there own audio support for + custom devices and platforms. + + These examples demonstrate the basic techniques used to take advantage of + Audio API in Qt applications. + \section1 \l{Qt Examples#SQL}{SQL} \l{Qt Examples#SQL}{\inlineimage sql-examples.png diff --git a/doc/src/examples.qdoc b/doc/src/examples.qdoc index e85acd134..74a9bd880 100644 --- a/doc/src/examples.qdoc +++ b/doc/src/examples.qdoc @@ -255,6 +255,14 @@ \o \l{phonon/musicplayer}{Music Player}\raisedaster \endlist + \section1 Multimedia + + \list + \o \l{multimedia/audio/audiodevices}{Audio Devices}\raisedaster + \o \l{multimedia/audio/audiooutput}{Audio Output}\raisedaster + \o \l{multimedia/audio/audioinput}{Audio Input}\raisedaster + \endlist + \section1 Qt Designer \list diff --git a/doc/src/examples/audiodevices.qdoc b/doc/src/examples/audiodevices.qdoc new file mode 100644 index 000000000..3b8cdd852 --- /dev/null +++ b/doc/src/examples/audiodevices.qdoc @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \example multimedia/audio/audiodevices + \title Audio Devices Example + + The Audio Devices example demonstrates the basic use of QAudioDeviceInfo class + provided with Qt. + + Qt provides the QAudioDeviceInfo class to enable audio querying within + a standard application user interface. + + This example allows you to browse audio devices available and try out different + configurations to see if they are supported. +*/ diff --git a/doc/src/examples/audioinput.qdoc b/doc/src/examples/audioinput.qdoc new file mode 100644 index 000000000..5dfe76e07 --- /dev/null +++ b/doc/src/examples/audioinput.qdoc @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \example multimedia/audio/audioinput + \title AudioInput Example + + The Audio Input example demonstrates the basic use of QAudioInput class + provided with Qt. + + Qt provides the QAudioInput class to enable audio functionality within + a standard application user interface. + + This example uses a fast-fourier transform on the input audio from the microphone + and displays the output. +*/ diff --git a/doc/src/examples/audiooutput.qdoc b/doc/src/examples/audiooutput.qdoc new file mode 100644 index 000000000..9c8a75f4b --- /dev/null +++ b/doc/src/examples/audiooutput.qdoc @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \example multimedia/audio/audiooutput + \title Audio Output Example + + The Audio Output example demonstrates the basic use of the QAudioOutput class + provided with Qt. + + This example provides a tone generator to supply continuous audio playback. + The first button allows pause and resume of the playback. + The second button allows toggling between push and pull modes of operation. +*/ diff --git a/examples/examples.pro b/examples/examples.pro index 5855e4f38..e6cece9da 100644 --- a/examples/examples.pro +++ b/examples/examples.pro @@ -26,6 +26,7 @@ SUBDIRS = \ multitouch \ gestures +contains(QT_CONFIG, multimedia):!static: SUBDIRS += multimedia contains(QT_CONFIG, phonon):!static: SUBDIRS += phonon contains(QT_CONFIG, webkit): SUBDIRS += webkit embedded:SUBDIRS += qws diff --git a/examples/multimedia/README b/examples/multimedia/README new file mode 100644 index 000000000..aa78e369f --- /dev/null +++ b/examples/multimedia/README @@ -0,0 +1,34 @@ + +The example launcher provided with Qt can be used to explore each of the +examples in this directory. + +Documentation for these examples can be found via the Tutorial and Examples +link in the main Qt documentation. + + +Finding the Qt Examples and Demos launcher +========================================== + +On Windows: + +The launcher can be accessed via the Windows Start menu. Select the menu +entry entitled "Qt Examples and Demos" entry in the submenu containing +the Qt tools. + +On Mac OS X: + +For the binary distribution, the qtdemo executable is installed in the +/Developer/Applications/Qt directory. For the source distribution, it is +installed alongside the other Qt tools on the path specified when Qt is +configured. + +On Unix/Linux: + +The qtdemo executable is installed alongside the other Qt tools on the path +specified when Qt is configured. + +On all platforms: + +The source code for the launcher can be found in the demos/qtdemo directory +in the Qt package. This example is built at the same time as the Qt libraries, +tools, examples, and demonstrations. diff --git a/examples/multimedia/audio/audio.pro b/examples/multimedia/audio/audio.pro new file mode 100644 index 000000000..c64bb34c6 --- /dev/null +++ b/examples/multimedia/audio/audio.pro @@ -0,0 +1,10 @@ +TEMPLATE = subdirs +SUBDIRS = audioinput \ + audiooutput \ + audiodevices + +# install +target.path = $$[QT_INSTALL_EXAMPLES]/multimedia/audio +sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS audio.pro README +sources.path = $$[QT_INSTALL_EXAMPLES]/multimedia/audio +INSTALLS += target sources diff --git a/examples/multimedia/audio/audiodevices/audiodevices.cpp b/examples/multimedia/audio/audiodevices/audiodevices.cpp new file mode 100644 index 000000000..2a3af9877 --- /dev/null +++ b/examples/multimedia/audio/audiodevices/audiodevices.cpp @@ -0,0 +1,272 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include +#include + +#include "audiodevices.h" + +AudioDevicesBase::AudioDevicesBase( QMainWindow *parent, Qt::WFlags f ) +{ + Q_UNUSED(parent) + Q_UNUSED(f) + setupUi( this ); +} + +AudioDevicesBase::~AudioDevicesBase() {} + + +AudioTest::AudioTest( QMainWindow *parent, Qt::WFlags f ) + : AudioDevicesBase( parent, f ) +{ + mode = QAudio::AudioOutput; + modeBox->addItem("Input"); + modeBox->addItem("Output"); + + connect(testButton,SIGNAL(clicked()),SLOT(test())); + connect(modeBox,SIGNAL(activated(int)),SLOT(modeChanged(int))); + connect(deviceBox,SIGNAL(activated(int)),SLOT(deviceChanged(int))); + connect(frequencyBox,SIGNAL(activated(int)),SLOT(freqChanged(int))); + connect(channelsBox,SIGNAL(activated(int)),SLOT(channelChanged(int))); + connect(codecsBox,SIGNAL(activated(int)),SLOT(codecChanged(int))); + connect(sampleSizesBox,SIGNAL(activated(int)),SLOT(sampleSizeChanged(int))); + connect(sampleTypesBox,SIGNAL(activated(int)),SLOT(sampleTypeChanged(int))); + connect(endianBox,SIGNAL(activated(int)),SLOT(endianChanged(int))); + + device = 0; + + modeBox->setCurrentIndex(0); + modeChanged(0); + deviceBox->setCurrentIndex(0); + deviceChanged(0); +} + +AudioTest::~AudioTest() +{ +} + +void AudioTest::test() +{ + // tries to set all the settings picked. + + if(device) { + if(device->isFormatSupported(settings)) { + logOutput->append("Success"); + nearestFreq->setText(""); + nearestChannel->setText(""); + nearestCodec->setText(""); + nearestSampleSize->setText(""); + nearestSampleType->setText(""); + nearestEndian->setText(""); + } else { + QAudioFormat nearest = device->nearestFormat(settings); + logOutput->append(tr("Failed")); + nearestFreq->setText(QString("%1").arg(nearest.frequency())); + nearestChannel->setText(QString("%1").arg(nearest.channels())); + nearestCodec->setText(nearest.codec()); + nearestSampleSize->setText(QString("%1").arg(nearest.sampleSize())); + + switch(nearest.sampleType()) { + case QAudioFormat::SignedInt: + nearestSampleType->setText("SignedInt"); + break; + case QAudioFormat::UnSignedInt: + nearestSampleType->setText("UnSignedInt"); + break; + case QAudioFormat::Float: + nearestSampleType->setText("Float"); + break; + case QAudioFormat::Unknown: + nearestSampleType->setText("Unknown"); + } + switch(nearest.byteOrder()) { + case QAudioFormat::LittleEndian: + nearestEndian->setText("LittleEndian"); + break; + case QAudioFormat::BigEndian: + nearestEndian->setText("BigEndian"); + } + } + } + else + logOutput->append("No Device"); +} + +void AudioTest::modeChanged(int idx) +{ + // mode has changed + if(idx == 0) + mode=QAudio::AudioInput; + else + mode=QAudio::AudioOutput; + + deviceBox->clear(); + QList devices = QAudioDeviceInfo::deviceList(mode); + for(int i = 0; i < devices.size(); ++i) { + deviceBox->addItem(QAudioDeviceInfo(devices.at(i)).deviceName(), qVariantFromValue(devices.at(i))); + } +} + +void AudioTest::deviceChanged(int idx) +{ + delete device; + device = 0; + + if (deviceBox->count() == 0) + return; + + // device has changed + deviceHandle = deviceBox->itemData(idx).value(); + device = new QAudioDeviceInfo(deviceHandle, this); + + frequencyBox->clear(); + QList freqz = device->supportedFrequencies(); + for(int i = 0; i < freqz.size(); ++i) + frequencyBox->addItem(QString("%1").arg(freqz.at(i))); + if(freqz.size()) + settings.setFrequency(freqz.at(0)); + + channelsBox->clear(); + QList chz = device->supportedChannels(); + for(int i = 0; i < chz.size(); ++i) + channelsBox->addItem(QString("%1").arg(chz.at(i))); + if(chz.size()) + settings.setChannels(chz.at(0)); + + codecsBox->clear(); + QStringList codecz = device->supportedCodecs(); + for(int i = 0; i < codecz.size(); ++i) + codecsBox->addItem(QString("%1").arg(codecz.at(i))); + if(codecz.size()) + settings.setCodec(codecz.at(0)); + // Add false to create failed condition! + codecsBox->addItem("audio/mpeg"); + + sampleSizesBox->clear(); + QList sampleSizez = device->supportedSampleSizes(); + for(int i = 0; i < sampleSizez.size(); ++i) + sampleSizesBox->addItem(QString("%1").arg(sampleSizez.at(i))); + if(sampleSizez.size()) + settings.setSampleSize(sampleSizez.at(0)); + + sampleTypesBox->clear(); + QList sampleTypez = device->supportedSampleTypes(); + for(int i = 0; i < sampleTypez.size(); ++i) { + switch(sampleTypez.at(i)) { + case QAudioFormat::SignedInt: + sampleTypesBox->addItem("SignedInt"); + break; + case QAudioFormat::UnSignedInt: + sampleTypesBox->addItem("UnSignedInt"); + break; + case QAudioFormat::Float: + sampleTypesBox->addItem("Float"); + break; + case QAudioFormat::Unknown: + sampleTypesBox->addItem("Unknown"); + } + if(sampleTypez.size()) + settings.setSampleType(sampleTypez.at(0)); + } + + endianBox->clear(); + QList endianz = device->supportedByteOrders(); + for(int i = 0; i < endianz.size(); ++i) { + switch(endianz.at(i)) { + case QAudioFormat::LittleEndian: + endianBox->addItem("Little Endian"); + break; + case QAudioFormat::BigEndian: + endianBox->addItem("Big Endian"); + break; + } + } + if(endianz.size()) + settings.setByteOrder(endianz.at(0)); +} + +void AudioTest::freqChanged(int idx) +{ + // freq has changed + settings.setFrequency(frequencyBox->itemText(idx).toInt()); +} + +void AudioTest::channelChanged(int idx) +{ + settings.setChannels(channelsBox->itemText(idx).toInt()); +} + +void AudioTest::codecChanged(int idx) +{ + settings.setCodec(codecsBox->itemText(idx)); +} + +void AudioTest::sampleSizeChanged(int idx) +{ + settings.setSampleSize(sampleSizesBox->itemText(idx).toInt()); +} + +void AudioTest::sampleTypeChanged(int idx) +{ + switch(sampleTypesBox->itemText(idx).toInt()) { + case QAudioFormat::SignedInt: + settings.setSampleType(QAudioFormat::SignedInt); + break; + case QAudioFormat::UnSignedInt: + settings.setSampleType(QAudioFormat::UnSignedInt); + break; + case QAudioFormat::Float: + settings.setSampleType(QAudioFormat::Float); + } +} + +void AudioTest::endianChanged(int idx) +{ + switch(endianBox->itemText(idx).toInt()) { + case QAudioFormat::LittleEndian: + settings.setByteOrder(QAudioFormat::LittleEndian); + break; + case QAudioFormat::BigEndian: + settings.setByteOrder(QAudioFormat::BigEndian); + } +} + diff --git a/examples/multimedia/audio/audiodevices/audiodevices.h b/examples/multimedia/audio/audiodevices/audiodevices.h new file mode 100644 index 000000000..34a531b1f --- /dev/null +++ b/examples/multimedia/audio/audiodevices/audiodevices.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include +#include +#include + +#include "ui_audiodevicesbase.h" + +class AudioDevicesBase : public QMainWindow, public Ui::AudioDevicesBase +{ +public: + AudioDevicesBase( QMainWindow *parent = 0, Qt::WFlags f = 0 ); + virtual ~AudioDevicesBase(); +}; + +class AudioTest : public AudioDevicesBase +{ + Q_OBJECT +public: + AudioTest( QMainWindow *parent = 0, Qt::WFlags f = 0 ); + virtual ~AudioTest(); + + QAudioDeviceId deviceHandle; + QAudioDeviceInfo* device; + QAudioFormat settings; + QAudio::Mode mode; + +private slots: + void modeChanged(int idx); + void deviceChanged(int idx); + void freqChanged(int idx); + void channelChanged(int idx); + void codecChanged(int idx); + void sampleSizeChanged(int idx); + void sampleTypeChanged(int idx); + void endianChanged(int idx); + void test(); +}; + diff --git a/examples/multimedia/audio/audiodevices/audiodevices.pro b/examples/multimedia/audio/audiodevices/audiodevices.pro new file mode 100644 index 000000000..adc489091 --- /dev/null +++ b/examples/multimedia/audio/audiodevices/audiodevices.pro @@ -0,0 +1,12 @@ +HEADERS = audiodevices.h +SOURCES = audiodevices.cpp \ + main.cpp +FORMS += audiodevicesbase.ui + +QT += multimedia + +# install +target.path = $$[QT_INSTALL_EXAMPLES]/multimedia/audio/audiodevices +sources.files = $$SOURCES *.h $$RESOURCES $$FORMS audiodevices.pro +sources.path = $$[QT_INSTALL_EXAMPLES]/multimedia/audio/audiodevices +INSTALLS += target sources diff --git a/examples/multimedia/audio/audiodevices/audiodevicesbase.ui b/examples/multimedia/audio/audiodevices/audiodevicesbase.ui new file mode 100644 index 000000000..674f2014f --- /dev/null +++ b/examples/multimedia/audio/audiodevices/audiodevicesbase.ui @@ -0,0 +1,255 @@ + + AudioDevicesBase + + + + 0 + 0 + 504 + 702 + + + + AudioDevicesBase + + + + + 0 + 28 + 504 + 653 + + + + + + 40 + 21 + 321 + 506 + + + + + + + + 1 + 0 + + + + Device + + + + + + + Mode + + + + + + + + + + + + + QFrame::Panel + + + QFrame::Raised + + + Actual Settings + + + Qt::AlignCenter + + + + + + + QFrame::Panel + + + QFrame::Raised + + + Nearest Settings + + + Qt::AlignCenter + + + + + + + Frequency + + + + + + + Frequency + + + + + + + + + + + + + Channels + + + + + + + Channel + + + + + + + + + + + + + Codecs + + + + + + + Codec + + + + + + + + + + + + + SampleSize + + + + + + + SampleSize + + + + + + + + + + + + + SampleType + + + + + + + SampleType + + + + + + + + + + + + + Endianess + + + + + + + Endianess + + + + + + + + + + + + + + 0 + 40 + + + + + + + + Test + + + + + + + + + + 0 + 0 + 504 + 28 + + + + + + + 0 + 681 + 504 + 21 + + + + + + + diff --git a/examples/multimedia/audio/audiodevices/main.cpp b/examples/multimedia/audio/audiodevices/main.cpp new file mode 100644 index 000000000..12e413ea4 --- /dev/null +++ b/examples/multimedia/audio/audiodevices/main.cpp @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "audiodevices.h" + +int main(int argv, char **args) +{ + QApplication app(argv, args); + app.setApplicationName("Audio Device Test"); + + AudioTest audio; + audio.show(); + + return app.exec(); +} diff --git a/examples/multimedia/audio/audioinput/audioinput.cpp b/examples/multimedia/audio/audioinput/audioinput.cpp new file mode 100644 index 000000000..ae7d84c2f --- /dev/null +++ b/examples/multimedia/audio/audioinput/audioinput.cpp @@ -0,0 +1,376 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +#include +#include +#include + +#include +#include +#include "audioinput.h" + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +Spectrum::Spectrum(QObject* parent, QAudioInput* device, float* out) + :QIODevice( parent ) +{ + input = device; + output = out; + + unsigned int i; + + // Allocate sample buffer and initialize sin and cos lookup tables + fftState = (fft_state *) malloc (sizeof(fft_state)); + + for(i = 0; i < BUFFER_SIZE; i++) { + bitReverse[i] = reverseBits(i); + } + for(i = 0; i < BUFFER_SIZE / 2; i++) { + float j = 2 * M_PI * i / BUFFER_SIZE; + costable[i] = cos(j); + sintable[i] = sin(j); + } +} + +Spectrum::~Spectrum() +{ +} + +void Spectrum::start() +{ + open(QIODevice::WriteOnly); +} + +void Spectrum::stop() +{ + close(); +} + +qint64 Spectrum::readData(char *data, qint64 maxlen) +{ + Q_UNUSED(data) + Q_UNUSED(maxlen) + + return 0; +} + +qint64 Spectrum::writeData(const char *data, qint64 len) +{ + performFFT((sound_sample*)data); + emit update(); + + return len; +} + +int Spectrum::reverseBits(unsigned int initial) { + // BIT-REVERSE-COPY(a,A) + + unsigned int reversed = 0, loop; + for(loop = 0; loop < BUFFER_SIZE_LOG; loop++) { + reversed <<= 1; + reversed += (initial & 1); + initial >>= 1; + } + return reversed; +} + +void Spectrum::performFFT(const sound_sample *input) { + /* Convert to reverse bit order for FFT */ + prepFFT(input, fftState->real, fftState->imag); + + /* Calculate FFT */ + calcFFT(fftState->real, fftState->imag); + + /* Convert FFT to intensities */ + outputFFT(fftState->real, fftState->imag); +} + +void Spectrum::prepFFT(const sound_sample *input, float * re, float * im) { + unsigned int i; + float *realptr = re; + float *imagptr = im; + + /* Get input, in reverse bit order */ + for(i = 0; i < BUFFER_SIZE; i++) { + *realptr++ = input[bitReverse[i]]; + *imagptr++ = 0; + } +} + +void Spectrum::calcFFT(float * re, float * im) { + unsigned int i, j, k; + unsigned int exchanges; + float fact_real, fact_imag; + float tmp_real, tmp_imag; + unsigned int factfact; + + /* Set up some variables to reduce calculation in the loops */ + exchanges = 1; + factfact = BUFFER_SIZE / 2; + + /* divide and conquer method */ + for(i = BUFFER_SIZE_LOG; i != 0; i--) { + for(j = 0; j != exchanges; j++) { + fact_real = costable[j * factfact]; + fact_imag = sintable[j * factfact]; + for(k = j; k < BUFFER_SIZE; k += exchanges << 1) { + int k1 = k + exchanges; + tmp_real = fact_real * re[k1] - fact_imag * im[k1]; + tmp_imag = fact_real * im[k1] + fact_imag * re[k1]; + re[k1] = re[k] - tmp_real; + im[k1] = im[k] - tmp_imag; + re[k] += tmp_real; + im[k] += tmp_imag; + } + } + exchanges <<= 1; + factfact >>= 1; + } +} + +void Spectrum::outputFFT(const float * re, const float * im) { + const float *realptr = re; + const float *imagptr = im; + float *outputptr = output; + + float *endptr = output + BUFFER_SIZE / 2; + + /* Convert FFT to intensities */ + + while(outputptr <= endptr) { + *outputptr = (*realptr * *realptr) + (*imagptr * *imagptr); + outputptr++; realptr++; imagptr++; + } + *output /= 4; + *endptr /= 4; +} + + +RenderArea::RenderArea(QWidget *parent) + : QWidget(parent) +{ + setBackgroundRole(QPalette::Base); + setAutoFillBackground(true); + + samples = 0; + sampleSize = 0; + setMinimumHeight(30); + setMinimumWidth(200); +} + +void RenderArea::paintEvent(QPaintEvent * /* event */) +{ + QPainter painter(this); + + if(sampleSize == 0) + return; + + painter.setPen(Qt::red); + int max = 0; + for(int i=0;i max) + max = m; + } + int x1,y1,x2,y2; + + for(int i=0;i<10;i++) { + x1 = painter.viewport().left()+11; + y1 = painter.viewport().top()+10+i; + x2 = painter.viewport().right()-20-max; + y2 = painter.viewport().top()+10+i; + if(x2 < painter.viewport().left()+10) + x2 = painter.viewport().left()+10; + + painter.drawLine(QPoint(x1,y1),QPoint(x2,y2)); + } + + painter.setPen(Qt::black); + painter.drawRect(QRect(painter.viewport().left()+10, painter.viewport().top()+10, + painter.viewport().right()-20, painter.viewport().bottom()-20)); +} + +void RenderArea::spectrum(float* output, int size) +{ + samples = output; + sampleSize = size; + repaint(); +} + + +InputTest::InputTest() +{ + QWidget *window = new QWidget; + QVBoxLayout* layout = new QVBoxLayout; + + canvas = new RenderArea; + layout->addWidget(canvas); + + deviceBox = new QComboBox(this); + QList devices = QAudioDeviceInfo::deviceList(QAudio::AudioInput); + for(int i = 0; i < devices.size(); ++i) { + deviceBox->addItem(QAudioDeviceInfo(devices.at(i)).deviceName(), qVariantFromValue(devices.at(i))); + } + connect(deviceBox,SIGNAL(activated(int)),SLOT(deviceChanged(int))); + layout->addWidget(deviceBox); + + button = new QPushButton(this); + button->setText(tr("Click for Push Mode")); + connect(button,SIGNAL(clicked()),SLOT(toggleMode())); + layout->addWidget(button); + + button2 = new QPushButton(this); + button2->setText(tr("Click To Suspend")); + connect(button2,SIGNAL(clicked()),SLOT(toggleSuspend())); + layout->addWidget(button2); + + window->setLayout(layout); + setCentralWidget(window); + window->show(); + + buffer = new char[BUFFER_SIZE*10]; + output = new float[1024]; + + pullMode = true; + + format.setFrequency(8000); + format.setChannels(1); + format.setSampleSize(8); + format.setSampleType(QAudioFormat::UnSignedInt); + format.setByteOrder(QAudioFormat::LittleEndian); + format.setCodec("audio/pcm"); + + audioInput = new QAudioInput(format,this); + connect(audioInput,SIGNAL(notify()),SLOT(status())); + connect(audioInput,SIGNAL(stateChanged(QAudio::State)),SLOT(state(QAudio::State))); + spec = new Spectrum(this,audioInput,output); + connect(spec,SIGNAL(update()),SLOT(refreshDisplay())); + spec->start(); + audioInput->start(spec); +} + +InputTest::~InputTest() {} + +void InputTest::status() +{ + qWarning()<<"bytesReady = "<bytesReady()<<" bytes, clock = "<clock()<<"ms, totalTime = "<totalTime()/1000<<"ms"; +} + +void InputTest::readMore() +{ + if(!audioInput) + return; + qint64 len = audioInput->bytesReady(); + if(len > BUFFER_SIZE*10) + len = BUFFER_SIZE*10; + qint64 l = input->read(buffer,len); + if(l > 0) { + spec->write(buffer,l); + } +} + +void InputTest::toggleMode() +{ + // Change bewteen pull and push modes + audioInput->stop(); + + if(pullMode) { + button->setText(tr("Click for Push Mode")); + input = audioInput->start(0); + connect(input,SIGNAL(readyRead()),SLOT(readMore())); + pullMode = false; + } else { + button->setText(tr("Click for Pull Mode")); + pullMode = true; + audioInput->start(spec); + } +} + +void InputTest::toggleSuspend() +{ + // toggle suspend/resume + if(audioInput->state() == QAudio::SuspendState) { + qWarning()<<"status: Suspended, resume()"; + audioInput->resume(); + button2->setText("Click To Suspend"); + } else if (audioInput->state() == QAudio::ActiveState) { + qWarning()<<"status: Active, suspend()"; + audioInput->suspend(); + button2->setText("Click To Resume"); + } else if (audioInput->state() == QAudio::StopState) { + qWarning()<<"status: Stopped, resume()"; + audioInput->resume(); + button2->setText("Click To Suspend"); + } else if (audioInput->state() == QAudio::IdleState) { + qWarning()<<"status: IdleState"; + } +} + +void InputTest::state(QAudio::State state) +{ + qWarning()<<" state="<spectrum(output,256); + canvas->repaint(); +} + +void InputTest::deviceChanged(int idx) +{ + spec->stop(); + audioInput->stop(); + audioInput->disconnect(this); + delete audioInput; + + device = deviceBox->itemData(idx).value(); + audioInput = new QAudioInput(device, format, this); + connect(audioInput,SIGNAL(notify()),SLOT(status())); + connect(audioInput,SIGNAL(stateChanged(QAudio::State)),SLOT(state(QAudio::State))); + spec->start(); + audioInput->start(spec); +} diff --git a/examples/multimedia/audio/audioinput/audioinput.h b/examples/multimedia/audio/audioinput/audioinput.h new file mode 100644 index 000000000..3a6b3566c --- /dev/null +++ b/examples/multimedia/audio/audioinput/audioinput.h @@ -0,0 +1,144 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include + +#define BUFFER_SIZE_LOG 9 +#define BUFFER_SIZE (1 << BUFFER_SIZE_LOG) + +struct _struct_fft_state { + float real[BUFFER_SIZE]; + float imag[BUFFER_SIZE]; +}; +typedef _struct_fft_state fft_state; +typedef short int sound_sample; + +class Spectrum : public QIODevice +{ + Q_OBJECT +public: + Spectrum(QObject* parent, QAudioInput* device, float* out); + ~Spectrum(); + + void start(); + void stop(); + + qint64 readData(char *data, qint64 maxlen); + qint64 writeData(const char *data, qint64 len); + + QAudioInput* input; + float* output; + fft_state* fftState; + + unsigned int bitReverse[BUFFER_SIZE]; + float sintable[BUFFER_SIZE / 2]; + float costable[BUFFER_SIZE / 2]; + + void prepFFT (const sound_sample *input, float *re, float *im); + void calcFFT (float *re, float *im); + void outputFFT (const float *re, const float *im); + int reverseBits (unsigned int initial); + void performFFT (const sound_sample *input); + +signals: + void update(); +}; + + +class RenderArea : public QWidget +{ + Q_OBJECT + +public: + RenderArea(QWidget *parent = 0); + + void spectrum(float* output, int size); + +protected: + void paintEvent(QPaintEvent *event); + +private: + QPixmap pixmap; + + float* samples; + int sampleSize; +}; + +class InputTest : public QMainWindow +{ + Q_OBJECT +public: + InputTest(); + ~InputTest(); + + QAudioDeviceId device; + QAudioFormat format; + QAudioInput* audioInput; + Spectrum* spec; + QIODevice* input; + RenderArea* canvas; + + bool pullMode; + + QPushButton* button; + QPushButton* button2; + QComboBox* deviceBox; + + char* buffer; + float* output; + +private slots: + void refreshDisplay(); + void status(); + void readMore(); + void toggleMode(); + void toggleSuspend(); + void state(QAudio::State s); + void deviceChanged(int idx); +}; + diff --git a/examples/multimedia/audio/audioinput/audioinput.pro b/examples/multimedia/audio/audioinput/audioinput.pro new file mode 100644 index 000000000..d930750ec --- /dev/null +++ b/examples/multimedia/audio/audioinput/audioinput.pro @@ -0,0 +1,12 @@ +HEADERS = audioinput.h +SOURCES = audioinput.cpp \ + main.cpp + +QT += multimedia + +# install +target.path = $$[QT_INSTALL_EXAMPLES]/multimedia/audio/audioinput +sources.files = $$SOURCES *.h $$RESOURCES $$FORMS audioinput.pro +sources.path = $$[QT_INSTALL_EXAMPLES]/multimedia/audio/audioinput +INSTALLS += target sources + diff --git a/examples/multimedia/audio/audioinput/main.cpp b/examples/multimedia/audio/audioinput/main.cpp new file mode 100644 index 000000000..64a9b040f --- /dev/null +++ b/examples/multimedia/audio/audioinput/main.cpp @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "audioinput.h" + +int main(int argv, char **args) +{ + QApplication app(argv, args); + app.setApplicationName("Audio Input Test"); + + InputTest input; + input.show(); + + return app.exec(); +} diff --git a/examples/multimedia/audio/audiooutput/audiooutput.cpp b/examples/multimedia/audio/audiooutput/audiooutput.cpp new file mode 100644 index 000000000..be26f192c --- /dev/null +++ b/examples/multimedia/audio/audiooutput/audiooutput.cpp @@ -0,0 +1,280 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +#include +#include +#include "audiooutput.h" + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +Generator::Generator(QObject *parent) + :QIODevice( parent ) +{ + finished = false; + buffer = new char[SECONDS*44100*4+1000]; + t=buffer; + len=fillData(t+4,450,SECONDS); /* left channel, 450Hz sine */ + len+=fillData(t+6,452,SECONDS); /* right channel, 452Hz sine */ + putLong(t,len); + putLong(buffer+4,len+8+16+8); + pos = 0; + total = len+8+16+8; +} + +Generator::~Generator() +{ + delete [] buffer; +} + +void Generator::start() +{ + open(QIODevice::ReadOnly); +} + +void Generator::stop() +{ + close(); +} + +int Generator::putShort(char *t, unsigned int value) +{ + *(unsigned char *)(t++)=value&255; + *(unsigned char *)(t)=(value/256)&255; + return 2; +} + +int Generator::putLong(char *t, unsigned int value) +{ + *(unsigned char *)(t++)=value&255; + *(unsigned char *)(t++)=(value/256)&255; + *(unsigned char *)(t++)=(value/(256*256))&255; + *(unsigned char *)(t)=(value/(256*256*256))&255; + return 4; +} + +int Generator::fillData(char *start, int frequency, int seconds) +{ + int i, len=0; + int value; + for(i=0; i 16384) + len = 16384; + + if(len < (SECONDS*44100*4+1000)-pos) { + // Normal + memcpy(data,t+pos,len); + pos+=len; + return len; + } else { + // Whats left and reset to start + qint64 left = (SECONDS*44100*4+1000)-pos; + memcpy(data,t+pos,left); + pos=0; + return left; + } +} + +qint64 Generator::writeData(const char *data, qint64 len) +{ + Q_UNUSED(data); + Q_UNUSED(len); + + return 0; +} + +AudioTest::AudioTest() +{ + QWidget *window = new QWidget; + QVBoxLayout* layout = new QVBoxLayout; + + deviceBox = new QComboBox(this); + QList devices = QAudioDeviceInfo::deviceList(QAudio::AudioOutput); + for(int i = 0; i < devices.size(); ++i) { + deviceBox->addItem(QAudioDeviceInfo(devices.at(i)).deviceName(), qVariantFromValue(devices.at(i))); + } + connect(deviceBox,SIGNAL(activated(int)),SLOT(deviceChanged(int))); + layout->addWidget(deviceBox); + + button = new QPushButton(this); + button->setText(tr("Click for Push Mode")); + connect(button,SIGNAL(clicked()),SLOT(toggle())); + layout->addWidget(button); + + button2 = new QPushButton(this); + button2->setText(tr("Click To Suspend")); + connect(button2,SIGNAL(clicked()),SLOT(togglePlay())); + layout->addWidget(button2); + + window->setLayout(layout); + setCentralWidget(window); + window->show(); + + buffer = new char[BUFFER_SIZE]; + + gen = new Generator(this); + + pullMode = true; + + timer = new QTimer(this); + connect(timer,SIGNAL(timeout()),SLOT(writeMore())); + + gen->start(); + + settings.setFrequency(44100); + settings.setChannels(2); + settings.setSampleSize(16); + settings.setCodec("audio/pcm"); + settings.setByteOrder(QAudioFormat::LittleEndian); + settings.setSampleType(QAudioFormat::SignedInt); + audioOutput = new QAudioOutput(settings,this); + connect(audioOutput,SIGNAL(notify()),SLOT(status())); + connect(audioOutput,SIGNAL(stateChanged(QAudio::State)),SLOT(state(QAudio::State))); + + audioOutput->start(gen); +} + +AudioTest::~AudioTest() +{ + delete [] buffer; +} + +void AudioTest::deviceChanged(int idx) +{ + timer->stop(); + gen->stop(); + audioOutput->stop(); + audioOutput->disconnect(this); + delete audioOutput; + + device = deviceBox->itemData(idx).value(); + audioOutput = new QAudioOutput(device,settings,this); + connect(audioOutput,SIGNAL(notify()),SLOT(status())); + connect(audioOutput,SIGNAL(stateChanged(QAudio::State)),SLOT(state(QAudio::State))); + gen->start(); + audioOutput->start(gen); +} + +void AudioTest::status() +{ + qWarning()<<"byteFree = "<bytesFree()<<" bytes, clock = "<clock()<<"ms, totalTime = "<totalTime()/1000<<"ms"; +} + +void AudioTest::writeMore() +{ + if(!audioOutput) + return; + + if(audioOutput->state() == QAudio::StopState) + return; + + int l; + int out; + + int chunks = audioOutput->bytesFree()/audioOutput->periodSize(); + while(chunks) { + l = gen->read(buffer,audioOutput->periodSize()); + if(l > 0) + out = output->write(buffer,l); + if(l != audioOutput->periodSize()) + break; + chunks--; + } +} + +void AudioTest::toggle() +{ + // Change between pull and push modes + + timer->stop(); + audioOutput->stop(); + + if (pullMode) { + button->setText("Click for Pull Mode"); + output = audioOutput->start(0); + pullMode = false; + timer->start(20); + } else { + button->setText("Click for Push Mode"); + pullMode = true; + audioOutput->start(gen); + } +} + +void AudioTest::togglePlay() +{ + // toggle suspend/resume + if(audioOutput->state() == QAudio::SuspendState) { + qWarning()<<"status: Suspended, resume()"; + audioOutput->resume(); + button2->setText("Click To Suspend"); + } else if (audioOutput->state() == QAudio::ActiveState) { + qWarning()<<"status: Active, suspend()"; + audioOutput->suspend(); + button2->setText("Click To Resume"); + } else if (audioOutput->state() == QAudio::StopState) { + qWarning()<<"status: Stopped, resume()"; + audioOutput->resume(); + button2->setText("Click To Suspend"); + } else if (audioOutput->state() == QAudio::IdleState) { + qWarning()<<"status: IdleState"; + } +} + +void AudioTest::state(QAudio::State state) +{ + qWarning()<<" state="< + +#define BUFFER_SIZE 32768 +#define SECONDS 3 + +#include +#include +#include +#include +#include +#include + +#include + +class Generator : public QIODevice +{ + Q_OBJECT +public: + Generator(QObject *parent); + ~Generator(); + + void start(); + void stop(); + + char *t; + int len; + int pos; + int total; + char *buffer; + bool finished; + int chunk_size; + + qint64 readData(char *data, qint64 maxlen); + qint64 writeData(const char *data, qint64 len); + +private: + int putShort(char *t, unsigned int value); + int putLong(char *t, unsigned int value); + int fillData(char *start, int frequency, int seconds); +}; + +class AudioTest : public QMainWindow +{ + Q_OBJECT +public: + AudioTest(); + ~AudioTest(); + + QAudioDeviceId device; + Generator* gen; + QAudioOutput* audioOutput; + QIODevice* output; + QTimer* timer; + QAudioFormat settings; + + bool pullMode; + char* buffer; + + QPushButton* button; + QPushButton* button2; + QComboBox* deviceBox; + +private slots: + void status(); + void writeMore(); + void toggle(); + void togglePlay(); + void state(QAudio::State s); + void deviceChanged(int idx); +}; + diff --git a/examples/multimedia/audio/audiooutput/audiooutput.pro b/examples/multimedia/audio/audiooutput/audiooutput.pro new file mode 100644 index 000000000..08f43ce9e --- /dev/null +++ b/examples/multimedia/audio/audiooutput/audiooutput.pro @@ -0,0 +1,11 @@ +HEADERS = audiooutput.h +SOURCES = audiooutput.cpp \ + main.cpp + +QT += multimedia + +# install +target.path = $$[QT_INSTALL_EXAMPLES]/multimedia/audio/audiooutput +sources.files = $$SOURCES *.h $$RESOURCES $$FORMS audiooutput.pro +sources.path = $$[QT_INSTALL_EXAMPLES]/multimedia/audio/audiooutput +INSTALLS += target sources diff --git a/examples/multimedia/audio/audiooutput/main.cpp b/examples/multimedia/audio/audiooutput/main.cpp new file mode 100644 index 000000000..fc319bd56 --- /dev/null +++ b/examples/multimedia/audio/audiooutput/main.cpp @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include + +#include "audiooutput.h" + +int main(int argv, char **args) +{ + QApplication app(argv, args); + app.setApplicationName("Audio Output Test"); + + AudioTest audio; + audio.show(); + + return app.exec(); +} diff --git a/examples/multimedia/multimedia.pro b/examples/multimedia/multimedia.pro new file mode 100644 index 000000000..ac78b15b4 --- /dev/null +++ b/examples/multimedia/multimedia.pro @@ -0,0 +1,8 @@ +TEMPLATE = subdirs +SUBDIRS = audio + +# install +target.path = $$[QT_INSTALL_EXAMPLES]/multimedia +sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS multimedia.pro README +sources.path = $$[QT_INSTALL_EXAMPLES]/multimedia +INSTALLS += target sources diff --git a/mkspecs/features/qt.prf b/mkspecs/features/qt.prf index 1bac953fa..a03a3139d 100644 --- a/mkspecs/features/qt.prf +++ b/mkspecs/features/qt.prf @@ -36,7 +36,7 @@ INCLUDEPATH = $$QMAKE_INCDIR_QT $$INCLUDEPATH #prepending prevents us from picki win32:INCLUDEPATH += $$QMAKE_INCDIR_QT/ActiveQt # As order does matter for static libs, we reorder the QT variable here -TMPLIBS = webkit phonon dbus testlib script scripttools svg qt3support sql xmlpatterns xml egl opengl openvg gui network core +TMPLIBS = multimedia webkit phonon dbus testlib script scripttools svg qt3support sql xmlpatterns xml egl opengl openvg gui network core for(QTLIB, $$list($$TMPLIBS)) { contains(QT, $$QTLIB): QT_ORDERED += $$QTLIB } @@ -152,6 +152,7 @@ for(QTLIB, $$list($$lower($$unique(QT)))) { else:isEqual(QTLIB, dbus):qlib = QtDBus else:isEqual(QTLIB, phonon):qlib = phonon else:isEqual(QTLIB, webkit):qlib = QtWebKit + else:isEqual(QTLIB, multimedia):qlib = QtMultimedia else:message("Unknown QT: $$QTLIB"):qlib = !isEmpty(qlib) { target_qt:isEqual(TARGET, qlib) { diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h index 18d5a9f80..1711f1671 100644 --- a/src/corelib/global/qglobal.h +++ b/src/corelib/global/qglobal.h @@ -1173,6 +1173,11 @@ class QDataStream; # else # define Q_OPENGL_EXPORT Q_DECL_IMPORT # endif +# if defined(QT_BUILD_MULTIMEDIA_LIB) +# define Q_MULTIMEDIA_EXPORT Q_DECL_EXPORT +# else +# define Q_MULTIMEDIA_EXPORT Q_DECL_IMPORT +# endif # if defined(QT_BUILD_OPENVG_LIB) # define Q_OPENVG_EXPORT Q_DECL_EXPORT # else @@ -1217,6 +1222,7 @@ class QDataStream; # define Q_SVG_EXPORT Q_DECL_IMPORT # define Q_CANVAS_EXPORT Q_DECL_IMPORT # define Q_OPENGL_EXPORT Q_DECL_IMPORT +# define Q_MULTIMEDIA_EXPORT Q_DECL_IMPORT # define Q_OPENVG_EXPORT Q_DECL_IMPORT # define Q_XML_EXPORT Q_DECL_IMPORT # define Q_XMLPATTERNS_EXPORT Q_DECL_IMPORT @@ -1243,6 +1249,7 @@ class QDataStream; # define Q_NETWORK_EXPORT Q_DECL_EXPORT # define Q_SVG_EXPORT Q_DECL_EXPORT # define Q_OPENGL_EXPORT Q_DECL_EXPORT +# define Q_MULTIMEDIA_EXPORT Q_DECL_EXPORT # define Q_OPENVG_EXPORT Q_DECL_EXPORT # define Q_XML_EXPORT Q_DECL_EXPORT # define Q_XMLPATTERNS_EXPORT Q_DECL_EXPORT @@ -1256,6 +1263,7 @@ class QDataStream; # define Q_NETWORK_EXPORT # define Q_SVG_EXPORT # define Q_OPENGL_EXPORT +# define Q_MULTIMEDIA_EXPORT # define Q_XML_EXPORT # define Q_XMLPATTERNS_EXPORT # define Q_SCRIPT_EXPORT @@ -2305,12 +2313,14 @@ QT3_SUPPORT Q_CORE_EXPORT const char *qInstallPathSysconf(); #define QT_MODULE_DBUS 0x08000 #define QT_MODULE_SCRIPTTOOLS 0x10000 #define QT_MODULE_OPENVG 0x20000 +#define QT_MODULE_MULTIMEDIA 0x40000 /* Qt editions */ #define QT_EDITION_CONSOLE (QT_MODULE_CORE \ | QT_MODULE_NETWORK \ | QT_MODULE_SQL \ | QT_MODULE_SCRIPT \ + | QT_MODULE_MULTIMEDIA \ | QT_MODULE_XML \ | QT_MODULE_XMLPATTERNS \ | QT_MODULE_TEST \ @@ -2326,6 +2336,7 @@ QT3_SUPPORT Q_CORE_EXPORT const char *qInstallPathSysconf(); | QT_MODULE_OPENGL \ | QT_MODULE_OPENVG \ | QT_MODULE_SQL \ + | QT_MODULE_MULTIMEDIA \ | QT_MODULE_XML \ | QT_MODULE_XMLPATTERNS \ | QT_MODULE_SCRIPT \ @@ -2374,6 +2385,9 @@ QT_LICENSED_MODULE(OpenVG) #if (QT_EDITION & QT_MODULE_SQL) QT_LICENSED_MODULE(Sql) #endif +#if (QT_EDITION & QT_MODULE_MULTIMEDIA) +QT_LICENSED_MODULE(Multimedia) +#endif #if (QT_EDITION & QT_MODULE_XML) QT_LICENSED_MODULE(Xml) #endif diff --git a/src/multimedia/audio/audio.pri b/src/multimedia/audio/audio.pri new file mode 100644 index 000000000..3ddb23b80 --- /dev/null +++ b/src/multimedia/audio/audio.pri @@ -0,0 +1,56 @@ +HEADERS += $$PWD/qaudio.h \ + $$PWD/qaudioformat.h \ + $$PWD/qaudioinput.h \ + $$PWD/qaudiooutput.h \ + $$PWD/qaudiodeviceinfo.h \ + $$PWD/qaudioengineplugin.h \ + $$PWD/qaudioengine.h \ + $$PWD/qaudiodevicefactory_p.h \ + $$PWD/qaudiodeviceid.h \ + $$PWD/qaudiodeviceid_p.h + + +SOURCES += $$PWD/qaudio.cpp \ + $$PWD/qaudioformat.cpp \ + $$PWD/qaudiodeviceinfo.cpp \ + $$PWD/qaudiooutput.cpp \ + $$PWD/qaudioinput.cpp \ + $$PWD/qaudioengineplugin.cpp \ + $$PWD/qaudioengine.cpp \ + $$PWD/qaudiodevicefactory.cpp \ + $$PWD/qaudiodeviceid.cpp + +mac { + HEADERS += $$PWD/qaudioinput_mac_p.h \ + $$PWD/qaudiooutput_mac_p.h \ + $$PWD/qaudiodeviceinfo_mac_p.h \ + $$PWD/qaudio_mac_p.h + + SOURCES += $$PWD/qaudiodeviceinfo_mac_p.cpp \ + $$PWD/qaudiooutput_mac_p.cpp \ + $$PWD/qaudioinput_mac_p.cpp \ + $$PWD/qaudio_mac.cpp + + LIBS += -framework CoreAudio -framework AudioUnit -framework AudioToolbox + +} else:win32 { + + HEADERS += $$PWD/qaudioinput_win32_p.h $$PWD/qaudiooutput_win32_p.h $$PWD/qaudiodeviceinfo_win32_p.h + SOURCES += $$PWD/qaudiodeviceinfo_win32_p.cpp \ + $$PWD/qaudiooutput_win32_p.cpp \ + $$PWD/qaudioinput_win32_p.cpp + !wince*:LIBS += -lwinmm + wince*:LIBS += -lcoredll + +} else:unix { + unix:contains(QT_CONFIG, alsa) { + linux-*|freebsd-*|openbsd-*:{ + DEFINES += HAS_ALSA + HEADERS += $$PWD/qaudiooutput_alsa_p.h $$PWD/qaudioinput_alsa_p.h $$PWD/qaudiodeviceinfo_alsa_p.h + SOURCES += $$PWD/qaudiodeviceinfo_alsa_p.cpp \ + $$PWD/qaudiooutput_alsa_p.cpp \ + $$PWD/qaudioinput_alsa_p.cpp + LIBS += -lasound + } + } +} diff --git a/src/multimedia/audio/qaudio.cpp b/src/multimedia/audio/qaudio.cpp new file mode 100644 index 000000000..5ba6493f0 --- /dev/null +++ b/src/multimedia/audio/qaudio.cpp @@ -0,0 +1,102 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include + + +QT_BEGIN_NAMESPACE + +namespace QAudio +{ + +class RegisterMetaTypes +{ +public: + RegisterMetaTypes() + { + qRegisterMetaType(); + qRegisterMetaType(); + qRegisterMetaType(); + } + +} _register; + +} + +/*! + \namespace QAudio + \brief The QAudio namespace contains enums used by the audio classes. + \since 4.6 +*/ + +/*! + \enum QAudio::Error + + \value NoError No errors have occurred + \value OpenError An error opening the audio device + \value IOError An error occurred during read/write of audio device + \value UnderrunError Audio data is not being fed to the audio device at a fast enough rate + \value FatalError A non-recoverable error has occurred, the audio device is not usable at this time. +*/ + +/*! + \enum QAudio::State + + \value ActiveState Audio data is being processed, this state is set after start() is called + and while audio data is available to be processed. + \value SuspendState The audio device is in a suspended state, this state will only be entered + after suspend() is called. + \value StopState The audio device is closed, not processing any audio data + \value IdleState The QIODevice passed in has no data and audio system's buffer is empty, this state + is set after start() is called and while no audio data is available to be processed. +*/ + +/*! + \enum QAudio::Mode + + \value AudioOutput audio output device + \value AudioInput audio input device +*/ + + +QT_END_NAMESPACE + diff --git a/src/multimedia/audio/qaudio.h b/src/multimedia/audio/qaudio.h new file mode 100644 index 000000000..b996cc6a0 --- /dev/null +++ b/src/multimedia/audio/qaudio.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QAUDIO_H +#define QAUDIO_H + + +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + +namespace QAudio +{ + enum Error { NoError, OpenError, IOError, UnderrunError, FatalError }; + enum State { ActiveState, SuspendState, StopState, IdleState }; + enum Mode { AudioInput, AudioOutput }; +} + +QT_END_NAMESPACE + +QT_END_HEADER + +Q_DECLARE_METATYPE(QAudio::Error); +Q_DECLARE_METATYPE(QAudio::State); +Q_DECLARE_METATYPE(QAudio::Mode); + +#endif // QAUDIO_H diff --git a/src/multimedia/audio/qaudio_mac.cpp b/src/multimedia/audio/qaudio_mac.cpp new file mode 100644 index 000000000..cfa7ca313 --- /dev/null +++ b/src/multimedia/audio/qaudio_mac.cpp @@ -0,0 +1,142 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include "qaudio_mac_p.h" + +QT_BEGIN_NAMESPACE + +// Debugging +QDebug operator<<(QDebug dbg, const QAudioFormat& audioFormat) +{ + dbg.nospace() << "QAudioFormat(" << + audioFormat.frequency() << "," << + audioFormat.channels() << "," << + audioFormat.sampleSize()<< "," << + audioFormat.codec() << "," << + audioFormat.byteOrder() << "," << + audioFormat.sampleType() << ")"; + + return dbg.space(); +} + + +// Conversion +QAudioFormat toQAudioFormat(AudioStreamBasicDescription const& sf) +{ + QAudioFormat audioFormat; + + audioFormat.setFrequency(sf.mSampleRate); + audioFormat.setChannels(sf.mChannelsPerFrame); + audioFormat.setSampleSize(sf.mBitsPerChannel); + audioFormat.setCodec(QString::fromLatin1("audio/pcm")); + audioFormat.setByteOrder(sf.mFormatFlags & kLinearPCMFormatFlagIsBigEndian != 0 ? QAudioFormat::BigEndian : QAudioFormat::LittleEndian); + QAudioFormat::SampleType type = QAudioFormat::UnSignedInt; + if ((sf.mFormatFlags & kLinearPCMFormatFlagIsSignedInteger) != 0) + type = QAudioFormat::SignedInt; + else if ((sf.mFormatFlags & kLinearPCMFormatFlagIsFloat) != 0) + type = QAudioFormat::Float; + audioFormat.setSampleType(type); + + return audioFormat; +} + +AudioStreamBasicDescription toAudioStreamBasicDescription(QAudioFormat const& audioFormat) +{ + AudioStreamBasicDescription sf; + + sf.mFormatFlags = kAudioFormatFlagIsPacked; + sf.mSampleRate = audioFormat.frequency(); + sf.mFramesPerPacket = 1; + sf.mChannelsPerFrame = audioFormat.channels(); + sf.mBitsPerChannel = audioFormat.sampleSize(); + sf.mBytesPerFrame = sf.mChannelsPerFrame * (sf.mBitsPerChannel / 8); + sf.mBytesPerPacket = sf.mFramesPerPacket * sf.mBytesPerFrame; + sf.mFormatID = kAudioFormatLinearPCM; + + switch (audioFormat.sampleType()) { + case QAudioFormat::SignedInt: sf.mFormatFlags |= kAudioFormatFlagIsSignedInteger; break; + case QAudioFormat::UnSignedInt: /* default */ break; + case QAudioFormat::Float: sf.mFormatFlags |= kAudioFormatFlagIsFloat; break; + case QAudioFormat::Unknown: default: break; + } + + return sf; +} + +// QAudioRingBuffer +QAudioRingBuffer::QAudioRingBuffer(int bufferSize): + m_bufferSize(bufferSize) +{ + m_buffer = new char[m_bufferSize]; + reset(); +} + +QAudioRingBuffer::~QAudioRingBuffer() +{ + delete m_buffer; +} + +int QAudioRingBuffer::used() const +{ + return m_bufferUsed; +} + +int QAudioRingBuffer::free() const +{ + return m_bufferSize - m_bufferUsed; +} + +int QAudioRingBuffer::size() const +{ + return m_bufferSize; +} + +void QAudioRingBuffer::reset() +{ + m_readPos = 0; + m_writePos = 0; + m_bufferUsed = 0; +} + +QT_END_NAMESPACE + + diff --git a/src/multimedia/audio/qaudio_mac_p.h b/src/multimedia/audio/qaudio_mac_p.h new file mode 100644 index 000000000..8e2d522e5 --- /dev/null +++ b/src/multimedia/audio/qaudio_mac_p.h @@ -0,0 +1,144 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + + +#ifndef QAUDIO_MAC_P_H +#define QAUDIO_MAC_P_H + +#include + +#include +#include + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +extern QDebug operator<<(QDebug dbg, const QAudioFormat& audioFormat); + +extern QAudioFormat toQAudioFormat(const AudioStreamBasicDescription& streamFormat); +extern AudioStreamBasicDescription toAudioStreamBasicDescription(QAudioFormat const& audioFormat); + +class QAudioRingBuffer +{ +public: + typedef QPair Region; + + QAudioRingBuffer(int bufferSize); + ~QAudioRingBuffer(); + + Region acquireReadRegion(int size) + { + const int used = m_bufferUsed.fetchAndAddAcquire(0); + + if (used > 0) { + const int readSize = qMin(size, qMin(m_bufferSize - m_readPos, used)); + + return readSize > 0 ? Region(m_buffer + m_readPos, readSize) : Region(0, 0); + } + + return Region(0, 0); + } + + void releaseReadRegion(Region const& region) + { + m_readPos = (m_readPos + region.second) % m_bufferSize; + + m_bufferUsed.fetchAndAddRelease(-region.second); + } + + Region acquireWriteRegion(int size) + { + const int free = m_bufferSize - m_bufferUsed.fetchAndAddAcquire(0); + + if (free > 0) { + const int writeSize = qMin(size, qMin(m_bufferSize - m_writePos, free)); + + return writeSize > 0 ? Region(m_buffer + m_writePos, writeSize) : Region(0, 0); + } + + return Region(0, 0); + } + + void releaseWriteRegion(Region const& region) + { + m_writePos = (m_writePos + region.second) % m_bufferSize; + + m_bufferUsed.fetchAndAddRelease(region.second); + } + + int used() const; + int free() const; + int size() const; + + void reset(); + +private: + int m_bufferSize; + int m_readPos; + int m_writePos; + char* m_buffer; + QAtomicInt m_bufferUsed; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QAUDIO_MAC_P_H + + diff --git a/src/multimedia/audio/qaudiodevicefactory.cpp b/src/multimedia/audio/qaudiodevicefactory.cpp new file mode 100644 index 000000000..35e9c9151 --- /dev/null +++ b/src/multimedia/audio/qaudiodevicefactory.cpp @@ -0,0 +1,250 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include "qaudiodevicefactory_p.h" +#include "qaudiodeviceid_p.h" + +#if defined(Q_OS_WIN) +#include "qaudiodeviceinfo_win32_p.h" +#include "qaudiooutput_win32_p.h" +#include "qaudioinput_win32_p.h" +#elif defined(Q_OS_MAC) +#include "qaudiodeviceinfo_mac_p.h" +#include "qaudiooutput_mac_p.h" +#include "qaudioinput_mac_p.h" +#elif defined(HAS_ALSA) +#include "qaudiodeviceinfo_alsa_p.h" +#include "qaudiooutput_alsa_p.h" +#include "qaudioinput_alsa_p.h" +#endif + +QT_BEGIN_NAMESPACE + +Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader, + (QAudioEngineFactoryInterface_iid, QLatin1String("/audio"), Qt::CaseInsensitive)) + + +class QNullDeviceInfo : public QAbstractAudioDeviceInfo +{ +public: + QAudioFormat preferredFormat() const { qWarning()<<"using null deviceinfo, none available"; return QAudioFormat(); } + bool isFormatSupported(const QAudioFormat& ) const { return false; } + QAudioFormat nearestFormat(const QAudioFormat& ) const { return QAudioFormat(); } + QString deviceName() const { return QString(); } + QStringList codecList() { return QStringList(); } + QList frequencyList() { return QList(); } + QList channelsList() { return QList(); } + QList sampleSizeList() { return QList(); } + QList byteOrderList() { return QList(); } + QList sampleTypeList() { return QList(); } +}; + +class QNullInputDevice : public QAbstractAudioInput +{ +public: + QIODevice* start(QIODevice* ) { qWarning()<<"using null input device, none available"; return 0; } + void stop() {} + void reset() {} + void suspend() {} + void resume() {} + int bytesReady() const { return 0; } + int periodSize() const { return 0; } + void setBufferSize(int ) {} + int bufferSize() const { return 0; } + void setNotifyInterval(int ) {} + int notifyInterval() const { return 0; } + qint64 totalTime() const { return 0; } + qint64 clock() const { return 0; } + QAudio::Error error() const { return QAudio::OpenError; } + QAudio::State state() const { return QAudio::StopState; } + QAudioFormat format() const { return QAudioFormat(); } +}; + +class QNullOutputDevice : public QAbstractAudioOutput +{ +public: + QIODevice* start(QIODevice* ) { qWarning()<<"using null output device, none available"; return 0; } + void stop() {} + void reset() {} + void suspend() {} + void resume() {} + int bytesFree() const { return 0; } + int periodSize() const { return 0; } + void setBufferSize(int ) {} + int bufferSize() const { return 0; } + void setNotifyInterval(int ) {} + int notifyInterval() const { return 0; } + qint64 totalTime() const { return 0; } + qint64 clock() const { return 0; } + QAudio::Error error() const { return QAudio::OpenError; } + QAudio::State state() const { return QAudio::StopState; } + QAudioFormat format() const { return QAudioFormat(); } +}; + +QList QAudioDeviceFactory::deviceList(QAudio::Mode mode) +{ + QList devices; +#if (defined(Q_OS_WIN) || defined(Q_OS_MAC) || defined(HAS_ALSA)) + foreach (const QByteArray &handle, QAudioDeviceInfoPrivate::deviceList(mode)) + devices += createDeviceId(QLatin1String("builtin"), mode, handle); +#endif + QFactoryLoader* l = loader(); + + foreach (QString const& key, l->keys()) { + QAudioEngineFactoryInterface* plugin = qobject_cast(l->instance(key)); + if (plugin) { + foreach (QByteArray const& handle, plugin->deviceList(mode)) + devices += createDeviceId(key, mode, handle); + } + + delete plugin; + } + + return devices; +} + +QAudioDeviceId QAudioDeviceFactory::defaultInputDevice() +{ + QAudioEngineFactoryInterface* plugin = qobject_cast(loader()->instance(QLatin1String("default"))); + + if (plugin) { + QList list = plugin->deviceList(QAudio::AudioInput); + if (list.size() > 0) + return createDeviceId(QLatin1String("default"), QAudio::AudioInput, list.at(0)); + } +#if (defined(Q_OS_WIN) || defined(Q_OS_MAC) || defined(HAS_ALSA)) + return createDeviceId(QLatin1String("builtin"), QAudio::AudioInput, QAudioDeviceInfoPrivate::defaultInputDevice()); +#endif + return QAudioDeviceId(); +} + +QAudioDeviceId QAudioDeviceFactory::defaultOutputDevice() +{ + QAudioEngineFactoryInterface* plugin = qobject_cast(loader()->instance(QLatin1String("default"))); + + if (plugin) { + QList list = plugin->deviceList(QAudio::AudioOutput); + if (list.size() > 0) + return createDeviceId(QLatin1String("default"), QAudio::AudioOutput, list.at(0)); + } +#if (defined(Q_OS_WIN) || defined(Q_OS_MAC) || defined(HAS_ALSA)) + return createDeviceId(QLatin1String("builtin"), QAudio::AudioOutput, QAudioDeviceInfoPrivate::defaultOutputDevice()); +#endif + return QAudioDeviceId(); +} + +QAbstractAudioDeviceInfo* QAudioDeviceFactory::audioDeviceInfo(QAudioDeviceId const& id) +{ + if (id.isNull()) + return new QNullDeviceInfo(); +#if (defined(Q_OS_WIN) || defined(Q_OS_MAC) || defined(HAS_ALSA)) + if (id.d->key == QLatin1String("builtin")) + return new QAudioDeviceInfoPrivate(id.d->handle, QAudio::Mode(id.d->mode)); +#endif + QAudioEngineFactoryInterface* plugin = qobject_cast(loader()->instance(id.d->key)); + + if (plugin) + return plugin->createDeviceInfo(id.d->handle, QAudio::Mode(id.d->mode)); + + return new QNullDeviceInfo(); +} + +QAbstractAudioInput* QAudioDeviceFactory::createDefaultInputDevice(QAudioFormat const &format) +{ + return createInputDevice(defaultInputDevice(), format); +} + +QAbstractAudioOutput* QAudioDeviceFactory::createDefaultOutputDevice(QAudioFormat const &format) +{ + return createOutputDevice(defaultOutputDevice(), format); +} + +QAbstractAudioInput* QAudioDeviceFactory::createInputDevice(QAudioDeviceId const& id, QAudioFormat const &format) +{ + if (id.isNull()) + return new QNullInputDevice(); +#if (defined(Q_OS_WIN) || defined(Q_OS_MAC) || defined(HAS_ALSA)) + if (id.d->key == QLatin1String("builtin")) { + if(!defaultInputDevice().isNull()) + return new QAudioInputPrivate(id.d->handle, format); + else + return new QNullInputDevice(); + } +#endif + QAudioEngineFactoryInterface* plugin = qobject_cast(loader()->instance((id.d->key))); + + if (plugin) + return plugin->createInput(id.d->handle, format); + + return new QNullInputDevice(); +} + +QAbstractAudioOutput* QAudioDeviceFactory::createOutputDevice(QAudioDeviceId const& id, QAudioFormat const &format) +{ + if (id.isNull()) + return new QNullOutputDevice(); +#if (defined(Q_OS_WIN) || defined(Q_OS_MAC) || defined(HAS_ALSA)) + if (id.d->key == QLatin1String("builtin")) { + if(!defaultOutputDevice().isNull()) + return new QAudioOutputPrivate(id.d->handle, format); + else + return new QNullOutputDevice(); + } +#endif + QAudioEngineFactoryInterface* plugin = qobject_cast(loader()->instance(id.d->key)); + + if (plugin) + return plugin->createOutput(id.d->handle, format); + + return new QNullOutputDevice(); +} + +QAudioDeviceId QAudioDeviceFactory::createDeviceId(QString const& key, int mode, QByteArray const& handle) +{ + return QAudioDeviceId(new QAudioDeviceIdPrivate(key, mode, handle)); +} + +QT_END_NAMESPACE + diff --git a/src/multimedia/audio/qaudiodevicefactory_p.h b/src/multimedia/audio/qaudiodevicefactory_p.h new file mode 100644 index 000000000..a8e2b28ee --- /dev/null +++ b/src/multimedia/audio/qaudiodevicefactory_p.h @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QAUDIODEVICEFACTORY_P_H +#define QAUDIODEVICEFACTORY_P_H + +#include +#include +#include + +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + +class QAbstractAudioInput; +class QAbstractAudioOutput; + + +class QAudioDeviceFactory +{ +public: + static QList deviceList(QAudio::Mode mode); + + static QAudioDeviceId defaultInputDevice(); + static QAudioDeviceId defaultOutputDevice(); + + static QAbstractAudioDeviceInfo* audioDeviceInfo(QAudioDeviceId const &device); + + static QAbstractAudioInput* createDefaultInputDevice(QAudioFormat const &format); + static QAbstractAudioOutput* createDefaultOutputDevice(QAudioFormat const &format); + + static QAbstractAudioInput* createInputDevice(QAudioDeviceId const &device, QAudioFormat const &format); + static QAbstractAudioOutput* createOutputDevice(QAudioDeviceId const &device, QAudioFormat const &format); + + static QAbstractAudioInput* createNullInput(); + static QAbstractAudioOutput* createNullOutput(); + + static QAudioDeviceId createDeviceId(QString const& key, int mode, QByteArray const& handle); +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QAUDIODEVICEFACTORY_P_H + diff --git a/src/multimedia/audio/qaudiodeviceid.cpp b/src/multimedia/audio/qaudiodeviceid.cpp new file mode 100644 index 000000000..21a9cd81d --- /dev/null +++ b/src/multimedia/audio/qaudiodeviceid.cpp @@ -0,0 +1,168 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include + +#include +#include "qaudiodeviceid_p.h" + + +QT_BEGIN_NAMESPACE + +/*! + \class QAudioDeviceId + \brief The QAudioDeviceId class provides means for identifying a unique input or output device on a system. + + \inmodule QtMultimedia + \ingroup multimedia + \since 4.6 + + \sa QAudioDeviceInfo, QAudioOutput, QAudioInput +*/ + +/*! + Construct a new null QAudioDeviceId. +*/ + +QAudioDeviceId::QAudioDeviceId() +{ +} + +/*! + Copy the QAudDeviceId referenced by \a other. +*/ + +QAudioDeviceId::QAudioDeviceId(const QAudioDeviceId &other): + d(other.d) +{ +} + +/*! + Destroy the QAudioDeviceId. +*/ + +QAudioDeviceId::~QAudioDeviceId() +{ +} + +/*! + Make a copy of the \a other QAudioDeviceId. +*/ + +QAudioDeviceId& QAudioDeviceId::operator=(const QAudioDeviceId &other) +{ + d = other.d; + return *this; +} + +/*! + Compare with the \a other QAudioDeviceId, return true if they are the same; + otherwise false. +*/ + +bool QAudioDeviceId::operator==(const QAudioDeviceId &other) const +{ + return (d.constData() == 0 && other.d.constData() == 0) || + (d.constData() != 0 && other.d.constData() != 0 && + d->key == other.d->key && d->mode == other.d->mode && d->handle == other.d->handle); +} + +/*! + Compare with the \a other QAudioDeviceId, return false if they are the same; + otherwise true. +*/ + +bool QAudioDeviceId::operator!=(const QAudioDeviceId &other) const +{ + return !(*this == other); +} + +/*! + Returns true if this is not a valid QAudioDeviceId; otherwise false. +*/ + +bool QAudioDeviceId::isNull() const +{ + return d.constData() == 0; +} + +/*! + \internal +*/ + +QAudioDeviceId::QAudioDeviceId(QAudioDeviceIdPrivate* data): + d(data) +{ +} + +/*! + \internal +*/ + +QAudioDeviceIdPrivate::QAudioDeviceIdPrivate(QString const& k, int m, QByteArray const& h): + key(k), mode(m), handle(h) +{ +} + +#ifndef QT_NO_DATASTREAM +Q_MULTIMEDIA_EXPORT QDataStream &operator<<(QDataStream &s, const QAudioDeviceId &id) +{ + s << id.d->key << id.d->mode << id.d->handle; + return s; +} + +Q_MULTIMEDIA_EXPORT QDataStream &operator>>(QDataStream &s, QAudioDeviceId &id) +{ + QString key; + int mode; + QByteArray handle; + + s >> key >> mode >> handle; + id = QAudioDeviceId(new QAudioDeviceIdPrivate(key, mode, handle)); + + return s; +} +#endif + + +QT_END_NAMESPACE diff --git a/src/multimedia/audio/qaudiodeviceid.h b/src/multimedia/audio/qaudiodeviceid.h new file mode 100644 index 000000000..f9188d3ff --- /dev/null +++ b/src/multimedia/audio/qaudiodeviceid.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QAUDIODEVICEID_H +#define QAUDIODEVICEID_H + +#include +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QAudioDeviceFactory; +class QAudioDeviceIdPrivate; + +class Q_MULTIMEDIA_EXPORT QAudioDeviceId +{ + friend class QAudioDeviceFactory; + friend Q_MULTIMEDIA_EXPORT QDataStream &operator<<(QDataStream&, const QAudioDeviceId&); + friend Q_MULTIMEDIA_EXPORT QDataStream &operator>>(QDataStream&, QAudioDeviceId&); + +public: + QAudioDeviceId(); + QAudioDeviceId(const QAudioDeviceId &other); + ~QAudioDeviceId(); + + QAudioDeviceId& operator=(const QAudioDeviceId &other); + bool operator==(const QAudioDeviceId &id) const; + bool operator!=(const QAudioDeviceId &id) const; + + bool isNull() const; + +private: + QAudioDeviceId(QAudioDeviceIdPrivate *data); + + QSharedDataPointer d; +}; + +#ifndef QT_NO_DATASTREAM +Q_MULTIMEDIA_EXPORT QDataStream &operator<<(QDataStream&, const QAudioDeviceId&); +Q_MULTIMEDIA_EXPORT QDataStream &operator>>(QDataStream&, QAudioDeviceId&); +#endif + +QT_END_NAMESPACE + +QT_END_HEADER + +Q_DECLARE_METATYPE(QAudioDeviceId); + + +#endif // QAUDIODEVICEID_H diff --git a/src/multimedia/audio/qaudiodeviceid_p.h b/src/multimedia/audio/qaudiodeviceid_p.h new file mode 100644 index 000000000..303457476 --- /dev/null +++ b/src/multimedia/audio/qaudiodeviceid_p.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QAUDIODEVICEIDPRIVATE_H +#define QAUDIODEVICEIDPRIVATE_H + +#include +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QAudioDeviceIdPrivate : public QSharedData +{ +public: + QAudioDeviceIdPrivate(QString const& k, int m, QByteArray const& h); + + QString key; + int mode; + QByteArray handle; +}; + + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QAUDIODEVICEIDPRIVATE_H diff --git a/src/multimedia/audio/qaudiodeviceinfo.cpp b/src/multimedia/audio/qaudiodeviceinfo.cpp new file mode 100644 index 000000000..c1895d71d --- /dev/null +++ b/src/multimedia/audio/qaudiodeviceinfo.cpp @@ -0,0 +1,270 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qaudiodevicefactory_p.h" +#include +#include + + +QT_BEGIN_NAMESPACE + +/*! + \class QAudioDeviceInfo + \brief The QAudioDeviceInfo class provides an interface to query audio devices and their functionality. + + \inmodule QtMultimedia + \ingroup multimedia + \since 4.6 + + QAudioDeviceInfo lets you query for audio devices--such as sound + cards and USB headsets--that are currently available on the system. + The audio devices available are dependent on the platform or audio plugins installed. + + You can also query each device for the formats it supports. A + format in this context is a set consisting of a specific byte + order, channel, codec, frequency, sample rate, and sample type. A + format is represented by the QAudioFormat class. + + The values supported by the the device for each of these + parameters can be fetched with + supportedByteOrders(), supportedChannels(), supportedCodecs(), + supportedFrequencies(), supportedSampleSizes(), and + supportedSampleTypes(). The combinations supported are dependent on the platform, + audio plugins installed and the audio device capabilities. If you need a specific format, you can check if + the device supports it with isFormatSupported(), or fetch a + supported format that is as close as possible to the format with + nearestFormat(). + + A QAudioDeviceInfo is constructed with a QAudioDeviceId, which is + an identifier for a physical device. It is used by Qt to construct + classes that communicate with the device--such as + QAudioDeviceInfo, QAudioInput, and QAudioOutput. The static + functions defaultInputDevice(), defaultOutputDevice(), and + deviceList() let you get a hold of the ids for all available + devices. You fetch ids based on whether you will use the device + for input or output; this is specified by the QAudio::Mode enum. + The QAudioDeviceId returned are only valid for the QAudio::Mode. + + For instance: + + \code + foreach(QAudioDeviceId audioId, QAudioDeviceInfo::deviceList(QAudio::AudioOutput)) { + QAudioDeviceInfo info(audioId); + qDebug() << "Device name: " << info.deviceName(); + } + \endcode + + In this code sample, we loop through all devices that are able to output + sound, i.e., play an audio stream in a supported format. For each device we + find, we simply print the deviceName(). + + \sa QAudioOutput, QAudioInput, QAudioDeviceId +*/ + +/*! + Construct a new audio device info and attach it to \a parent. + Using the audio device with the specified \a id. +*/ + +QAudioDeviceInfo::QAudioDeviceInfo(const QAudioDeviceId &id, QObject *parent): + QObject(parent) +{ + d = QAudioDeviceFactory::audioDeviceInfo(id); +} + +/*! + Destroy this audio device info. +*/ + +QAudioDeviceInfo::~QAudioDeviceInfo() +{ + delete d; +} + +/*! + Returns human readable name of audio device. + + Device names vary depending on platform/audio plugin being used. + + They are a unique string identifiers for the audio device. + + eg. default, Intel, U0x46d0x9a4 +*/ + +QString QAudioDeviceInfo::deviceName() const +{ + return d->deviceName(); +} + +/*! + Returns true if \a settings are supported by the audio device of this QAudioDeviceInfo. +*/ + +bool QAudioDeviceInfo::isFormatSupported(const QAudioFormat &settings) const +{ + return d->isFormatSupported(settings); +} + +/*! + Returns QAudioFormat of default settings. + + These settings are provided by the platform/audio plugin being used. + + They also are dependent on the QAudio::Mode being used. + + A typical audio system would provide something like: + \list + \o Input settings: 8000Hz mono 8 bit. + \o Output settings: 44100Hz stereo 16 bit little endian. + \endlist +*/ + +QAudioFormat QAudioDeviceInfo::preferredFormat() const +{ + return d->preferredFormat(); +} + +/*! + Returns closest QAudioFormat to \a settings that system audio supports. + + These settings are provided by the platform/audio plugin being used. + + They also are dependent on the QAudio::Mode being used. +*/ + +QAudioFormat QAudioDeviceInfo::nearestFormat(const QAudioFormat &settings) const +{ + return d->nearestFormat(settings); +} + +/*! + Returns a list of supported codecs. + + All platform and plugin implementations should provide support for: + + "audio/pcm" - Linear PCM + + For writing plugins to support additional codecs refer to: + + http://www.iana.org/assignments/media-types/audio/ +*/ + +QStringList QAudioDeviceInfo::supportedCodecs() const +{ + return d->codecList(); +} + +/*! + Returns a list of supported frequencies. +*/ + +QList QAudioDeviceInfo::supportedFrequencies() const +{ + return d->frequencyList(); +} + +/*! + Returns a list of supported channels. +*/ + +QList QAudioDeviceInfo::supportedChannels() const +{ + return d->channelsList(); +} + +/*! + Returns a list of supported sample sizes. +*/ + +QList QAudioDeviceInfo::supportedSampleSizes() const +{ + return d->sampleSizeList(); +} + +/*! + Returns a list of supported byte orders. +*/ + +QList QAudioDeviceInfo::supportedByteOrders() const +{ + return d->byteOrderList(); +} + +/*! + Returns a list of supported sample types. +*/ + +QList QAudioDeviceInfo::supportedSampleTypes() const +{ + return d->sampleTypeList(); +} + +/*! + Returns the name of the default input audio device. + All platform and audio plugin implementations provide a default audio device to use. +*/ + +QAudioDeviceId QAudioDeviceInfo::defaultInputDevice() +{ + return QAudioDeviceFactory::defaultInputDevice(); +} + +/*! + Returns the name of the default output audio device. + All platform and audio plugin implementations provide a default audio device to use. +*/ + +QAudioDeviceId QAudioDeviceInfo::defaultOutputDevice() +{ + return QAudioDeviceFactory::defaultOutputDevice(); +} + +/*! + Returns a list of audio devices that support \a mode. +*/ + +QList QAudioDeviceInfo::deviceList(QAudio::Mode mode) +{ + return QAudioDeviceFactory::deviceList(mode); +} + +QT_END_NAMESPACE + diff --git a/src/multimedia/audio/qaudiodeviceinfo.h b/src/multimedia/audio/qaudiodeviceinfo.h new file mode 100644 index 000000000..444a00a7e --- /dev/null +++ b/src/multimedia/audio/qaudiodeviceinfo.h @@ -0,0 +1,102 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QAUDIODEVICEINFO_H +#define QAUDIODEVICEINFO_H + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QAbstractAudioDeviceInfo; + +class Q_MULTIMEDIA_EXPORT QAudioDeviceInfo : public QObject +{ + Q_OBJECT + +public: + explicit QAudioDeviceInfo(const QAudioDeviceId &id, QObject *parent = 0); + ~QAudioDeviceInfo(); + + QString deviceName() const; + + bool isFormatSupported(const QAudioFormat &format) const; + QAudioFormat preferredFormat() const; + QAudioFormat nearestFormat(const QAudioFormat &format) const; + + QStringList supportedCodecs() const; + QList supportedFrequencies() const; + QList supportedChannels() const; + QList supportedSampleSizes() const; + QList supportedByteOrders() const; + QList supportedSampleTypes() const; + + static QAudioDeviceId defaultInputDevice(); + static QAudioDeviceId defaultOutputDevice(); + + static QList deviceList(QAudio::Mode mode); + +private: + Q_DISABLE_COPY(QAudioDeviceInfo) + + QAbstractAudioDeviceInfo* d; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QAUDIODEVICEINFO_H diff --git a/src/multimedia/audio/qaudiodeviceinfo_alsa_p.cpp b/src/multimedia/audio/qaudiodeviceinfo_alsa_p.cpp new file mode 100644 index 000000000..fe45f829f --- /dev/null +++ b/src/multimedia/audio/qaudiodeviceinfo_alsa_p.cpp @@ -0,0 +1,394 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qaudiodeviceinfo_alsa_p.h" + +QAudioDeviceInfoPrivate::QAudioDeviceInfoPrivate(QByteArray dev, QAudio::Mode mode) +{ + handle = 0; + + device = QLatin1String(dev); + this->mode = mode; +} + +QAudioDeviceInfoPrivate::~QAudioDeviceInfoPrivate() +{ + close(); +} + +bool QAudioDeviceInfoPrivate::isFormatSupported(const QAudioFormat& format) const +{ + return testSettings(format); +} + +QAudioFormat QAudioDeviceInfoPrivate::preferredFormat() const +{ + QAudioFormat nearest; + if(mode == QAudio::AudioOutput) { + nearest.setFrequency(44100); + nearest.setChannels(2); + nearest.setByteOrder(QAudioFormat::LittleEndian); + nearest.setSampleType(QAudioFormat::SignedInt); + nearest.setSampleSize(16); + nearest.setCodec(tr("audio/pcm")); + } else { + nearest.setFrequency(8000); + nearest.setChannels(1); + nearest.setSampleType(QAudioFormat::SignedInt); + nearest.setSampleSize(8); + nearest.setCodec(tr("audio/pcm")); + } + return nearest; +} + +QAudioFormat QAudioDeviceInfoPrivate::nearestFormat(const QAudioFormat& format) const +{ + if(testSettings(format)) + return format; + else + return preferredFormat(); +} + +QString QAudioDeviceInfoPrivate::deviceName() const +{ + return device; +} + +QStringList QAudioDeviceInfoPrivate::codecList() +{ + updateLists(); + return codecz; +} + +QList QAudioDeviceInfoPrivate::frequencyList() +{ + updateLists(); + return freqz; +} + +QList QAudioDeviceInfoPrivate::channelsList() +{ + updateLists(); + return channelz; +} + +QList QAudioDeviceInfoPrivate::sampleSizeList() +{ + updateLists(); + return sizez; +} + +QList QAudioDeviceInfoPrivate::byteOrderList() +{ + updateLists(); + return byteOrderz; +} + +QList QAudioDeviceInfoPrivate::sampleTypeList() +{ + updateLists(); + return typez; +} + +bool QAudioDeviceInfoPrivate::open() +{ + int err = 0; + QString dev = device; + if(!dev.contains(tr("default"))) { + int idx = snd_card_get_index(dev.toLocal8Bit().constData()); + dev = QString(tr("hw:%1,0")).arg(idx); + } + if(mode == QAudio::AudioOutput) { + err=snd_pcm_open( &handle,dev.toLocal8Bit().constData(),SND_PCM_STREAM_PLAYBACK,0); + } else { + err=snd_pcm_open( &handle,dev.toLocal8Bit().constData(),SND_PCM_STREAM_CAPTURE,0); + } + if(err < 0) { + handle = 0; + return false; + } + return true; +} + +void QAudioDeviceInfoPrivate::close() +{ + if(handle) + snd_pcm_close(handle); + handle = 0; +} + +bool QAudioDeviceInfoPrivate::testSettings(const QAudioFormat& format) const +{ + // Set nearest to closest settings that do work. + // See if what is in settings will work (return value). + + int err = 0; + snd_pcm_t* handle; + snd_pcm_hw_params_t *params; + QString dev = device; + + // open() + if(!dev.contains(tr("default"))) { + int idx = snd_card_get_index(dev.toLocal8Bit().constData()); + dev = QString(tr("hw:%1,0")).arg(idx); + } + if(mode == QAudio::AudioOutput) { + err=snd_pcm_open( &handle,dev.toLocal8Bit().constData(),SND_PCM_STREAM_PLAYBACK,0); + } else { + err=snd_pcm_open( &handle,dev.toLocal8Bit().constData(),SND_PCM_STREAM_CAPTURE,0); + } + if(err < 0) { + handle = 0; + return false; + } + + bool testChannel = false; + bool testCodec = false; + bool testFreq = false; + bool testType = false; + bool testSize = false; + + int dir = 0; + + snd_pcm_nonblock( handle, 0 ); + snd_pcm_hw_params_alloca( ¶ms ); + snd_pcm_hw_params_any( handle, params ); + + // For now, just accept only audio/pcm codec + if(!format.codec().startsWith(tr("audio/pcm"))) { + err=-1; + } else + testCodec = true; + + if(err>=0 && format.channels() != -1) { + err = snd_pcm_hw_params_test_channels(handle,params,format.channels()); + if(err>=0) + err = snd_pcm_hw_params_set_channels(handle,params,format.channels()); + if(err>=0) + testChannel = true; + } + + if(err>=0 && format.frequency() != -1) { + err = snd_pcm_hw_params_test_rate(handle,params,format.frequency(),0); + if(err>=0) + err = snd_pcm_hw_params_set_rate(handle,params,format.frequency(),dir); + if(err>=0) + testFreq = true; + } + + if((err>=0 && format.sampleSize() != -1) && + (format.sampleType() != QAudioFormat::Unknown)) { + switch(format.sampleSize()) { + case 8: + if(format.sampleType() == QAudioFormat::SignedInt) + err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S8); + else if(format.sampleType() == QAudioFormat::UnSignedInt) + err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U8); + break; + case 16: + if(format.sampleType() == QAudioFormat::SignedInt) { + if(format.byteOrder() == QAudioFormat::LittleEndian) + err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S16_LE); + else if(format.byteOrder() == QAudioFormat::BigEndian) + err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S16_BE); + } else if(format.sampleType() == QAudioFormat::UnSignedInt) { + if(format.byteOrder() == QAudioFormat::LittleEndian) + err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U16_LE); + else if(format.byteOrder() == QAudioFormat::BigEndian) + err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U16_BE); + } + break; + case 32: + if(format.sampleType() == QAudioFormat::SignedInt) { + if(format.byteOrder() == QAudioFormat::LittleEndian) + err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S32_LE); + else if(format.byteOrder() == QAudioFormat::BigEndian) + err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S32_BE); + } else if(format.sampleType() == QAudioFormat::UnSignedInt) { + if(format.byteOrder() == QAudioFormat::LittleEndian) + err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U32_LE); + else if(format.byteOrder() == QAudioFormat::BigEndian) + err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U32_BE); + } + } + if(err>=0) { + testSize = true; + testType = true; + } + } + if(err>=0) + err = snd_pcm_hw_params(handle, params); + + if(err == 0) { + // settings work + // close() + if(handle) + snd_pcm_close(handle); + return true; + } + if(handle) + snd_pcm_close(handle); + + return false; +} + +void QAudioDeviceInfoPrivate::updateLists() +{ + // redo all lists based on current settings + freqz.clear(); + channelz.clear(); + sizez.clear(); + byteOrderz.clear(); + typez.clear(); + codecz.clear(); + + if(!handle) + open(); + + if(!handle) + return; + + for(int i=0; i<(int)MAX_SAMPLE_RATES; i++) { + //if(snd_pcm_hw_params_test_rate(handle, params, SAMPLE_RATES[i], dir) == 0) + freqz.append(SAMPLE_RATES[i]); + } + channelz.append(1); + channelz.append(2); + sizez.append(8); + sizez.append(16); + sizez.append(32); + byteOrderz.append(QAudioFormat::LittleEndian); + byteOrderz.append(QAudioFormat::BigEndian); + typez.append(QAudioFormat::SignedInt); + typez.append(QAudioFormat::UnSignedInt); + typez.append(QAudioFormat::Float); + codecz.append(tr("audio/pcm")); + close(); +} + +QList QAudioDeviceInfoPrivate::deviceList(QAudio::Mode mode) +{ + QAudio::Mode _m; + QList devices; + QByteArray filter; + QString dir; + + // Create a list of all current audio devices that support mode + void **hints, **n; + char *name, *descr, *io; + + if(snd_device_name_hint(-1, "pcm", &hints) < 0) { + qWarning()<<"no alsa devices available"; + return devices; + } + n = hints; + + while (*n != NULL) { + _m = QAudio::AudioOutput; + name = snd_device_name_get_hint(*n, "NAME"); + descr = snd_device_name_get_hint(*n, "DESC"); + io = snd_device_name_get_hint(*n, "IOID"); + dir = QString::fromUtf8(io); + if((name != NULL) && (descr != NULL) && ((io == NULL) || (dir.length() ==filter.length()))) { + if(dir.length() == 5) + _m = QAudio::AudioInput; + if(io == NULL) + _m = mode; + + QString str = tr(name); + + if(str.contains(tr("default"))) { + int pos = str.indexOf(tr("="),0); + devices.append(str.mid(pos+1).toLocal8Bit().constData()); + } + } + if(name != NULL) + free(name); + if(descr != NULL) + free(descr); + if(io != NULL) + free(io); + n++; + } + snd_device_name_free_hint(hints); + + if(devices.size() > 0) { + devices.append("default"); + if(mode == QAudio::AudioInput) { + filter.append("Input"); + } else { + filter.append("Output"); + } + } + + return devices; +} + +QByteArray QAudioDeviceInfoPrivate::defaultInputDevice() +{ + QList devices = deviceList(QAudio::AudioInput); + if(devices.size() == 0) + return QByteArray(); + + return QByteArray("default"); +} + +QByteArray QAudioDeviceInfoPrivate::defaultOutputDevice() +{ + QList devices = deviceList(QAudio::AudioOutput); + if(devices.size() == 0) + return QByteArray(); + + return QByteArray("default"); +} + + diff --git a/src/multimedia/audio/qaudiodeviceinfo_alsa_p.h b/src/multimedia/audio/qaudiodeviceinfo_alsa_p.h new file mode 100644 index 000000000..3ac92390d --- /dev/null +++ b/src/multimedia/audio/qaudiodeviceinfo_alsa_p.h @@ -0,0 +1,113 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + + +#ifndef QAUDIODEVICEINFOALSA_H +#define QAUDIODEVICEINFOALSA_H + +#include + +#include +#include +#include +#include + +#include +#include +#include + +const unsigned int MAX_SAMPLE_RATES = 5; +const unsigned int SAMPLE_RATES[] = + { 8000, 11025, 22050, 44100, 48000 }; + +class QAudioDeviceInfoPrivate : public QAbstractAudioDeviceInfo +{ + Q_OBJECT +public: + QAudioDeviceInfoPrivate(QByteArray dev,QAudio::Mode mode); + ~QAudioDeviceInfoPrivate(); + + bool testSettings(const QAudioFormat& format) const; + void updateLists(); + QAudioFormat preferredFormat() const; + bool isFormatSupported(const QAudioFormat& format) const; + QAudioFormat nearestFormat(const QAudioFormat& format) const; + QString deviceName() const; + QStringList codecList(); + QList frequencyList(); + QList channelsList(); + QList sampleSizeList(); + QList byteOrderList(); + QList sampleTypeList(); + static QByteArray defaultInputDevice(); + static QByteArray defaultOutputDevice(); + static QList deviceList(QAudio::Mode); + +private: + bool open(); + void close(); + + QString device; + QAudio::Mode mode; + QAudioFormat nearest; + QList freqz; + QList channelz; + QList sizez; + QList byteOrderz; + QStringList codecz; + QList typez; + snd_pcm_t* handle; + snd_pcm_hw_params_t *params; +}; + +#endif + diff --git a/src/multimedia/audio/qaudiodeviceinfo_mac_p.cpp b/src/multimedia/audio/qaudiodeviceinfo_mac_p.cpp new file mode 100644 index 000000000..c94e0c47b --- /dev/null +++ b/src/multimedia/audio/qaudiodeviceinfo_mac_p.cpp @@ -0,0 +1,357 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include +#include +#include +#include + +#include +#include "qaudio_mac_p.h" +#include "qaudiodeviceinfo_mac_p.h" + + + +QT_BEGIN_NAMESPACE + + +QAudioDeviceInfoPrivate::QAudioDeviceInfoPrivate(QByteArray const& handle, QAudio::Mode) +{ + QDataStream ds(handle); + quint32 did, tm; + + ds >> did >> tm >> name; + deviceId = AudioDeviceID(did); + mode = QAudio::Mode(tm); +} + +bool QAudioDeviceInfoPrivate::isFormatSupported(const QAudioFormat& format) const +{ + return format.codec() == QString::fromLatin1("audio/pcm"); +} + +QAudioFormat QAudioDeviceInfoPrivate::preferredFormat() const +{ + QAudioFormat rc; + + UInt32 propSize = 0; + + if (AudioDeviceGetPropertyInfo(deviceId, + 0, + mode == QAudio::AudioInput, + kAudioDevicePropertyStreams, + &propSize, + 0) == noErr) { + + const int sc = propSize / sizeof(AudioStreamID); + + if (sc > 0) { + AudioStreamID* streams = new AudioStreamID[sc]; + + if (AudioDeviceGetProperty(deviceId, + 0, + mode == QAudio::AudioInput, + kAudioDevicePropertyStreams, + &propSize, + streams) == noErr) { + + for (int i = 0; i < sc; ++i) { + if (AudioStreamGetPropertyInfo(streams[i], + 0, + kAudioStreamPropertyPhysicalFormat, + &propSize, + 0) == noErr) { + + AudioStreamBasicDescription sf; + + if (AudioStreamGetProperty(streams[i], + 0, + kAudioStreamPropertyPhysicalFormat, + &propSize, + &sf) == noErr) { + rc = toQAudioFormat(sf); + break; + } + } + } + } + + delete streams; + } + } + + return rc; +} + +QAudioFormat QAudioDeviceInfoPrivate::nearestFormat(const QAudioFormat& format) const +{ + QAudioFormat rc(format); + QAudioFormat target = preferredFormat(); + + if (!format.codec().isEmpty() && format.codec() != QString::fromLatin1("audio/pcm")) + return QAudioFormat(); + + rc.setCodec(QString::fromLatin1("audio/pcm")); + + if (rc.frequency() != target.frequency()) + rc.setFrequency(target.frequency()); + if (rc.channels() != target.channels()) + rc.setChannels(target.channels()); + if (rc.sampleSize() != target.sampleSize()) + rc.setSampleSize(target.sampleSize()); + if (rc.byteOrder() != target.byteOrder()) + rc.setByteOrder(target.byteOrder()); + if (rc.sampleType() != target.sampleType()) + rc.setSampleType(target.sampleType()); + + return rc; +} + +QString QAudioDeviceInfoPrivate::deviceName() const +{ + return name; +} + +QStringList QAudioDeviceInfoPrivate::codecList() +{ + return QStringList() << QString::fromLatin1("audio/pcm"); +} + +QList QAudioDeviceInfoPrivate::frequencyList() +{ + QSet rc; + + // Add some common frequencies + rc << 8000 << 11025 << 22050 << 44100; + + // + UInt32 propSize = 0; + + if (AudioDeviceGetPropertyInfo(deviceId, + 0, + mode == QAudio::AudioInput, + kAudioDevicePropertyAvailableNominalSampleRates, + &propSize, + 0) == noErr) { + + const int pc = propSize / sizeof(AudioValueRange); + + if (pc > 0) { + AudioValueRange* vr = new AudioValueRange[pc]; + + if (AudioDeviceGetProperty(deviceId, + 0, + mode == QAudio::AudioInput, + kAudioDevicePropertyAvailableNominalSampleRates, + &propSize, + vr) == noErr) { + + for (int i = 0; i < pc; ++i) + rc << vr[i].mMaximum; + } + + delete vr; + } + } + + return rc.toList(); +} + +QList QAudioDeviceInfoPrivate::channelsList() +{ + QList rc; + + // Can mix down to 1 channel + rc << 1; + + UInt32 propSize = 0; + int channels = 0; + + if (AudioDeviceGetPropertyInfo(deviceId, + 0, + mode == QAudio::AudioInput, + kAudioDevicePropertyStreamConfiguration, + &propSize, + 0) == noErr) { + + AudioBufferList* audioBufferList = static_cast(qMalloc(propSize)); + + if (audioBufferList != 0) { + if (AudioDeviceGetProperty(deviceId, + 0, + mode == QAudio::AudioInput, + kAudioDevicePropertyStreamConfiguration, + &propSize, + audioBufferList) == noErr) { + + for (int i = 0; i < int(audioBufferList->mNumberBuffers); ++i) { + channels += audioBufferList->mBuffers[i].mNumberChannels; + rc << channels; + } + } + + qFree(audioBufferList); + } + } + + return rc; +} + +QList QAudioDeviceInfoPrivate::sampleSizeList() +{ + return QList() << 8 << 16 << 24 << 32 << 64; +} + +QList QAudioDeviceInfoPrivate::byteOrderList() +{ + return QList() << QAudioFormat::LittleEndian << QAudioFormat::BigEndian; +} + +QList QAudioDeviceInfoPrivate::sampleTypeList() +{ + return QList() << QAudioFormat::SignedInt << QAudioFormat::UnSignedInt << QAudioFormat::Float; +} + +static QByteArray get_device_info(AudioDeviceID audioDevice, QAudio::Mode mode) +{ + UInt32 size; + QByteArray device; + QDataStream ds(&device, QIODevice::WriteOnly); + AudioStreamBasicDescription sf; + CFStringRef name; + Boolean isInput = mode == QAudio::AudioInput; + + // Id + ds << quint32(audioDevice); + + // Mode + size = sizeof(AudioStreamBasicDescription); + if (AudioDeviceGetProperty(audioDevice, 0, isInput, kAudioDevicePropertyStreamFormat, + &size, &sf) != noErr) { + return QByteArray(); + } + ds << quint32(mode); + + // Name + size = sizeof(CFStringRef); + if (AudioDeviceGetProperty(audioDevice, 0, isInput, kAudioObjectPropertyName, + &size, &name) != noErr) { + qWarning() << "QAudioDeviceInfo: Unable to find device name"; + } + ds << QCFString::toQString(name); + + CFRelease(name); + + return device; +} + +QByteArray QAudioDeviceInfoPrivate::defaultInputDevice() +{ + AudioDeviceID audioDevice; + UInt32 size = sizeof(audioDevice); + + if (AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &size, + &audioDevice) != noErr) { + qWarning() << "QAudioDeviceInfo: Unable to find default input device"; + return QByteArray(); + } + + return get_device_info(audioDevice, QAudio::AudioInput); +} + +QByteArray QAudioDeviceInfoPrivate::defaultOutputDevice() +{ + AudioDeviceID audioDevice; + UInt32 size = sizeof(audioDevice); + + if (AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &size, + &audioDevice) != noErr) { + qWarning() << "QAudioDeviceInfo: Unable to find default output device"; + return QByteArray(); + } + + return get_device_info(audioDevice, QAudio::AudioOutput); +} + +QList QAudioDeviceInfoPrivate::deviceList(QAudio::Mode mode) +{ + QList devices; + + UInt32 propSize = 0; + + if (AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &propSize, 0) == noErr) { + + const int dc = propSize / sizeof(AudioDeviceID); + + if (dc > 0) { + AudioDeviceID* audioDevices = new AudioDeviceID[dc]; + + if (AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &propSize, audioDevices) == noErr) { + for (int i = 0; i < dc; ++i) { + QByteArray info = get_device_info(audioDevices[i], mode); + if (!info.isNull()) + devices << info; + } + } + + delete audioDevices; + } + } + + return devices; +} + + +QT_END_NAMESPACE + diff --git a/src/multimedia/audio/qaudiodeviceinfo_mac_p.h b/src/multimedia/audio/qaudiodeviceinfo_mac_p.h new file mode 100644 index 000000000..ee593dee7 --- /dev/null +++ b/src/multimedia/audio/qaudiodeviceinfo_mac_p.h @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + + +#ifndef QDEVICEINFO_MAC_P_H +#define QDEVICEINFO_MAC_P_H + +#include + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QAudioDeviceInfoPrivate : public QAbstractAudioDeviceInfo +{ +public: + AudioDeviceID deviceId; + QString name; + QAudio::Mode mode; + + QAudioDeviceInfoPrivate(QByteArray const& handle, QAudio::Mode mode); + + bool isFormatSupported(const QAudioFormat& format) const; + QAudioFormat preferredFormat() const; + QAudioFormat nearestFormat(const QAudioFormat& format) const; + + QString deviceName() const; + + QStringList codecList(); + QList frequencyList(); + QList channelsList(); + QList sampleSizeList(); + QList byteOrderList(); + QList sampleTypeList(); + + static QByteArray defaultInputDevice(); + static QByteArray defaultOutputDevice(); + + static QList deviceList(QAudio::Mode mode); +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QDEVICEINFO_MAC_P_H diff --git a/src/multimedia/audio/qaudiodeviceinfo_win32_p.cpp b/src/multimedia/audio/qaudiodeviceinfo_win32_p.cpp new file mode 100644 index 000000000..1a1995aa7 --- /dev/null +++ b/src/multimedia/audio/qaudiodeviceinfo_win32_p.cpp @@ -0,0 +1,378 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + + +#include +#include +#include "qaudiodeviceinfo_win32_p.h" + +// For mingw toolchain mmsystem.h only defines half the defines, so add if needed. +#ifndef WAVE_FORMAT_44M08 +#define WAVE_FORMAT_44M08 0x00000100 +#define WAVE_FORMAT_44S08 0x00000200 +#define WAVE_FORMAT_44M16 0x00000400 +#define WAVE_FORMAT_44S16 0x00000800 +#define WAVE_FORMAT_48M08 0x00001000 +#define WAVE_FORMAT_48S08 0x00002000 +#define WAVE_FORMAT_48M16 0x00004000 +#define WAVE_FORMAT_48S16 0x00008000 +#define WAVE_FORMAT_96M08 0x00010000 +#define WAVE_FORMAT_96S08 0x00020000 +#define WAVE_FORMAT_96M16 0x00040000 +#define WAVE_FORMAT_96S16 0x00080000 +#endif + + +QAudioDeviceInfoPrivate::QAudioDeviceInfoPrivate(QByteArray dev, QAudio::Mode mode) +{ + device = QLatin1String(dev); + this->mode = mode; +} + +QAudioDeviceInfoPrivate::~QAudioDeviceInfoPrivate() +{ + close(); +} + +bool QAudioDeviceInfoPrivate::isFormatSupported(const QAudioFormat& format) const +{ + return testSettings(format); +} + +QAudioFormat QAudioDeviceInfoPrivate::preferredFormat() const +{ + QAudioFormat nearest; + if(mode == QAudio::AudioOutput) { + nearest.setFrequency(44100); + nearest.setChannels(2); + nearest.setByteOrder(QAudioFormat::LittleEndian); + nearest.setSampleType(QAudioFormat::SignedInt); + nearest.setSampleSize(16); + nearest.setCodec(tr("audio/pcm")); + } else { + nearest.setFrequency(11025); + nearest.setChannels(1); + nearest.setSampleType(QAudioFormat::SignedInt); + nearest.setSampleSize(8); + nearest.setCodec(tr("audio/pcm")); + } + return nearest; +} + +QAudioFormat QAudioDeviceInfoPrivate::nearestFormat(const QAudioFormat& format) const +{ + if(testSettings(format)) + return format; + else + return preferredFormat(); +} + +QString QAudioDeviceInfoPrivate::deviceName() const +{ + return device; +} + +QStringList QAudioDeviceInfoPrivate::codecList() +{ + updateLists(); + return codecz; +} + +QList QAudioDeviceInfoPrivate::frequencyList() +{ + updateLists(); + return freqz; +} + +QList QAudioDeviceInfoPrivate::channelsList() +{ + updateLists(); + return channelz; +} + +QList QAudioDeviceInfoPrivate::sampleSizeList() +{ + updateLists(); + return sizez; +} + +QList QAudioDeviceInfoPrivate::byteOrderList() +{ + updateLists(); + return byteOrderz; +} + +QList QAudioDeviceInfoPrivate::sampleTypeList() +{ + updateLists(); + return typez; +} + + +bool QAudioDeviceInfoPrivate::open() +{ + return true; +} + +void QAudioDeviceInfoPrivate::close() +{ +} + +bool QAudioDeviceInfoPrivate::testSettings(const QAudioFormat& format) const +{ + // Set nearest to closest settings that do work. + // See if what is in settings will work (return value). + + bool testChannel = false; + bool testCodec = false; + bool testFreq = false; + + int err = 0; + + // For now, just accept only audio/pcm codec + if(!format.codec().startsWith(tr("audio/pcm"))) { + err=-1; + } else + testCodec = true; + + if(err>=0 && format.channels() != -1) { + testChannel = true; + } + + if(err>=0 && format.frequency() != -1) { + testFreq = true; + } + + if(err == 0) { + // settings work + return true; + } + return false; +} + +void QAudioDeviceInfoPrivate::updateLists() +{ + // redo all lists based on current settings + bool base = false; + bool match = false; + DWORD fmt = NULL; + QString tmp; + + if(device.compare(tr("default")) == 0) + base = true; + + if(mode == QAudio::AudioOutput) { + WAVEOUTCAPS woc; + unsigned long iNumDevs,i; + iNumDevs = waveOutGetNumDevs(); + for(i=0;i QAudioDeviceInfoPrivate::deviceList(QAudio::Mode mode) +{ + Q_UNUSED(mode) + + QList devices; + + devices.append("default"); + + if(mode == QAudio::AudioOutput) { + WAVEOUTCAPS woc; + unsigned long iNumDevs,i; + iNumDevs = waveOutGetNumDevs(); + for(i=0;i +#include +#include +#include + +#include +#include + + +const unsigned int MAX_SAMPLE_RATES = 5; +const unsigned int SAMPLE_RATES[] = { 8000, 11025, 22050, 44100, 48000 }; + +class QAudioDeviceInfoPrivate : public QAbstractAudioDeviceInfo +{ + Q_OBJECT + +public: + QAudioDeviceInfoPrivate(QByteArray dev,QAudio::Mode mode); + ~QAudioDeviceInfoPrivate(); + + bool open(); + void close(); + + bool testSettings(const QAudioFormat& format) const; + void updateLists(); + QAudioFormat preferredFormat() const; + bool isFormatSupported(const QAudioFormat& format) const; + QAudioFormat nearestFormat(const QAudioFormat& format) const; + QString deviceName() const; + QStringList codecList(); + QList frequencyList(); + QList channelsList(); + QList sampleSizeList(); + QList byteOrderList(); + QList sampleTypeList(); + static QByteArray defaultInputDevice(); + static QByteArray defaultOutputDevice(); + static QList deviceList(QAudio::Mode); + +private: + QAudio::Mode mode; + QString device; + QAudioFormat nearest; + QList freqz; + QList channelz; + QList sizez; + QList byteOrderz; + QStringList codecz; + QList typez; +}; + +#endif diff --git a/src/multimedia/audio/qaudioengine.cpp b/src/multimedia/audio/qaudioengine.cpp new file mode 100644 index 000000000..930977e02 --- /dev/null +++ b/src/multimedia/audio/qaudioengine.cpp @@ -0,0 +1,343 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +QT_BEGIN_NAMESPACE + +/*! + \class QAbstractAudioDeviceInfo + \brief The QAbstractAudioDeviceInfo class provides access for QAudioDeviceInfo to access the audio + device provided by the plugin. + \internal + + \ingroup multimedia + + This class implements the audio functionality for + QAudioDeviceInfo, i.e., QAudioDeviceInfo keeps a + QAbstractAudioDeviceInfo and routes function calls to it. For a + description of the functionality that QAbstractAudioDeviceInfo + implements, you can read the class and functions documentation of + QAudioDeviceInfo. + + \sa QAudioDeviceInfo +*/ + +/*! + \fn virtual QAudioFormat QAbstractAudioDeviceInfo::preferredFormat() const + Returns the nearest settings. +*/ + +/*! + \fn virtual bool QAbstractAudioDeviceInfo::isFormatSupported(const QAudioFormat& format) const + Returns true if \a format is available from audio device. +*/ + +/*! + \fn virtual QAudioFormat QAbstractAudioDeviceInfo::nearestFormat(const QAudioFormat& format) const + Returns the nearest settings \a format. +*/ + +/*! + \fn virtual QString QAbstractAudioDeviceInfo::deviceName() const + Returns the audio device name. +*/ + +/*! + \fn virtual QStringList QAbstractAudioDeviceInfo::codecList() + Returns the list of currently available codecs. +*/ + +/*! + \fn virtual QList QAbstractAudioDeviceInfo::frequencyList() + Returns the list of currently available frequencies. +*/ + +/*! + \fn virtual QList QAbstractAudioDeviceInfo::channelsList() + Returns the list of currently available channels. +*/ + +/*! + \fn virtual QList QAbstractAudioDeviceInfo::sampleSizeList() + Returns the list of currently available sample sizes. +*/ + +/*! + \fn virtual QList QAbstractAudioDeviceInfo::byteOrderList() + Returns the list of currently available byte orders. +*/ + +/*! + \fn virtual QList QAbstractAudioDeviceInfo::sampleTypeList() + Returns the list of currently available sample types. +*/ + +/*! + \class QAbstractAudioOutput + \brief The QAbstractAudioOutput class provides access for QAudioOutput to access the audio + device provided by the plugin. + \internal + + \ingroup multimedia + + QAbstractAudioOutput implements audio functionality for + QAudioOutput, i.e., QAudioOutput routes function calls to + QAbstractAudioOutput. For a description of the functionality that + is implemented, see the QAudioOutput class and function + descriptions. + + \sa QAudioOutput +*/ + +/*! + \fn virtual QIODevice* QAbstractAudioOutput::start(QIODevice* device) + Uses the \a device as the QIODevice to transfer data. If \a device is null then the class + creates an internal QIODevice. Returns a pointer to the QIODevice being used to handle + the data transfer. This QIODevice can be used to write() audio data directly. Passing a + QIODevice allows the data to be transfered without any extra code. +*/ + +/*! + \fn virtual void QAbstractAudioOutput::stop() + Stops the audio output. +*/ + +/*! + \fn virtual void QAbstractAudioOutput::reset() + Drops all audio data in the buffers, resets buffers to zero. +*/ + +/*! + \fn virtual void QAbstractAudioOutput::suspend() + Stops processing audio data, preserving buffered audio data. +*/ + +/*! + \fn virtual void QAbstractAudioOutput::resume() + Resumes processing audio data after a suspend() +*/ + +/*! + \fn virtual int QAbstractAudioOutput::bytesFree() const + Returns the free space available in bytes in the audio buffer. +*/ + +/*! + \fn virtual int QAbstractAudioOutput::periodSize() const + Returns the period size in bytes. +*/ + +/*! + \fn virtual void QAbstractAudioOutput::setBufferSize(int value) + Sets the audio buffer size to \a value in bytes. +*/ + +/*! + \fn virtual int QAbstractAudioOutput::bufferSize() const + Returns the audio buffer size in bytes. +*/ + +/*! + \fn virtual void QAbstractAudioOutput::setNotifyInterval(int ms) + Sets the interval for notify() signal to be emitted. This is based on the \a ms + of audio data processed not on actual real-time. The resolution of the timer + is platform specific. +*/ + +/*! + \fn virtual int QAbstractAudioOutput::notifyInterval() const + Returns the notify interval in milliseconds. +*/ + +/*! + \fn virtual qint64 QAbstractAudioOutput::totalTime() const + Returns the amount of audio data processed since start() was called in milliseconds. +*/ + +/*! + \fn virtual qint64 QAbstractAudioOutput::clock() const + Returns the milliseconds since start() was called, including time in Idle and suspend states. +*/ + +/*! + \fn virtual QAudio::Error QAbstractAudioOutput::error() const + Returns the error state. +*/ + +/*! + \fn virtual QAudio::State QAbstractAudioOutput::state() const + Returns the state of audio processing. +*/ + +/*! + \fn virtual QAudioFormat QAbstractAudioOutput::format() const + Returns the QAudioFormat being used. +*/ + +/*! + \fn QAbstractAudioOutput::stateChanged(QAudio::State state) + This signal is emitted when the device \a state has changed. +*/ + +/*! + \fn QAbstractAudioOutput::notify() + This signal is emitted when x ms of audio data has been processed + the interval set by setNotifyInterval(x). +*/ + + +/*! + \class QAbstractAudioInput + \brief The QAbstractAudioInput class provides access for QAudioInput to access the audio + device provided by the plugin. + \internal + + \ingroup multimedia + + QAudioDeviceInput keeps an instance of QAbstractAudioInput and + routes calls to functions of the same name to QAbstractAudioInput. + This means that it is QAbstractAudioInput that implements the + audio functionality. For a description of the functionality, see + the QAudioInput class description. + + \sa QAudioInput +*/ + +/*! + \fn virtual QIODevice* QAbstractAudioInput::start(QIODevice* device) + Uses the \a device as the QIODevice to transfer data. If \a device is null + then the class creates an internal QIODevice. Returns a pointer to the + QIODevice being used to handle the data transfer. This QIODevice can be used to + read() audio data directly. Passing a QIODevice allows the data to be transfered + without any extra code. +*/ + +/*! + \fn virtual void QAbstractAudioInput::stop() + Stops the audio input. +*/ + +/*! + \fn virtual void QAbstractAudioInput::reset() + Drops all audio data in the buffers, resets buffers to zero. +*/ + +/*! + \fn virtual void QAbstractAudioInput::suspend() + Stops processing audio data, preserving buffered audio data. +*/ + +/*! + \fn virtual void QAbstractAudioInput::resume() + Resumes processing audio data after a suspend(). +*/ + +/*! + \fn virtual int QAbstractAudioInput::bytesReady() const + Returns the amount of audio data available to read in bytes. +*/ + +/*! + \fn virtual int QAbstractAudioInput::periodSize() const + Returns the period size in bytes. +*/ + +/*! + \fn virtual void QAbstractAudioInput::setBufferSize(int value) + Sets the audio buffer size to \a value in milliseconds. +*/ + +/*! + \fn virtual int QAbstractAudioInput::bufferSize() const + Returns the audio buffer size in milliseconds. +*/ + +/*! + \fn virtual void QAbstractAudioInput::setNotifyInterval(int ms) + Sets the interval for notify() signal to be emitted. This is based + on the \a ms of audio data processed not on actual real-time. + The resolution of the timer is platform specific. +*/ + +/*! + \fn virtual int QAbstractAudioInput::notifyInterval() const + Returns the notify interval in milliseconds. +*/ + +/*! + \fn virtual qint64 QAbstractAudioInput::totalTime() const + Returns the amount of audio data processed since start() was called in milliseconds. +*/ + +/*! + \fn virtual qint64 QAbstractAudioInput::clock() const + Returns the milliseconds since start() was called, including time in Idle and suspend states. +*/ + +/*! + \fn virtual QAudio::Error QAbstractAudioInput::error() const + Returns the error state. +*/ + +/*! + \fn virtual QAudio::State QAbstractAudioInput::state() const + Returns the state of audio processing. +*/ + +/*! + \fn virtual QAudioFormat QAbstractAudioInput::format() const + Returns the QAudioFormat being used +*/ + +/*! + \fn QAbstractAudioInput::stateChanged(QAudio::State state) + This signal is emitted when the device \a state has changed. +*/ + +/*! + \fn QAbstractAudioInput::notify() + This signal is emitted when x ms of audio data has been processed + the interval set by setNotifyInterval(x). +*/ + + +QT_END_NAMESPACE diff --git a/src/multimedia/audio/qaudioengine.h b/src/multimedia/audio/qaudioengine.h new file mode 100644 index 000000000..b0aa7628b --- /dev/null +++ b/src/multimedia/audio/qaudioengine.h @@ -0,0 +1,131 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QAUDIOENGINE_H +#define QAUDIOENGINE_H + +#include +#include +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + +class Q_MULTIMEDIA_EXPORT QAbstractAudioDeviceInfo : public QObject +{ + Q_OBJECT + +public: + virtual QAudioFormat preferredFormat() const = 0; + virtual bool isFormatSupported(const QAudioFormat &format) const = 0; + virtual QAudioFormat nearestFormat(const QAudioFormat &format) const = 0; + virtual QString deviceName() const = 0; + virtual QStringList codecList() = 0; + virtual QList frequencyList() = 0; + virtual QList channelsList() = 0; + virtual QList sampleSizeList() = 0; + virtual QList byteOrderList() = 0; + virtual QList sampleTypeList() = 0; +}; + +class Q_MULTIMEDIA_EXPORT QAbstractAudioOutput : public QObject +{ + Q_OBJECT + +public: + virtual QIODevice* start(QIODevice* device) = 0; + virtual void stop() = 0; + virtual void reset() = 0; + virtual void suspend() = 0; + virtual void resume() = 0; + virtual int bytesFree() const = 0; + virtual int periodSize() const = 0; + virtual void setBufferSize(int value) = 0; + virtual int bufferSize() const = 0; + virtual void setNotifyInterval(int milliSeconds) = 0; + virtual int notifyInterval() const = 0; + virtual qint64 totalTime() const = 0; + virtual qint64 clock() const = 0; + virtual QAudio::Error error() const = 0; + virtual QAudio::State state() const = 0; + virtual QAudioFormat format() const = 0; + +Q_SIGNALS: + void stateChanged(QAudio::State); + void notify(); +}; + +class Q_MULTIMEDIA_EXPORT QAbstractAudioInput : public QObject +{ + Q_OBJECT + +public: + virtual QIODevice* start(QIODevice* device) = 0; + virtual void stop() = 0; + virtual void reset() = 0; + virtual void suspend() = 0; + virtual void resume() = 0; + virtual int bytesReady() const = 0; + virtual int periodSize() const = 0; + virtual void setBufferSize(int value) = 0; + virtual int bufferSize() const = 0; + virtual void setNotifyInterval(int milliSeconds) = 0; + virtual int notifyInterval() const = 0; + virtual qint64 totalTime() const = 0; + virtual qint64 clock() const = 0; + virtual QAudio::Error error() const = 0; + virtual QAudio::State state() const = 0; + virtual QAudioFormat format() const = 0; + +Q_SIGNALS: + void stateChanged(QAudio::State); + void notify(); +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QAUDIOENGINE_H diff --git a/src/multimedia/audio/qaudioengineplugin.cpp b/src/multimedia/audio/qaudioengineplugin.cpp new file mode 100644 index 000000000..6e3900493 --- /dev/null +++ b/src/multimedia/audio/qaudioengineplugin.cpp @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include + +QT_BEGIN_NAMESPACE + +QAudioEnginePlugin::QAudioEnginePlugin(QObject* parent) : + QObject(parent) +{} + +QAudioEnginePlugin::~QAudioEnginePlugin() +{} + +QT_END_NAMESPACE diff --git a/src/multimedia/audio/qaudioengineplugin.h b/src/multimedia/audio/qaudioengineplugin.h new file mode 100644 index 000000000..8eab2d710 --- /dev/null +++ b/src/multimedia/audio/qaudioengineplugin.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QAUDIOENGINEPLUGIN_H +#define QAUDIOENGINEPLUGIN_H + +#include +#include +#include + +#include +#include +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + +struct Q_MULTIMEDIA_EXPORT QAudioEngineFactoryInterface : public QFactoryInterface +{ + virtual QList deviceList(QAudio::Mode) const = 0; + virtual QAbstractAudioInput* createInput(const QByteArray& device, const QAudioFormat& format = QAudioFormat()) = 0; + virtual QAbstractAudioOutput* createOutput(const QByteArray& device, const QAudioFormat& format = QAudioFormat()) = 0; + virtual QAbstractAudioDeviceInfo* createDeviceInfo(const QByteArray& device, QAudio::Mode mode) = 0; +}; + +#define QAudioEngineFactoryInterface_iid \ + "com.nokia.qt.QAudioEngineFactoryInterface" +Q_DECLARE_INTERFACE(QAudioEngineFactoryInterface, QAudioEngineFactoryInterface_iid) + +class Q_MULTIMEDIA_EXPORT QAudioEnginePlugin : public QObject, public QAudioEngineFactoryInterface +{ + Q_OBJECT + Q_INTERFACES(QAudioEngineFactoryInterface:QFactoryInterface) + +public: + QAudioEnginePlugin(QObject *parent = 0); + ~QAudioEnginePlugin(); + + virtual QStringList keys() const = 0; + virtual QList deviceList(QAudio::Mode) const = 0; + virtual QAbstractAudioInput* createInput(const QByteArray& device, const QAudioFormat& format = QAudioFormat()) = 0; + virtual QAbstractAudioOutput* createOutput(const QByteArray& device, const QAudioFormat& format = QAudioFormat()) = 0; + virtual QAbstractAudioDeviceInfo* createDeviceInfo(const QByteArray& device, QAudio::Mode mode) = 0; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QAUDIOENGINEPLUGIN_H diff --git a/src/multimedia/audio/qaudioformat.cpp b/src/multimedia/audio/qaudioformat.cpp new file mode 100644 index 000000000..6632c63c3 --- /dev/null +++ b/src/multimedia/audio/qaudioformat.cpp @@ -0,0 +1,335 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + + +QT_BEGIN_NAMESPACE + + +class QAudioFormatPrivate : public QSharedData +{ +public: + QAudioFormatPrivate() + { + frequency = -1; + channels = -1; + sampleSize = -1; + byteOrder = QAudioFormat::Endian(QSysInfo::ByteOrder); + sampleType = QAudioFormat::Unknown; + } + + QString codec; + QAudioFormat::Endian byteOrder; + QAudioFormat::SampleType sampleType; + + int frequency; + int channels; + int sampleSize; +}; + +/*! + \class QAudioFormat + \brief The QAudioFormat class stores audio parameter information. + + \inmodule QtMultimedia + \ingroup multimedia + \since 4.6 + + An audio format specifies how data in an audio stream is arranged, + i.e, how the stream is to be interpreted. The encoding itself is + specified by the codec() used for the stream. + + In addition to the encoding, QAudioFormat contains other + parameters that further specify how the audio data is arranged. + These are the frequency, the number of channels, the sample size, + the sample type, and the byte order. The following table describes + these in more detail. + + \table + \header + \o Parameter + \o Description + \row + \o Frequency + \o Samples per second of audio data in Hertz. + \row + \o Number of channels + \o The number of audio channels (typically one for mono + or two for stereo) + \row + \o Sample size + \o How much data is stored in each sample (typically 8 + or 16) + \row + \o Sample type + \o Numerical representation of sample (typically signed integer, + unsigned integer or float) + \row + \o Byte order + \o Byte ordering of sample (typically little endian, big endian) + \endtable + + You can obtain audio formats compatible with the audio device used + through functions in QAudioDeviceInfo. This class also lets you + query available parameter values for a device, so that you can set + the parameters yourself. See the QAudioDeviceInfo class + description for details. +*/ + +/*! + Construct a new audio format. + + Values are initialized as follows: + \list + \o frequency() = -1 + \o channels() = -1 + \o sampleSize() = -1 + \o byteOrder() = QAudioFormat::Endian(QSysInfo::ByteOrder) + \o sampleType() = QAudioFormat::Unknown + \c codec() = "" + \endlist +*/ + +QAudioFormat::QAudioFormat(): + d(new QAudioFormatPrivate) +{ +} + +/*! + Construct a new audio format using \a other. +*/ + +QAudioFormat::QAudioFormat(const QAudioFormat &other): + d(other.d) +{ +} + +/*! + Destroy this audio format. +*/ + +QAudioFormat::~QAudioFormat() +{ +} + +/*! + Assigns \a other to this QAudioFormat implementation. +*/ + +QAudioFormat& QAudioFormat::operator=(const QAudioFormat &other) +{ + d = other.d; + return *this; +} + +/*! + Returns true if this QAudioFormat is equal to the \a other + QAudioFormat; otherwise returns false. + + All elements of QAudioFormat are used for the comparison. +*/ + +bool QAudioFormat::operator==(const QAudioFormat &other) const +{ + return d->frequency == other.d->frequency && + d->channels == other.d->channels && + d->sampleSize == other.d->sampleSize && + d->byteOrder == other.d->byteOrder && + d->codec == other.d->codec && + d->sampleType == other.d->sampleType; +} + +/*! + Returns true if this QAudioFormat is not equal to the \a other + QAudioFormat; otherwise returns false. + + All elements of QAudioFormat are used for the comparison. +*/ + +bool QAudioFormat::operator!=(const QAudioFormat& other) const +{ + return !(*this == other); +} + +/*! + Returns true if any of the parameters are invalid. +*/ + +bool QAudioFormat::isNull() const +{ + return d->frequency == -1 && d->channels == -1 && + d->sampleSize == -1 && + d->byteOrder == QAudioFormat::Endian(QSysInfo::ByteOrder) && + d->sampleType == QAudioFormat::Unknown && + d->codec.isNull(); +} + +/*! + Sets the frequency to \a frequency. +*/ + +void QAudioFormat::setFrequency(int frequency) +{ + d->frequency = frequency; +} + +/*! + Returns the current frequency value. +*/ + +int QAudioFormat::frequency() const +{ + return d->frequency; +} + +/*! + Sets the channels to \a channels. +*/ + +void QAudioFormat::setChannels(int channels) +{ + d->channels = channels; +} + +/*! + Returns the current channel value. +*/ + +int QAudioFormat::channels() const +{ + return d->channels; +} + +/*! + Sets the sampleSize to \a sampleSize. +*/ + +void QAudioFormat::setSampleSize(int sampleSize) +{ + d->sampleSize = sampleSize; +} + +/*! + Returns the current sampleSize value. +*/ + +int QAudioFormat::sampleSize() const +{ + return d->sampleSize; +} + +/*! + Sets the codec to \a codec. + + \sa QAudioDeviceInfo::supportedCodecs() +*/ + +void QAudioFormat::setCodec(QString codec) +{ + d->codec = codec; +} + +/*! + Returns the current codec value. + + \sa QAudioDeviceInfo::supportedCodecs() +*/ + +QString QAudioFormat::codec() const +{ + return d->codec; +} + +/*! + Sets the byteOrder to \a byteOrder. +*/ + +void QAudioFormat::setByteOrder(QAudioFormat::Endian byteOrder) +{ + d->byteOrder = byteOrder; +} + +/*! + Returns the current byteOrder value. +*/ + +QAudioFormat::Endian QAudioFormat::byteOrder() const +{ + return d->byteOrder; +} + +/*! + Sets the sampleType to \a sampleType. +*/ + +void QAudioFormat::setSampleType(QAudioFormat::SampleType sampleType) +{ + d->sampleType = sampleType; +} + +/*! + Returns the current SampleType value. +*/ + +QAudioFormat::SampleType QAudioFormat::sampleType() const +{ + return d->sampleType; +} + +/*! + \enum QAudioFormat::SampleType + + \value Unknown Not Set + \value SignedInt samples are signed integers + \value UnSignedInt samples are unsigned intergers + \value Float samples are floats +*/ + +/*! + \enum QAudioFormat::Endian + + \value BigEndian samples are big endian byte order + \value LittleEndian samples are little endian byte order +*/ + +QT_END_NAMESPACE + diff --git a/src/multimedia/audio/qaudioformat.h b/src/multimedia/audio/qaudioformat.h new file mode 100644 index 000000000..c74096978 --- /dev/null +++ b/src/multimedia/audio/qaudioformat.h @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QAUDIOFORMAT_H +#define QAUDIOFORMAT_H + +#include +#include +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QAudioFormatPrivate; + +class Q_MULTIMEDIA_EXPORT QAudioFormat +{ +public: + enum SampleType { Unknown, SignedInt, UnSignedInt, Float }; + enum Endian { BigEndian = QSysInfo::BigEndian, LittleEndian = QSysInfo::LittleEndian }; + + QAudioFormat(); + QAudioFormat(const QAudioFormat &other); + ~QAudioFormat(); + + QAudioFormat& operator=(const QAudioFormat &other); + bool operator==(const QAudioFormat &other) const; + bool operator!=(const QAudioFormat &other) const; + + bool isNull() const; + + void setFrequency(int frequency); + int frequency() const; + + void setChannels(int channels); + int channels() const; + + void setSampleSize(int sampleSize); + int sampleSize() const; + + void setCodec(QString codec); + QString codec() const; + + void setByteOrder(QAudioFormat::Endian byteOrder); + QAudioFormat::Endian byteOrder() const; + + void setSampleType(QAudioFormat::SampleType sampleType); + QAudioFormat::SampleType sampleType() const; + +private: + QSharedDataPointer d; +}; + + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QAUDIOFORMAT_H diff --git a/src/multimedia/audio/qaudioinput.cpp b/src/multimedia/audio/qaudioinput.cpp new file mode 100644 index 000000000..17cacc6df --- /dev/null +++ b/src/multimedia/audio/qaudioinput.cpp @@ -0,0 +1,400 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include +#include +#include +#include + +#include "qaudiodevicefactory_p.h" + + +QT_BEGIN_NAMESPACE + +/*! + \class QAudioInput + \brief The QAudioInput class provides an interface for receiving audio data from an audio input device. + + \inmodule QtMultimedia + \ingroup multimedia + \since 4.6 + + You can construct an audio input with the system's + \l{QAudioDeviceInfo::defaultInputDevice()}{default audio input + device}. It is also possible to create QAudioInput with a + specific QAudioDeviceId. When you create the audio input, you + should also send in the QAudioFormat to be used for the recording + (see the QAudioFormat class description for details). + + To record to a file: + + QAudioInput lets you record audio with an audio input device. The + default constructor of this class will use the systems default + audio device, but you can also specify a QAudioDeviceId for a + specific device. You also need to pass in the QAudioFormat in + which you wish to record. + + Starting up the QAudioInput is simply a matter of calling start() + with a QIODevice opened for writing. For instance, to record to a + file, you can: + + \code + { + QFile outputFile; + outputFile.setFileName("/tmp/test.raw"); + outputFile.open( QIODevice::WriteOnly | QIODevice::Truncate ); + + QAudioFormat format; + // set up the format you want, eg. + format.setFrequency(8000); + format.setChannels(1); + format.setSampleSize(8); + format.setCodec("audio/pcm"); + format.setByteOrder(QAudioFormat::LittleEndian); + format.setSampleType(QAudioFormat::UnSignedInt); + + QAudioInput *audio = new QAudioInput(format, this); + QTimer::singleShot(3000, this, SLOT(stopRecording())); + audio->start(outputFile); + // Records audio for 3000ms + } + \endcode + + This will start recording if the format specified is supported by + the input device (you can check this with + QAudioDeviceInfo::isFormatSupported(). In case there are any + snags, use the error() function to check what went wrong. We stop + recording in the \c stopRecording() slot. + + \code + void stopRecording() + { + audio->stop(); + outputFile->close(); + } + \endcode + + At any point in time, QAudioInput will be in one of four states: + active, suspended, stopped, or idle. These states are specified by + the QAudio::State enum. You can request a state change directly through + suspend(), resume(), stop(), reset(), and start(). The current + state is reported by state(). QAudioOutput will also signal you + when the state changes (stateChanged()). + + QAudioInput provides several ways of measuring the time that has + passed since the start() of the recording. The \c totalTime() + function returns the length of the stream in microseconds written, + i.e., it leaves out the times the audio input was suspended or idle. + The clock() function returns the time elapsed since start() was called regardless of + which states the QAudioInput has been in. + + If an error should occur, you can fetch its reason with error(). + The possible error reasons are described by the QAudio::Error enum. + + \sa QAudioOutput, QAudioDeviceInfo +*/ + +/*! + Construct a new audio input and attach it to \a parent. + The default audio input device is used with the output + \a format parameters. +*/ + +QAudioInput::QAudioInput(const QAudioFormat &format, QObject *parent): + QObject(parent) +{ + d = QAudioDeviceFactory::createDefaultInputDevice(format); + connect(d, SIGNAL(notify()), SIGNAL(notify())); + connect(d, SIGNAL(stateChanged(QAudio::State)), SIGNAL(stateChanged(QAudio::State))); +} + +/*! + Construct a new audio input and attach it to \a parent. + The \a id of the audio input device is used with the input + \a format parameters. +*/ + +QAudioInput::QAudioInput(const QAudioDeviceId &id, const QAudioFormat &format, QObject *parent): + QObject(parent) +{ + d = QAudioDeviceFactory::createInputDevice(id, format); + connect(d, SIGNAL(notify()), SIGNAL(notify())); + connect(d, SIGNAL(stateChanged(QAudio::State)), SIGNAL(stateChanged(QAudio::State))); +} + +/*! + Destroy this audio input. +*/ + +QAudioInput::~QAudioInput() +{ + delete d; +} + +/*! + Uses the \a device as the QIODevice to transfer data. + If \a device is null then the class creates an internal QIODevice. + Returns a pointer to the QIODevice being used to handle the data + transfer. This QIODevice can be used to read() audio data + directly. + Passing a QIODevice allows the data to be transfered without any extra code. + All that is required is to open the QIODevice. + + /sa QIODevice +*/ + +QIODevice* QAudioInput::start(QIODevice* device) +{ + /* + PULL MODE (valid QIODevice) + -If currently not StopState, stop + -If previous start was push mode, delete internal QIODevice. + -open audio input. + If ok, NoError and ActiveState, else OpenError and StopState. + -emit stateChanged() + -return device + + PUSH MODE (device = 0) + -If currently not StopState, stop + -If no internal QIODevice, create one. + -open audio input. + -If ok, NoError and IdleState, else OpenError and StopState + -emit stateChanged() + -return internal QIODevice + */ + return d->start(device); +} + +/*! + Returns the QAudioFormat being used. +*/ + +QAudioFormat QAudioInput::format() const +{ + return d->format(); +} + +/*! + Stops the audio input. +*/ + +void QAudioInput::stop() +{ + /* + -If StopState, return + -set to StopState + -detach from audio device + -emit stateChanged() + */ + d->stop(); +} + +/*! + Drops all audio data in the buffers, resets buffers to zero. +*/ + +void QAudioInput::reset() +{ + /* + -drop all buffered audio, set buffers to zero. + -call stop() + */ + d->reset(); +} + +/*! + Stops processing audio data, preserving buffered audio data. +*/ + +void QAudioInput::suspend() +{ + /* + -If not ActiveState|IdleState, return + -stop processing audio, saving all buffered audio data + -set NoError and SuspendState + -emit stateChanged() + */ + d->suspend(); +} + +/*! + Resumes processing audio data after a suspend(). +*/ + +void QAudioInput::resume() +{ + /* + -If SuspendState, return + -resume audio + -(PULL MODE): set ActiveState, NoError + -(PUSH MODE): set IdleState, NoError + -kick start audio if needed + -emit stateChanged() + */ + d->resume(); +} + +/*! + Sets the audio buffer size to \a value milliseconds. + + Note: This function can be called anytime before start(), calls to this + are ignored after start(). It should not be assumed that the buffer size + set is the actual buffer size used, calling bufferSize() anytime after start() + will return the actual buffer size being used. + +*/ + +void QAudioInput::setBufferSize(int value) +{ + d->setBufferSize(value); +} + +/*! + Returns the audio buffer size in milliseconds. + + If called before start(), returns platform default value. + If called before start() but setBufferSize() was called prior, returns value set by setBufferSize(). + If called after start(), returns the actual buffer size being used. This may not be what was set previously + by setBufferSize(). + +*/ + +int QAudioInput::bufferSize() const +{ + return d->bufferSize(); +} + +/*! + Returns the amount of audio data available to read in bytes. +*/ + +int QAudioInput::bytesReady() const +{ + /* + -If not ActiveState|IdleState, return 0 + -return amount of audio data available to read + */ + return d->bytesReady(); +} + +/*! + Returns the period size in bytes. + + Note: This is the recommended read size in bytes. +*/ + +int QAudioInput::periodSize() const +{ + return d->periodSize(); +} + +/*! + Sets the interval for notify() signal to be emitted. + This is based on the \a ms of audio data processed + not on actual real-time. The resolution of the timer is platform specific. +*/ + +void QAudioInput::setNotifyInterval(int ms) +{ + d->setNotifyInterval(ms); +} + +/*! + Returns the notify interval in milliseconds. +*/ + +int QAudioInput::notifyInterval() const +{ + return d->notifyInterval(); +} + +/*! + Returns the amount of audio data processed since start() + was called in microseconds. +*/ + +qint64 QAudioInput::totalTime() const +{ + return d->totalTime(); +} + +/*! + Returns the microseconds since start() was called, including time in Idle and + Suspend states. +*/ + +qint64 QAudioInput::clock() const +{ + return d->clock(); +} + +/*! + Returns the error state. +*/ + +QAudio::Error QAudioInput::error() const +{ + return d->error(); +} + +/*! + Returns the state of audio processing. +*/ + +QAudio::State QAudioInput::state() const +{ + return d->state(); +} + +/*! + \fn QAudioInput::stateChanged(QAudio::State state) + This signal is emitted when the device \a state has changed. +*/ + +/*! + \fn QAudioInput::notify() + This signal is emitted when x ms of audio data has been processed + the interval set by setNotifyInterval(x). +*/ + +QT_END_NAMESPACE + diff --git a/src/multimedia/audio/qaudioinput.h b/src/multimedia/audio/qaudioinput.h new file mode 100644 index 000000000..b0f1aed6e --- /dev/null +++ b/src/multimedia/audio/qaudioinput.h @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QAUDIOINPUT_H +#define QAUDIOINPUT_H + +#include +#include + +#include +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QAbstractAudioInput; + +class Q_MULTIMEDIA_EXPORT QAudioInput : public QObject +{ + Q_OBJECT + +public: + explicit QAudioInput(const QAudioFormat &format = QAudioFormat(), QObject *parent = 0); + explicit QAudioInput(const QAudioDeviceId &id, const QAudioFormat &format = QAudioFormat(), QObject *parent = 0); + ~QAudioInput(); + + QAudioFormat format() const; + + QIODevice* start(QIODevice *device = 0); + void stop(); + void reset(); + void suspend(); + void resume(); + + void setBufferSize(int bytes); + int bufferSize() const; + + int bytesReady() const; + int periodSize() const; + + void setNotifyInterval(int milliSeconds); + int notifyInterval() const; + + qint64 totalTime() const; + qint64 clock() const; + + QAudio::Error error() const; + QAudio::State state() const; + +Q_SIGNALS: + void stateChanged(QAudio::State); + void notify(); + +private: + Q_DISABLE_COPY(QAudioInput); + + QAbstractAudioInput* d; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QAUDIOINPUT_H diff --git a/src/multimedia/audio/qaudioinput_alsa_p.cpp b/src/multimedia/audio/qaudioinput_alsa_p.cpp new file mode 100644 index 000000000..6f00469fc --- /dev/null +++ b/src/multimedia/audio/qaudioinput_alsa_p.cpp @@ -0,0 +1,688 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include "qaudioinput_alsa_p.h" + +//#define DEBUG_AUDIO 1 + +QAudioInputPrivate::QAudioInputPrivate(const QByteArray &device, const QAudioFormat& audioFormat): + settings(audioFormat) +{ + bytesAvailable = 0; + handle = 0; + ahandler = 0; + access = SND_PCM_ACCESS_RW_INTERLEAVED; + pcmformat = SND_PCM_FORMAT_S16; + buffer_size = 0; + period_size = 0; + buffer_time = 100000; + period_time = 20000; + totalTimeValue = 0; + intervalTime = 1000; + audioBuffer = 0; + errorState = QAudio::NoError; + deviceState = QAudio::StopState; + audioSource = 0; + pullMode = true; + resuming = false; + + QStringList list1 = QString(tr(device)).split(tr(":")); + m_device = QByteArray(list1.at(0).toLocal8Bit().constData()); + + timer = new QTimer(this); + connect(timer,SIGNAL(timeout()),SLOT(userFeed())); +} + +QAudioInputPrivate::~QAudioInputPrivate() +{ + close(); + disconnect(timer, SIGNAL(timeout())); + QCoreApplication::processEvents(); + delete timer; +} + +QAudio::Error QAudioInputPrivate::error() const +{ + return errorState; +} + +QAudio::State QAudioInputPrivate::state() const +{ + return deviceState; +} + + +QAudioFormat QAudioInputPrivate::format() const +{ + return settings; +} + +int QAudioInputPrivate::xrun_recovery(int err) +{ + int count = 0; + bool reset = false; + + if(err == -EPIPE) { + errorState = QAudio::UnderrunError; + err = snd_pcm_prepare(handle); + if(err < 0) + reset = true; + + } else if((err == -ESTRPIPE)||(err == -EIO)) { + errorState = QAudio::IOError; + while((err = snd_pcm_resume(handle)) == -EAGAIN){ + usleep(100); + count++; + if(count > 5) { + reset = true; + break; + } + } + if(err < 0) { + err = snd_pcm_prepare(handle); + if(err < 0) + reset = true; + } + } + if(reset) { + close(); + open(); + snd_pcm_prepare(handle); + return 0; + } + return err; +} + +int QAudioInputPrivate::setFormat() +{ + snd_pcm_format_t format = SND_PCM_FORMAT_S16; + + if(settings.sampleSize() == 8) { + format = SND_PCM_FORMAT_U8; + } else if(settings.sampleSize() == 16) { + if(settings.sampleType() == QAudioFormat::SignedInt) { + if(settings.byteOrder() == QAudioFormat::LittleEndian) + format = SND_PCM_FORMAT_S16_LE; + else + format = SND_PCM_FORMAT_S16_BE; + } else if(settings.sampleType() == QAudioFormat::UnSignedInt) { + if(settings.byteOrder() == QAudioFormat::LittleEndian) + format = SND_PCM_FORMAT_U16_LE; + else + format = SND_PCM_FORMAT_U16_BE; + } + } else if(settings.sampleSize() == 24) { + if(settings.sampleType() == QAudioFormat::SignedInt) { + if(settings.byteOrder() == QAudioFormat::LittleEndian) + format = SND_PCM_FORMAT_S24_LE; + else + format = SND_PCM_FORMAT_S24_BE; + } else if(settings.sampleType() == QAudioFormat::UnSignedInt) { + if(settings.byteOrder() == QAudioFormat::LittleEndian) + format = SND_PCM_FORMAT_U24_LE; + else + format = SND_PCM_FORMAT_U24_BE; + } + } else if(settings.sampleSize() == 32) { + if(settings.sampleType() == QAudioFormat::SignedInt) { + if(settings.byteOrder() == QAudioFormat::LittleEndian) + format = SND_PCM_FORMAT_S32_LE; + else + format = SND_PCM_FORMAT_S32_BE; + } else if(settings.sampleType() == QAudioFormat::UnSignedInt) { + if(settings.byteOrder() == QAudioFormat::LittleEndian) + format = SND_PCM_FORMAT_U32_LE; + else + format = SND_PCM_FORMAT_U32_BE; + } else if(settings.sampleType() == QAudioFormat::Float) { + if(settings.byteOrder() == QAudioFormat::LittleEndian) + format = SND_PCM_FORMAT_FLOAT_LE; + else + format = SND_PCM_FORMAT_FLOAT_BE; + } + } else if(settings.sampleSize() == 64) { + if(settings.byteOrder() == QAudioFormat::LittleEndian) + format = SND_PCM_FORMAT_FLOAT64_LE; + else + format = SND_PCM_FORMAT_FLOAT64_BE; + } + + return snd_pcm_hw_params_set_format( handle, hwparams, format); +} + +QIODevice* QAudioInputPrivate::start(QIODevice* device) +{ + if(deviceState != QAudio::StopState) + close(); + + if(!pullMode && audioSource) { + delete audioSource; + } + + if(device) { + //set to pull mode + pullMode = true; + audioSource = device; + } else { + //set to push mode + pullMode = false; + audioSource = new InputPrivate(this); + audioSource->open(QIODevice::ReadOnly | QIODevice::Unbuffered); + } + + if( !open() ) + return 0; + + emit stateChanged(deviceState); + + return audioSource; +} + +void QAudioInputPrivate::stop() +{ + if(deviceState == QAudio::StopState) + return; + + deviceState = QAudio::StopState; + + close(); + emit stateChanged(deviceState); +} + +bool QAudioInputPrivate::open() +{ +#ifdef DEBUG_AUDIO + QTime now(QTime::currentTime()); + qDebug()<start(period_time*chunks/2000); + + errorState = QAudio::NoError; + deviceState = QAudio::ActiveState; + + totalTimeValue = 0; + + return true; +} + +void QAudioInputPrivate::close() +{ + deviceState = QAudio::StopState; + timer->stop(); + + if ( handle ) { + snd_pcm_drop( handle ); + snd_pcm_close( handle ); + handle = 0; + delete [] audioBuffer; + audioBuffer=0; + } +} + +int QAudioInputPrivate::bytesReady() const +{ + if(resuming) + return period_size; + + if(deviceState != QAudio::ActiveState) + return 0; + int frames = snd_pcm_avail_update(handle); + if((int)frames > (int)buffer_frames) + frames = buffer_frames; + + return snd_pcm_frames_to_bytes(handle, frames); +} + +qint64 QAudioInputPrivate::read(char* data, qint64 len) +{ + Q_UNUSED(data) + Q_UNUSED(len) + // Read in some audio data and write it to QIODevice, pull mode + if ( !handle ) + return 0; + + bytesAvailable = bytesReady(); + + int count=0, err = 0; + while(count < 5) { + int chunks = bytesAvailable/period_size; + int frames = chunks*period_frames; + if(frames > (int)buffer_frames) + frames = buffer_frames; + int readFrames = snd_pcm_readi(handle, audioBuffer, frames); + if (readFrames >= 0) { + err = snd_pcm_frames_to_bytes(handle, readFrames); +#ifdef DEBUG_AUDIO + qDebug()< 0) { + // got some send it onward +#ifdef DEBUG_AUDIO + qDebug()<<"PULL: frames to write to QIODevice = "<< + snd_pcm_bytes_to_frames( handle, (int)err )<<" ("<write(audioBuffer,err); + if(l < 0) { + close(); + errorState = QAudio::IOError; + deviceState = QAudio::StopState; + emit stateChanged(deviceState); + } else if(l == 0) { + errorState = QAudio::NoError; + deviceState = QAudio::IdleState; + } else { + totalTimeValue += snd_pcm_bytes_to_frames(handle, err)*1000000/settings.frequency(); + resuming = false; + errorState = QAudio::NoError; + deviceState = QAudio::ActiveState; + } + return l; + } + return 0; +} + +void QAudioInputPrivate::resume() +{ + if(deviceState == QAudio::SuspendState) { + int err = 0; + + if(handle) { + err = snd_pcm_prepare( handle ); + if(err < 0) + xrun_recovery(err); + + err = snd_pcm_start(handle); + if(err < 0) + xrun_recovery(err); + + bytesAvailable = buffer_size; + } + resuming = true; + deviceState = QAudio::ActiveState; + int chunks = buffer_size/period_size; + timer->start(buffer_time*chunks/2000); + emit stateChanged(deviceState); + } +} + +void QAudioInputPrivate::setBufferSize(int value) +{ + buffer_size = value; +} + +int QAudioInputPrivate::bufferSize() const +{ + return buffer_size; +} + +int QAudioInputPrivate::periodSize() const +{ + return period_size; +} + +void QAudioInputPrivate::setNotifyInterval(int ms) +{ + intervalTime = ms; +} + +int QAudioInputPrivate::notifyInterval() const +{ + return intervalTime; +} + +qint64 QAudioInputPrivate::totalTime() const +{ + return totalTimeValue; +} + +void QAudioInputPrivate::suspend() +{ + if(deviceState == QAudio::ActiveState||resuming) { + timer->stop(); + deviceState = QAudio::SuspendState; + emit stateChanged(deviceState); + } +} + +void QAudioInputPrivate::userFeed() +{ + if(deviceState == QAudio::StopState || deviceState == QAudio::SuspendState) + return; +#ifdef DEBUG_AUDIO + QTime now(QTime::currentTime()); + qDebug()<(audioSource); + a->trigger(); + } + bytesAvailable = bytesReady(); + + if(deviceState != QAudio::ActiveState) + return true; + + if(timeStamp.elapsed() > intervalTime && intervalTime > 50) { + emit notify(); + timeStamp.restart(); + } + return true; +} + +qint64 QAudioInputPrivate::clock() const +{ + if(!handle) + return 0; + + if(deviceState != QAudio::ActiveState) + return 0; + + snd_pcm_status_t* status; + snd_pcm_status_alloca(&status); + + snd_timestamp_t t1,t2; + if( snd_pcm_status(handle, status) >= 0) { + snd_pcm_status_get_tstamp(status,&t1); + snd_pcm_status_get_trigger_tstamp(status,&t2); + t1.tv_sec-=t2.tv_sec; + + signed long l = (signed long)t1.tv_usec - (signed long)t2.tv_usec; + if(l < 0) { + t1.tv_sec--; + l = -l; + l %= 1000000; + } + return ((t1.tv_sec * 1000)+l/1000); + } else + return 0; +} + +void QAudioInputPrivate::reset() +{ + if(handle) + snd_pcm_reset(handle); +} + +void QAudioInputPrivate::drain() +{ + if(handle) + snd_pcm_drain(handle); +} + +InputPrivate::InputPrivate(QAudioInputPrivate* audio) +{ + audioDevice = qobject_cast(audio); +} + +InputPrivate::~InputPrivate() +{ +} + +qint64 InputPrivate::readData( char* data, qint64 len) +{ + // push mode, user read() called + if((audioDevice->state() != QAudio::ActiveState) && !audioDevice->resuming) + return 0; + + int readFrames; + int count=0, err = 0; + + while(count < 5) { + int frames = snd_pcm_bytes_to_frames(audioDevice->handle, len); + readFrames = snd_pcm_readi(audioDevice->handle, data, frames); + if (readFrames >= 0) { + err = snd_pcm_frames_to_bytes(audioDevice->handle, readFrames); +#ifdef DEBUG_AUDIO + qDebug()<errorState = QAudio::IOError; + err = 0; + break; + } else { + if(readFrames == -EPIPE) { + audioDevice->errorState = QAudio::UnderrunError; + err = snd_pcm_prepare(audioDevice->handle); + } else if(readFrames == -ESTRPIPE) { + err = snd_pcm_prepare(audioDevice->handle); + } + if(err != 0) break; + } + count++; + } + if(err > 0 && readFrames > 0) { + audioDevice->totalTimeValue += readFrames*1000/audioDevice->settings.frequency()*1000; + audioDevice->deviceState = QAudio::ActiveState; + return err; + } + return 0; +} + +qint64 InputPrivate::writeData(const char* data, qint64 len) +{ + Q_UNUSED(data) + Q_UNUSED(len) + return 0; +} + +void InputPrivate::trigger() +{ + emit readyRead(); +} + diff --git a/src/multimedia/audio/qaudioinput_alsa_p.h b/src/multimedia/audio/qaudioinput_alsa_p.h new file mode 100644 index 000000000..21c8064b0 --- /dev/null +++ b/src/multimedia/audio/qaudioinput_alsa_p.h @@ -0,0 +1,151 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + + +#ifndef QAUDIOINPUTALSA_H +#define QAUDIOINPUTALSA_H + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +class InputPrivate; + +class QAudioInputPrivate : public QAbstractAudioInput +{ + Q_OBJECT +public: + QAudioInputPrivate(const QByteArray &device, const QAudioFormat& audioFormat); + ~QAudioInputPrivate(); + + qint64 read(char* data, qint64 len); + + QIODevice* start(QIODevice* device = 0); + void stop(); + void reset(); + void suspend(); + void resume(); + int bytesReady() const; + int periodSize() const; + void setBufferSize(int value); + int bufferSize() const; + void setNotifyInterval(int milliSeconds); + int notifyInterval() const; + qint64 totalTime() const; + qint64 clock() const; + QAudio::Error error() const; + QAudio::State state() const; + QAudioFormat format() const; + bool resuming; + snd_pcm_t* handle; + qint64 totalTimeValue; + QIODevice* audioSource; + QAudioFormat settings; + QAudio::Error errorState; + QAudio::State deviceState; + +private slots: + void userFeed(); + bool deviceReady(); + +private: + int xrun_recovery(int err); + int setFormat(); + bool open(); + void close(); + void drain(); + + QTimer* timer; + QTime timeStamp; + int intervalTime; + char* audioBuffer; + int bytesAvailable; + QByteArray m_device; + bool pullMode; + int buffer_size; + int period_size; + unsigned int buffer_time; + unsigned int period_time; + snd_pcm_uframes_t buffer_frames; + snd_pcm_uframes_t period_frames; + snd_async_handler_t* ahandler; + snd_pcm_access_t access; + snd_pcm_format_t pcmformat; + snd_timestamp_t* timestamp; + snd_pcm_hw_params_t *hwparams; +}; + +class InputPrivate : public QIODevice +{ + Q_OBJECT +public: + InputPrivate(QAudioInputPrivate* audio); + ~InputPrivate(); + + qint64 readData( char* data, qint64 len); + qint64 writeData(const char* data, qint64 len); + + void trigger(); +private: + QAudioInputPrivate *audioDevice; +}; + +#endif diff --git a/src/multimedia/audio/qaudioinput_mac_p.cpp b/src/multimedia/audio/qaudioinput_mac_p.cpp new file mode 100644 index 000000000..5400c850f --- /dev/null +++ b/src/multimedia/audio/qaudioinput_mac_p.cpp @@ -0,0 +1,930 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include + +#include +#include + +#include "qaudio_mac_p.h" +#include "qaudioinput_mac_p.h" + + +QT_BEGIN_NAMESPACE + + +namespace +{ + +static const int default_buffer_size = 4 * 1024; + +class QAudioBufferList +{ +public: + QAudioBufferList(AudioStreamBasicDescription const& streamFormat): + owner(false), + sf(streamFormat) + { + const bool isInterleaved = (sf.mFormatFlags & kAudioFormatFlagIsNonInterleaved) == 0; + const int numberOfBuffers = isInterleaved ? 1 : sf.mChannelsPerFrame; + + dataSize = 0; + + bfs = reinterpret_cast(qMalloc(sizeof(AudioBufferList) + + (sizeof(AudioBuffer) * numberOfBuffers))); + + bfs->mNumberBuffers = numberOfBuffers; + for (int i = 0; i < numberOfBuffers; ++i) { + bfs->mBuffers[i].mNumberChannels = isInterleaved ? numberOfBuffers : 1; + bfs->mBuffers[i].mDataByteSize = 0; + bfs->mBuffers[i].mData = 0; + } + } + + QAudioBufferList(AudioStreamBasicDescription const& streamFormat, char* buffer, int bufferSize): + owner(false), + sf(streamFormat), + bfs(0) + { + dataSize = bufferSize; + + bfs = reinterpret_cast(qMalloc(sizeof(AudioBufferList) + sizeof(AudioBuffer))); + + bfs->mNumberBuffers = 1; + bfs->mBuffers[0].mNumberChannels = 1; + bfs->mBuffers[0].mDataByteSize = dataSize; + bfs->mBuffers[0].mData = buffer; + } + + QAudioBufferList(AudioStreamBasicDescription const& streamFormat, int framesToBuffer): + owner(true), + sf(streamFormat), + bfs(0) + { + const bool isInterleaved = (sf.mFormatFlags & kAudioFormatFlagIsNonInterleaved) == 0; + const int numberOfBuffers = isInterleaved ? 1 : sf.mChannelsPerFrame; + + dataSize = framesToBuffer * sf.mBytesPerFrame; + + bfs = reinterpret_cast(qMalloc(sizeof(AudioBufferList) + + (sizeof(AudioBuffer) * numberOfBuffers))); + bfs->mNumberBuffers = numberOfBuffers; + for (int i = 0; i < numberOfBuffers; ++i) { + bfs->mBuffers[i].mNumberChannels = isInterleaved ? numberOfBuffers : 1; + bfs->mBuffers[i].mDataByteSize = dataSize; + bfs->mBuffers[i].mData = qMalloc(dataSize); + } + } + + ~QAudioBufferList() + { + if (owner) { + for (UInt32 i = 0; i < bfs->mNumberBuffers; ++i) + qFree(bfs->mBuffers[i].mData); + } + + qFree(bfs); + } + + AudioBufferList* audioBufferList() const + { + return bfs; + } + + char* data(int buffer = 0) const + { + return static_cast(bfs->mBuffers[buffer].mData); + } + + qint64 bufferSize(int buffer = 0) const + { + return bfs->mBuffers[buffer].mDataByteSize; + } + + int frameCount(int buffer = 0) const + { + return bfs->mBuffers[buffer].mDataByteSize / sf.mBytesPerFrame; + } + + int packetCount(int buffer = 0) const + { + return bfs->mBuffers[buffer].mDataByteSize / sf.mBytesPerPacket; + } + + int packetSize() const + { + return sf.mBytesPerPacket; + } + + void reset() + { + for (UInt32 i = 0; i < bfs->mNumberBuffers; ++i) + bfs->mBuffers[i].mDataByteSize = dataSize; + } + +private: + bool owner; + int dataSize; + AudioStreamBasicDescription sf; + AudioBufferList* bfs; +}; + +class QAudioPacketFeeder +{ +public: + QAudioPacketFeeder(QAudioBufferList* abl): + audioBufferList(abl) + { + totalPackets = audioBufferList->packetCount(); + position = 0; + } + + bool feed(AudioBufferList& dst, UInt32& packetCount) + { + if (position == totalPackets) { + dst.mBuffers[0].mDataByteSize = 0; + packetCount = 0; + return false; + } + + if (totalPackets - position < packetCount) + packetCount = totalPackets - position; + + dst.mBuffers[0].mDataByteSize = packetCount * audioBufferList->packetSize(); + dst.mBuffers[0].mData = audioBufferList->data() + (position * audioBufferList->packetSize()); + + position += packetCount; + + return true; + } + +private: + UInt32 totalPackets; + UInt32 position; + QAudioBufferList* audioBufferList; +}; + +class QAudioInputBuffer : public QObject +{ + Q_OBJECT + +public: + QAudioInputBuffer(int bufferSize, + int maxPeriodSize, + AudioStreamBasicDescription const& inputFormat, + AudioStreamBasicDescription const& outputFormat, + QObject* parent): + QObject(parent), + m_deviceError(false), + m_inputFormat(inputFormat), + m_outputFormat(outputFormat) + { + m_maxPeriodSize = maxPeriodSize; + m_periodTime = m_maxPeriodSize / m_outputFormat.mBytesPerFrame * 1000 / m_outputFormat.mSampleRate; + m_buffer = new QAudioRingBuffer(bufferSize + (bufferSize % maxPeriodSize == 0 ? 0 : maxPeriodSize - (bufferSize % maxPeriodSize))); + m_inputBufferList = new QAudioBufferList(m_inputFormat); + + m_flushTimer = new QTimer(this); + connect(m_flushTimer, SIGNAL(timeout()), SLOT(flushBuffer())); + + if (inputFormat.mSampleRate != outputFormat.mSampleRate) { + if (AudioConverterNew(&m_inputFormat, &m_outputFormat, &m_audioConverter) != noErr) { + qWarning() << "QAudioInput: Unable to create an Audio Converter"; + m_audioConverter = 0; + } + } + } + + ~QAudioInputBuffer() + { + delete m_buffer; + } + + qint64 renderFromDevice(AudioUnit audioUnit, + AudioUnitRenderActionFlags* ioActionFlags, + const AudioTimeStamp* inTimeStamp, + UInt32 inBusNumber, + UInt32 inNumberFrames) + { + const bool wasEmpty = m_buffer->used() == 0; + + OSStatus err; + qint64 framesRendered = 0; + + m_inputBufferList->reset(); + err = AudioUnitRender(audioUnit, + ioActionFlags, + inTimeStamp, + inBusNumber, + inNumberFrames, + m_inputBufferList->audioBufferList()); + + if (m_audioConverter != 0) { + QAudioPacketFeeder feeder(m_inputBufferList); + + bool wecan = true; + int copied = 0; + + const int available = m_buffer->free(); + + while (err == noErr && wecan) { + QAudioRingBuffer::Region region = m_buffer->acquireWriteRegion(available); + + if (region.second > 0) { + AudioBufferList output; + output.mNumberBuffers = 1; + output.mBuffers[0].mNumberChannels = 1; + output.mBuffers[0].mDataByteSize = region.second; + output.mBuffers[0].mData = region.first; + + UInt32 packetSize = region.second / m_outputFormat.mBytesPerPacket; + err = AudioConverterFillComplexBuffer(m_audioConverter, + converterCallback, + &feeder, + &packetSize, + &output, + 0); + + region.second = output.mBuffers[0].mDataByteSize; + copied += region.second; + + m_buffer->releaseWriteRegion(region); + } + else + wecan = false; + } + + framesRendered += copied / m_outputFormat.mBytesPerFrame; + } + else { + const int available = m_inputBufferList->bufferSize(); + bool wecan = true; + int copied = 0; + + while (wecan && copied < available) { + QAudioRingBuffer::Region region = m_buffer->acquireWriteRegion(available - copied); + + if (region.second > 0) { + memcpy(region.first, m_inputBufferList->data() + copied, region.second); + copied += region.second; + } + else + wecan = false; + + m_buffer->releaseWriteRegion(region); + } + + framesRendered = copied / m_outputFormat.mBytesPerFrame; + } + + if (wasEmpty && framesRendered > 0) + emit readyRead(); + + return framesRendered; + } + + qint64 readBytes(char* data, qint64 len) + { + bool wecan = true; + qint64 bytesCopied = 0; + + len -= len % m_maxPeriodSize; + while (wecan && bytesCopied < len) { + QAudioRingBuffer::Region region = m_buffer->acquireReadRegion(len - bytesCopied); + + if (region.second > 0) { + memcpy(data + bytesCopied, region.first, region.second); + bytesCopied += region.second; + } + else + wecan = false; + + m_buffer->releaseReadRegion(region); + } + + return bytesCopied; + } + + void setFlushDevice(QIODevice* device) + { + if (m_device != device) + m_device = device; + } + + void startFlushTimer() + { + if (m_device != 0) { + m_flushTimer->start((m_buffer->size() - (m_maxPeriodSize * 2)) / m_maxPeriodSize * m_periodTime); + } + } + + void stopFlushTimer() + { + m_flushTimer->stop(); + } + + void flush(bool all = false) + { + const int used = m_buffer->used(); + const int readSize = all ? used : used - (used % m_maxPeriodSize); + + if (readSize > 0) { + bool wecan = true; + int flushed = 0; + + while (!m_deviceError && wecan && flushed < readSize) { + QAudioRingBuffer::Region region = m_buffer->acquireReadRegion(readSize - flushed); + + if (region.second > 0) { + int bytesWritten = m_device->write(region.first, region.second); + if (bytesWritten < 0) { + stopFlushTimer(); + m_deviceError = true; + } + else { + region.second = bytesWritten; + flushed += bytesWritten; + wecan = bytesWritten != 0; + } + } + else + wecan = false; + + m_buffer->releaseReadRegion(region); + } + } + } + + void reset() + { + m_buffer->reset(); + m_deviceError = false; + } + + int available() const + { + return m_buffer->free(); + } + + int used() const + { + return m_buffer->used(); + } + +signals: + void readyRead(); + +private slots: + void flushBuffer() + { + flush(); + } + +private: + bool m_deviceError; + int m_maxPeriodSize; + int m_periodTime; + QIODevice* m_device; + QTimer* m_flushTimer; + QAudioRingBuffer* m_buffer; + QAudioBufferList* m_inputBufferList; + AudioConverterRef m_audioConverter; + AudioStreamBasicDescription m_inputFormat; + AudioStreamBasicDescription m_outputFormat; + + const static OSStatus as_empty = 'qtem'; + + // Converter callback + static OSStatus converterCallback(AudioConverterRef inAudioConverter, + UInt32* ioNumberDataPackets, + AudioBufferList* ioData, + AudioStreamPacketDescription** outDataPacketDescription, + void* inUserData) + { + Q_UNUSED(inAudioConverter); + Q_UNUSED(outDataPacketDescription); + + QAudioPacketFeeder* feeder = static_cast(inUserData); + + if (!feeder->feed(*ioData, *ioNumberDataPackets)) + return as_empty; + + return noErr; + } +}; + + +class MacInputDevice : public QIODevice +{ + Q_OBJECT + +public: + MacInputDevice(QAudioInputBuffer* audioBuffer, QObject* parent): + QIODevice(parent), + m_audioBuffer(audioBuffer) + { + open(QIODevice::ReadOnly | QIODevice::Unbuffered); + connect(m_audioBuffer, SIGNAL(readyRead()), SIGNAL(readyRead())); + } + + qint64 readData(char* data, qint64 len) + { + return m_audioBuffer->readBytes(data, len); + } + + qint64 writeData(const char* data, qint64 len) + { + Q_UNUSED(data); + Q_UNUSED(len); + + return 0; + } + + bool isSequential() const + { + return true; + } + +private: + QAudioInputBuffer* m_audioBuffer; +}; + +} + + +QAudioInputPrivate::QAudioInputPrivate(const QByteArray& device, QAudioFormat const& format): + audioFormat(format) +{ + QDataStream ds(device); + quint32 did, mode; + + ds >> did >> mode; + + if (QAudio::Mode(mode) == QAudio::AudioOutput) + errorCode = QAudio::OpenError; + else { + isOpen = false; + audioDeviceId = AudioDeviceID(did); + audioUnit = 0; + startTime = 0; + totalFrames = 0; + audioBuffer = 0; + internalBufferSize = default_buffer_size; + clockFrequency = AudioGetHostClockFrequency() / 1000; + errorCode = QAudio::NoError; + stateCode = QAudio::StopState; + + intervalTimer = new QTimer(this); + intervalTimer->setInterval(1000); + connect(intervalTimer, SIGNAL(timeout()), SIGNAL(notify())); + } +} + +QAudioInputPrivate::~QAudioInputPrivate() +{ + close(); +} + +bool QAudioInputPrivate::open() +{ + UInt32 size = 0; + + if (isOpen) + return true; + + ComponentDescription cd; + cd.componentType = kAudioUnitType_Output; + cd.componentSubType = kAudioUnitSubType_HALOutput; + cd.componentManufacturer = kAudioUnitManufacturer_Apple; + cd.componentFlags = 0; + cd.componentFlagsMask = 0; + + // Open + Component cp = FindNextComponent(NULL, &cd); + if (cp == 0) { + qWarning() << "QAudioInput: Failed to find HAL Output component"; + return false; + } + + if (OpenAComponent(cp, &audioUnit) != noErr) { + qWarning() << "QAudioInput: Unable to Open Output Component"; + return false; + } + + // Set mode + // switch to input mode + UInt32 enable = 1; + if (AudioUnitSetProperty(audioUnit, + kAudioOutputUnitProperty_EnableIO, + kAudioUnitScope_Input, + 1, + &enable, + sizeof(enable)) != noErr) { + qWarning() << "QAudioInput: Unabled to switch to input mode (Enable Input)"; + return false; + } + + enable = 0; + if (AudioUnitSetProperty(audioUnit, + kAudioOutputUnitProperty_EnableIO, + kAudioUnitScope_Output, + 0, + &enable, + sizeof(enable)) != noErr) { + qWarning() << "QAudioInput: Unabled to switch to input mode (Disable output)"; + return false; + } + + // register callback + AURenderCallbackStruct cb; + cb.inputProc = inputCallback; + cb.inputProcRefCon = this; + + if (AudioUnitSetProperty(audioUnit, + kAudioOutputUnitProperty_SetInputCallback, + kAudioUnitScope_Global, + 0, + &cb, + sizeof(cb)) != noErr) { + qWarning() << "QAudioInput: Failed to set AudioUnit callback"; + return false; + } + + // Set Audio Device + if (AudioUnitSetProperty(audioUnit, + kAudioOutputUnitProperty_CurrentDevice, + kAudioUnitScope_Global, + 0, + &audioDeviceId, + sizeof(audioDeviceId)) != noErr) { + qWarning() << "QAudioInput: Unable to use configured device"; + return false; + } + + // Set format + streamFormat = toAudioStreamBasicDescription(audioFormat); + + size = sizeof(deviceFormat); + if (AudioUnitGetProperty(audioUnit, + kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Input, + 1, + &deviceFormat, + &size) != noErr) { + qWarning() << "QAudioInput: Unable to retrieve device format"; + return false; + } + + // If the device frequency is different to the requested use a converter + if (deviceFormat.mSampleRate != streamFormat.mSampleRate) { + AudioUnitSetProperty(audioUnit, + kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Output, + 1, + &deviceFormat, + sizeof(streamFormat)); + } + else { + AudioUnitSetProperty(audioUnit, + kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Output, + 1, + &streamFormat, + sizeof(streamFormat)); + } + + // Setup buffers + UInt32 numberOfFrames; + size = sizeof(UInt32); + if (AudioUnitGetProperty(audioUnit, + kAudioDevicePropertyBufferFrameSize, + kAudioUnitScope_Global, + 0, + &numberOfFrames, + &size) != noErr) { + qWarning() << "QAudioInput: Failed to get audio period size"; + return false; + } + + // Allocate buffer + periodSizeBytes = (numberOfFrames * streamFormat.mSampleRate / deviceFormat.mSampleRate) * + streamFormat.mBytesPerFrame; + if (internalBufferSize < periodSizeBytes * 2) + internalBufferSize = periodSizeBytes * 2; + else + internalBufferSize -= internalBufferSize % streamFormat.mBytesPerFrame; + + audioBuffer = new QAudioInputBuffer(internalBufferSize, + periodSizeBytes, + deviceFormat, + streamFormat, + this); + + audioIO = new MacInputDevice(audioBuffer, this); + + // Init + if (AudioUnitInitialize(audioUnit) != noErr) { + qWarning() << "QAudioInput: Failed to initialize AudioUnit"; + return false; + } + + isOpen = true; + + return isOpen; +} + +void QAudioInputPrivate::close() +{ + if (audioUnit != 0) { + AudioOutputUnitStop(audioUnit); + AudioUnitUninitialize(audioUnit); + CloseComponent(audioUnit); + } + + delete audioBuffer; +} + +QAudioFormat QAudioInputPrivate::format() const +{ + return audioFormat; +} + +QIODevice* QAudioInputPrivate::start(QIODevice* device) +{ + QIODevice* op = device; + + if (!open()) { + stateCode = QAudio::StopState; + errorCode = QAudio::OpenError; + return audioIO; + } + + reset(); + audioBuffer->reset(); + audioBuffer->setFlushDevice(op); + + if (op == 0) + op = audioIO; + + // Start + startTime = AudioGetCurrentHostTime(); + totalFrames = 0; + + audioThreadStart(); + + return op; +} + +void QAudioInputPrivate::stop() +{ + QMutexLocker lock(&mutex); + if (stateCode != QAudio::StopState) { + audioThreadStop(); + audioBuffer->flush(true); + + errorCode = QAudio::NoError; + stateCode = QAudio::StopState; + QMetaObject::invokeMethod(this, "stateChanged", Qt::QueuedConnection, Q_ARG(QAudio::State, stateCode)); + } +} + +void QAudioInputPrivate::reset() +{ + QMutexLocker lock(&mutex); + if (stateCode != QAudio::StopState) { + audioThreadStop(); + + errorCode = QAudio::NoError; + stateCode = QAudio::StopState; + QMetaObject::invokeMethod(this, "stateChanged", Qt::QueuedConnection, Q_ARG(QAudio::State, stateCode)); + } +} + +void QAudioInputPrivate::suspend() +{ + QMutexLocker lock(&mutex); + if (stateCode == QAudio::ActiveState || stateCode == QAudio::IdleState) { + audioThreadStop(); + + errorCode = QAudio::NoError; + stateCode = QAudio::SuspendState; + QMetaObject::invokeMethod(this, "stateChanged", Qt::QueuedConnection, Q_ARG(QAudio::State, stateCode)); + } +} + +void QAudioInputPrivate::resume() +{ + QMutexLocker lock(&mutex); + if (stateCode == QAudio::SuspendState) { + audioThreadStart(); + + errorCode = QAudio::NoError; + stateCode = QAudio::ActiveState; + QMetaObject::invokeMethod(this, "stateChanged", Qt::QueuedConnection, Q_ARG(QAudio::State, stateCode)); + } +} + +int QAudioInputPrivate::bytesReady() const +{ + return audioBuffer->used(); +} + +int QAudioInputPrivate::periodSize() const +{ + return periodSizeBytes; +} + +void QAudioInputPrivate::setBufferSize(int bs) +{ + internalBufferSize = bs; +} + +int QAudioInputPrivate::bufferSize() const +{ + return internalBufferSize; +} + +void QAudioInputPrivate::setNotifyInterval(int milliSeconds) +{ + intervalTimer->setInterval(milliSeconds); +} + +int QAudioInputPrivate::notifyInterval() const +{ + return intervalTimer->interval(); +} + +qint64 QAudioInputPrivate::totalTime() const +{ + return totalFrames * 1000000 / audioFormat.frequency(); +} + +qint64 QAudioInputPrivate::clock() const +{ + return (AudioGetCurrentHostTime() - startTime) / (clockFrequency / 1000); +} + +QAudio::Error QAudioInputPrivate::error() const +{ + return errorCode; +} + +QAudio::State QAudioInputPrivate::state() const +{ + return stateCode; +} + +void QAudioInputPrivate::audioThreadStop() +{ + stopTimers(); + if (audioThreadState.testAndSetAcquire(Running, Stopped)) + threadFinished.wait(&mutex); +} + +void QAudioInputPrivate::audioThreadStart() +{ + startTimers(); + audioThreadState = Running; + AudioOutputUnitStart(audioUnit); +} + +void QAudioInputPrivate::audioDeviceStop() +{ + AudioOutputUnitStop(audioUnit); + audioThreadState = Stopped; + threadFinished.wakeOne(); +} + +void QAudioInputPrivate::audioDeviceFull() +{ + QMutexLocker lock(&mutex); + if (stateCode == QAudio::ActiveState) { + audioDeviceStop(); + + errorCode = QAudio::UnderrunError; + stateCode = QAudio::IdleState; + QMetaObject::invokeMethod(this, "deviceStopped", Qt::QueuedConnection); + } +} + +void QAudioInputPrivate::audioDeviceError() +{ + QMutexLocker lock(&mutex); + if (stateCode == QAudio::ActiveState) { + audioDeviceStop(); + + errorCode = QAudio::IOError; + stateCode = QAudio::StopState; + QMetaObject::invokeMethod(this, "deviceStopped", Qt::QueuedConnection); + } +} + +void QAudioInputPrivate::startTimers() +{ + audioBuffer->startFlushTimer(); + intervalTimer->start(); +} + +void QAudioInputPrivate::stopTimers() +{ + audioBuffer->stopFlushTimer(); + intervalTimer->stop(); +} + +void QAudioInputPrivate::deviceStopped() +{ + stopTimers(); + emit stateChanged(stateCode); +} + +// Input callback +OSStatus QAudioInputPrivate::inputCallback(void* inRefCon, + AudioUnitRenderActionFlags* ioActionFlags, + const AudioTimeStamp* inTimeStamp, + UInt32 inBusNumber, + UInt32 inNumberFrames, + AudioBufferList* ioData) +{ + Q_UNUSED(ioData); + + QAudioInputPrivate* d = static_cast(inRefCon); + + const int threadState = d->audioThreadState.fetchAndAddAcquire(0); + if (threadState == Stopped) + d->audioDeviceStop(); + else { + qint64 framesWritten; + + framesWritten = d->audioBuffer->renderFromDevice(d->audioUnit, + ioActionFlags, + inTimeStamp, + inBusNumber, + inNumberFrames); + + if (framesWritten > 0) + d->totalFrames += framesWritten; + else if (framesWritten == 0) + d->audioDeviceFull(); + else if (framesWritten < 0) + d->audioDeviceError(); + } + + return noErr; +} + + +QT_END_NAMESPACE + +#include "qaudioinput_mac_p.moc" + diff --git a/src/multimedia/audio/qaudioinput_mac_p.h b/src/multimedia/audio/qaudioinput_mac_p.h new file mode 100644 index 000000000..98ef9ce2f --- /dev/null +++ b/src/multimedia/audio/qaudioinput_mac_p.h @@ -0,0 +1,171 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + + +#ifndef QAUDIOINPUT_MAC_P_H +#define QAUDIOINPUT_MAC_P_H + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QTimer; +class QIODevice; + +namespace +{ +class QAudioInputBuffer; +} + +class QAudioInputPrivate : public QAbstractAudioInput +{ + Q_OBJECT + +public: + bool isOpen; + int periodSizeBytes; + int internalBufferSize; + qint64 totalFrames; + QAudioFormat audioFormat; + QIODevice* audioIO; + AudioUnit audioUnit; + AudioDeviceID audioDeviceId; + Float64 clockFrequency; + UInt64 startTime; + QAudio::Error errorCode; + QAudio::State stateCode; + QAudioInputBuffer* audioBuffer; + QMutex mutex; + QWaitCondition threadFinished; + QAtomicInt audioThreadState; + QTimer* intervalTimer; + AudioStreamBasicDescription streamFormat; + AudioStreamBasicDescription deviceFormat; + + QAudioInputPrivate(const QByteArray& device, QAudioFormat const& format); + ~QAudioInputPrivate(); + + bool open(); + void close(); + + QAudioFormat format() const; + + QIODevice* start(QIODevice* device); + void stop(); + void reset(); + void suspend(); + void resume(); + void idle(); + + int bytesReady() const; + int periodSize() const; + + void setBufferSize(int value); + int bufferSize() const; + + void setNotifyInterval(int milliSeconds); + int notifyInterval() const; + + qint64 totalTime() const; + qint64 clock() const; + + QAudio::Error error() const; + QAudio::State state() const; + + void audioThreadStart(); + void audioThreadStop(); + + void audioDeviceStop(); + void audioDeviceFull(); + void audioDeviceError(); + + void startTimers(); + void stopTimers(); + +signals: + void stateChanged(QAudio::State); + void notify(); + +private slots: + void deviceStopped(); + +private: + enum { Running, Stopped }; + + // Input callback + static OSStatus inputCallback(void* inRefCon, + AudioUnitRenderActionFlags* ioActionFlags, + const AudioTimeStamp* inTimeStamp, + UInt32 inBusNumber, + UInt32 inNumberFrames, + AudioBufferList* ioData); +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QAUDIOINPUT_MAC_P_H diff --git a/src/multimedia/audio/qaudioinput_win32_p.cpp b/src/multimedia/audio/qaudioinput_win32_p.cpp new file mode 100644 index 000000000..e5b6e0d74 --- /dev/null +++ b/src/multimedia/audio/qaudioinput_win32_p.cpp @@ -0,0 +1,540 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + + +#include "qaudioinput_win32_p.h" + +//#define DEBUG_AUDIO 1 + + +QAudioInputPrivate::QAudioInputPrivate(const QByteArray &device, const QAudioFormat& audioFormat): + settings(audioFormat) +{ + bytesAvailable = 0; + buffer_size = 0; + period_size = 0; + m_device = device; + totalTimeValue = 0; + intervalTime = 1000; + errorState = QAudio::NoError; + deviceState = QAudio::StopState; + audioSource = 0; + pullMode = true; + resuming = false; + + connect(this,SIGNAL(processMore()),SLOT(deviceReady())); + + InitializeCriticalSection(&waveInCriticalSection); +} + +QAudioInputPrivate::~QAudioInputPrivate() +{ + close(); + DeleteCriticalSection(&waveInCriticalSection); +} + +void CALLBACK QAudioInputPrivate::waveInProc( HWAVEIN hWaveIn, UINT uMsg, + DWORD dwInstance, DWORD dwParam1, DWORD dwParam2 ) +{ + Q_UNUSED(dwParam1) + Q_UNUSED(dwParam2) + Q_UNUSED(hWaveIn) + + QAudioInputPrivate* qAudio; + qAudio = (QAudioInputPrivate*)(dwInstance); + if(!qAudio) + return; + + switch(uMsg) { + case WIM_OPEN: + break; + case WIM_DATA: + EnterCriticalSection(&waveInCriticalSection); + if(qAudio->waveFreeBlockCount > 0) + qAudio->waveFreeBlockCount--; + LeaveCriticalSection(&waveInCriticalSection); + qAudio->feedback(); + break; + case WIM_CLOSE: + break; + default: + return; + } +} + +WAVEHDR* QAudioInputPrivate::allocateBlocks(int size, int count) +{ + int i; + unsigned char* buffer; + WAVEHDR* blocks; + DWORD totalBufferSize = (size + sizeof(WAVEHDR))*count; + + if((buffer=(unsigned char*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, + totalBufferSize)) == 0) { + qWarning("QAudioInput: Memory allocation error"); + return 0; + } + blocks = (WAVEHDR*)buffer; + buffer += sizeof(WAVEHDR)*count; + for(i = 0; i < count; i++) { + blocks[i].dwBufferLength = size; + blocks[i].lpData = (LPSTR)buffer; + blocks[i].dwBytesRecorded=0; + blocks[i].dwUser = 0L; + blocks[i].dwFlags = 0L; + blocks[i].dwLoops = 0L; + result = waveInPrepareHeader(hWaveIn,&blocks[i], sizeof(WAVEHDR)); + if(result != MMSYSERR_NOERROR) { + qWarning("QAudioInput: Can't prepare block %d",i); + return 0; + } + buffer += size; + } + return blocks; +} + +void QAudioInputPrivate::freeBlocks(WAVEHDR* blockArray) +{ + HeapFree(GetProcessHeap(), 0, blockArray); +} + +QAudio::Error QAudioInputPrivate::error() const +{ + return errorState; +} + +QAudio::State QAudioInputPrivate::state() const +{ + return deviceState; +} + +QAudioFormat QAudioInputPrivate::format() const +{ + return settings; +} + +QIODevice* QAudioInputPrivate::start(QIODevice* device) +{ + if(deviceState != QAudio::StopState) + close(); + + if(!pullMode && audioSource) { + delete audioSource; + } + + if(device) { + //set to pull mode + pullMode = true; + audioSource = device; + } else { + //set to push mode + pullMode = false; + audioSource = new InputPrivate(this); + audioSource->open(QIODevice::ReadOnly | QIODevice::Unbuffered); + } + + if( !open() ) + return 0; + + emit stateChanged(deviceState); + + return audioSource; +} + +void QAudioInputPrivate::stop() +{ + if(deviceState == QAudio::StopState) + return; + + deviceState = QAudio::StopState; + + close(); + emit stateChanged(deviceState); +} + +bool QAudioInputPrivate::open() +{ +#ifdef DEBUG_AUDIO + QTime now(QTime::currentTime()); + qDebug()<> 3) * wfx.nChannels; + wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec; + + UINT_PTR devId = WAVE_MAPPER; + + WAVEINCAPS wic; + unsigned long iNumDevs,ii; + iNumDevs = waveInGetNumDevs(); + for(ii=0;ii 0) { + if(pullMode) { + l = audioSource->write(waveBlocks[header].lpData, + waveBlocks[header].dwBytesRecorded); +#ifdef DEBUG_AUDIO + qDebug()<<"IN: "<= buffer_size/period_size) + header = 0; + p+=l; + + if(!pullMode) { + if(l+period_size > len && waveFreeBlockCount == buffer_size/period_size) + done = true; + } else { + if(waveFreeBlockCount == buffer_size/period_size) + done = true; + } + written+=l; + } +#ifdef DEBUG_AUDIO + qDebug()<<"read in len="<(audioSource); + a->trigger(); + } + if(deviceState != QAudio::ActiveState) + return true; + + if(timeStamp.elapsed() > intervalTime && intervalTime > 50) { + emit notify(); + timeStamp.restart(); + } + return true; +} + +qint64 QAudioInputPrivate::clock() const +{ + if(deviceState != QAudio::ActiveState) + return 0; + + return timeStampOpened.elapsed(); +} + +void QAudioInputPrivate::reset() +{ + close(); +} + +InputPrivate::InputPrivate(QAudioInputPrivate* audio) +{ + audioDevice = qobject_cast(audio); +} + +InputPrivate::~InputPrivate() {} + +qint64 InputPrivate::readData( char* data, qint64 len) +{ + // push mode, user read() called + if(audioDevice->deviceState != QAudio::ActiveState) + return 0; + // Read in some audio data + return audioDevice->read(data,len); +} + +qint64 InputPrivate::writeData(const char* data, qint64 len) +{ + Q_UNUSED(data) + Q_UNUSED(len) + + emit readyRead(); + return 0; +} + +void InputPrivate::trigger() +{ + emit readyRead(); +} + diff --git a/src/multimedia/audio/qaudioinput_win32_p.h b/src/multimedia/audio/qaudioinput_win32_p.h new file mode 100644 index 000000000..32464f0c3 --- /dev/null +++ b/src/multimedia/audio/qaudioinput_win32_p.h @@ -0,0 +1,154 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QAUDIOINPUTWIN_H +#define QAUDIOINPUTWIN_H + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +static CRITICAL_SECTION waveInCriticalSection; + +class QAudioInputPrivate : public QAbstractAudioInput +{ + Q_OBJECT +public: + QAudioInputPrivate(const QByteArray &device, const QAudioFormat& audioFormat); + ~QAudioInputPrivate(); + + qint64 read(char* data, qint64 len); + + QAudioFormat format() const; + QIODevice* start(QIODevice* device = 0); + void stop(); + void reset(); + void suspend(); + void resume(); + int bytesReady() const; + int periodSize() const; + void setBufferSize(int value); + int bufferSize() const; + void setNotifyInterval(int milliSeconds); + int notifyInterval() const; + qint64 totalTime() const; + qint64 clock() const; + QAudio::Error error() const; + QAudio::State state() const; + + QIODevice* audioSource; + QAudioFormat settings; + QAudio::Error errorState; + QAudio::State deviceState; + +private: + qint32 buffer_size; + qint32 period_size; + qint32 header; + QByteArray m_device; + int bytesAvailable; + int intervalTime; + QTime timeStamp; + QTime timeStampOpened; + qint64 totalTimeValue; + bool pullMode; + bool resuming; + WAVEFORMATEX wfx; + HWAVEIN hWaveIn; + MMRESULT result; + WAVEHDR* waveBlocks; + volatile int waveFreeBlockCount; + int waveCurrentBlock; + + static void CALLBACK waveInProc( HWAVEIN hWaveIn, UINT uMsg, + DWORD dwInstance, DWORD dwParam1, DWORD dwParam2 ); + + WAVEHDR* allocateBlocks(int size, int count); + void freeBlocks(WAVEHDR* blockArray); + bool open(); + void close(); + +private slots: + void feedback(); + bool deviceReady(); + +signals: + void processMore(); +}; + +class InputPrivate : public QIODevice +{ + Q_OBJECT +public: + InputPrivate(QAudioInputPrivate* audio); + ~InputPrivate(); + + qint64 readData( char* data, qint64 len); + qint64 writeData(const char* data, qint64 len); + + void trigger(); +private: + QAudioInputPrivate *audioDevice; +}; + +#endif diff --git a/src/multimedia/audio/qaudiooutput.cpp b/src/multimedia/audio/qaudiooutput.cpp new file mode 100644 index 000000000..785da6121 --- /dev/null +++ b/src/multimedia/audio/qaudiooutput.cpp @@ -0,0 +1,403 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include +#include +#include +#include + +#include "qaudiodevicefactory_p.h" + + +QT_BEGIN_NAMESPACE + +/*! + \class QAudioOutput + \brief The QAudioOutput class provides an interface for sending audio data to an audio output device. + + \inmodule QtMultimedia + \ingroup multimedia + \since 4.6 + + You can construct an audio output with the system's + \l{QAudioDeviceInfo::defaultOutputDevice()}{default audio output + device}. It is also possible to create QAudioOutput with a + specific QAudioDeviceId. When you create the audio output, you + should also send in the QAudioFormat to be used for the playback + (see the QAudioFormat class description for details). + + To play a file: + + Starting to play an audio stream is simply a matter of calling + start() with a QIODevice. QAudioOutput will then fetch the data it + needs from the io device. So playing back an audio file is as + simple as: + + \code + QFile inputFile; + inputFile.setFileName("/tmp/test.raw"); + inputFile.open(QIODevice::ReadOnly); + + QAudioFormat format; + // Set up the format, eg. + format.setFrequency(8000); + format.setChannels(1); + format.setSampleSize(8); + format.setCodec("audio/pcm"); + format.setByteOrder(QAudioFormat::LittleEndian); + format.setSampleType(QAudioFormat::UnSignedInt); + + QAudioOutput *audio = new QAudioOutput(format, this); + connect(audio,SIGNAL(stateChanged(QAudio::State)),SLOT(finishedPlaying(QAudio::State))); + audio->start(inputFile); + + \endcode + + The file will start playing assuming that the audio system and + output device support it. If you run out of luck, check what's + up with the error() function. + + After the file has finished playing, we need to stop the device: + + \code + void finishedPlaying(QAudio::State state) + { + if(state == QAudio::IdleState) { + audio->stop(); + inputFile.close(); + } + } + \endcode + + At any given time, the QAudioOutput will be in one of four states: + active, suspended, stopped, or idle. These states are described + by the QAudio::State enum. + State changes are reported through the stateChanged() signal. You + can use this signal to, for instance, update the GUI of the + application; the mundane example here being changing the state of + a \c { play/pause } button. You request a state change directly + with suspend(), stop(), reset(), resume(), and start(). + + While the stream is playing, you can set a notify interval in + milliseconds with setNotifyInterval(). This interval specifies the + time between two emissions of the notify() signal. This is + relative to the position in the stream, i.e., if the QAudioOutput + is in the SuspendedState or the IdleState, the notify() signal is + not emitted. A typical use-case would be to update a + \l{QSlider}{slider} that allows seeking in the stream. + If you want the time since playback started regardless of which + states the audio output has been in, clock() is the function for you. + + If an error occurs, you can fetch the \l{QAudio::Error}{error + type} with the error() function. Please see the QAudio::Error enum + for a description of the possible errors that are reported. + + If an error is encountered state changes to QAudio::StopState. + + \sa QAudioInput, QAudioDeviceInfo +*/ + +/*! + Construct a new audio output and attach it to \a parent. + The default audio output device is used with the output + \a format parameters. +*/ + +QAudioOutput::QAudioOutput(const QAudioFormat &format, QObject *parent): + QObject(parent) +{ + d = QAudioDeviceFactory::createDefaultOutputDevice(format); + connect(d, SIGNAL(notify()), SIGNAL(notify())); + connect(d, SIGNAL(stateChanged(QAudio::State)), SIGNAL(stateChanged(QAudio::State))); +} + +/*! + Construct a new audio output and attach it to \a parent. + The \a id of the audio output device is used with the output + \a format parameters. +*/ + +QAudioOutput::QAudioOutput(const QAudioDeviceId &id, const QAudioFormat &format, QObject *parent): + QObject(parent) +{ + d = QAudioDeviceFactory::createOutputDevice(id, format); + connect(d, SIGNAL(notify()), SIGNAL(notify())); + connect(d, SIGNAL(stateChanged(QAudio::State)), SIGNAL(stateChanged(QAudio::State))); +} + +/*! + Destroys this audio output. +*/ + +QAudioOutput::~QAudioOutput() +{ + delete d; +} + +/*! + Returns the QAudioFormat being used. + +*/ + +QAudioFormat QAudioOutput::format() const +{ + return d->format(); +} + +/*! + Uses the \a device as the QIODevice to transfer data. + If \a device is null then the class creates an internal QIODevice. + Returns a pointer to the QIODevice being used to handle the data + transfer. This QIODevice can be used to write() audio data + directly. + Passing a QIODevice allows the data to be transfered without any extra code. + All that is required is to open the QIODevice. + + /sa QIODevice +*/ + +QIODevice* QAudioOutput::start(QIODevice* device) +{ + /* + PULL MODE (valid QIODevice) + -If currently not StopState, stop. + -If previous start was push mode, delete internal QIODevice. + -open audio output. + -If ok, NoError and ActiveState, else OpenError and StopState + -emit stateChanged() + -return device + + PUSH MODE (device = 0) + -If currently not StopState, stop. + -If no internal QIODevice, create one. + -open audio output. + -If ok, NoError and IdleState, else OpenError and StopState + -emit stateChanged() + -return internal QIODevice + */ + return d->start(device); +} + +/*! + Stops the audio output. +*/ + +void QAudioOutput::stop() +{ + /* + -If StopState, return + -set to StopState + -detach from audio device + -emit stateChanged() + */ + d->stop(); +} + +/*! + Drops all audio data in the buffers, resets buffers to zero. +*/ + +void QAudioOutput::reset() +{ + /* + -drop all buffered audio, set buffers to zero. + -call stop() + */ + d->reset(); +} + +/*! + Stops processing audio data, preserving buffered audio data. +*/ + +void QAudioOutput::suspend() +{ + /* + -If not ActiveState|IdleState, return + -stop processing audio, saving all buffered audio data + -set NoError and SuspendState + -emit stateChanged() + */ + d->suspend(); +} + +/*! + Resumes processing audio data after a suspend(). +*/ + +void QAudioOutput::resume() +{ + /* + -If SuspendState, return + -resume audio + -(PULL MODE): set ActiveState, NoError + -(PUSH MODE): set IdleState, NoError + -kick start audio if needed + -emit stateChanged() + */ + d->resume(); +} + +/*! + Returns the free space available in bytes in the audio buffer. +*/ + +int QAudioOutput::bytesFree() const +{ + /* + -If not ActiveState|IdleState, return 0 + -return space available in audio buffer in bytes + */ + return d->bytesFree(); +} + +/*! + Returns the period size in bytes. + + Note: This is the recommended write size in bytes. +*/ + +int QAudioOutput::periodSize() const +{ + return d->periodSize(); +} + +/*! + Sets the audio buffer size to \a value in bytes. + + Note: This function can be called anytime before start(), calls to this + are ignored after start(). It should not be assumed that the buffer size + set is the actual buffer size used, calling bufferSize() anytime after start() + will return the actual buffer size being used. +*/ + +void QAudioOutput::setBufferSize(int value) +{ + d->setBufferSize(value); +} + +/*! + Returns the audio buffer size in bytes. + + If called before start(), returns platform default value. + If called before start() but setBufferSize() was called prior, returns value set by setBufferSize(). + If called after start(), returns the actual buffer size being used. This may not be what was set previously + by setBufferSize(). + +*/ + +int QAudioOutput::bufferSize() const +{ + return d->bufferSize(); +} + +/*! + Sets the interval for notify() signal to be emitted. + This is based on the \a ms of audio data processed + not on actual real-time. The resolution of the timer is platform specific. +*/ + +void QAudioOutput::setNotifyInterval(int ms) +{ + d->setNotifyInterval(ms); +} + +/*! + Returns the notify interval in milliseconds. +*/ + +int QAudioOutput::notifyInterval() const +{ + return d->notifyInterval(); +} + +/*! + Returns the amount of audio data processed since start() + was called in microseconds. +*/ + +qint64 QAudioOutput::totalTime() const +{ + return d->totalTime(); +} + +/*! + Returns the microseconds since start() was called, including time in Idle and + Suspend states. +*/ + +qint64 QAudioOutput::clock() const +{ + return d->clock(); +} + +/*! + Returns the error state. +*/ + +QAudio::Error QAudioOutput::error() const +{ + return d->error(); +} + +/*! + Returns the state of audio processing. +*/ + +QAudio::State QAudioOutput::state() const +{ + return d->state(); +} + +/*! + \fn QAudioOutput::stateChanged(QAudio::State state) + This signal is emitted when the device \a state has changed. + This is the current state of the audio output. +*/ + +/*! + \fn QAudioOutput::notify() + This signal is emitted when x ms of audio data has been processed + the interval set by setNotifyInterval(x). +*/ + +QT_END_NAMESPACE diff --git a/src/multimedia/audio/qaudiooutput.h b/src/multimedia/audio/qaudiooutput.h new file mode 100644 index 000000000..95e28eada --- /dev/null +++ b/src/multimedia/audio/qaudiooutput.h @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QAUDIOOUTPUT_H +#define QAUDIOOUTPUT_H + +#include +#include + +#include +#include +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QAbstractAudioOutput; + +class Q_MULTIMEDIA_EXPORT QAudioOutput : public QObject +{ + Q_OBJECT + +public: + explicit QAudioOutput(const QAudioFormat &format = QAudioFormat(), QObject *parent = 0); + explicit QAudioOutput(const QAudioDeviceId &id, const QAudioFormat &format = QAudioFormat(), QObject *parent = 0); + ~QAudioOutput(); + + QAudioFormat format() const; + + QIODevice* start(QIODevice *device = 0); + void stop(); + void reset(); + void suspend(); + void resume(); + + void setBufferSize(int bytes); + int bufferSize() const; + + int bytesFree() const; + int periodSize() const; + + void setNotifyInterval(int milliSeconds); + int notifyInterval() const; + + qint64 totalTime() const; + qint64 clock() const; + + QAudio::Error error() const; + QAudio::State state() const; + +Q_SIGNALS: + void stateChanged(QAudio::State); + void notify(); + +private: + Q_DISABLE_COPY(QAudioOutput) + + QAbstractAudioOutput* d; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QAUDIOOUTPUT_H diff --git a/src/multimedia/audio/qaudiooutput_alsa_p.cpp b/src/multimedia/audio/qaudiooutput_alsa_p.cpp new file mode 100644 index 000000000..d41c449cc --- /dev/null +++ b/src/multimedia/audio/qaudiooutput_alsa_p.cpp @@ -0,0 +1,706 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include "qaudiooutput_alsa_p.h" + +//#define DEBUG_AUDIO 1 + +QAudioOutputPrivate::QAudioOutputPrivate(const QByteArray &device, const QAudioFormat& audioFormat): + settings(audioFormat) +{ + bytesAvailable = 0; + handle = 0; + ahandler = 0; + access = SND_PCM_ACCESS_RW_INTERLEAVED; + pcmformat = SND_PCM_FORMAT_S16; + buffer_frames = 0; + period_frames = 0; + buffer_size = 0; + period_size = 0; + buffer_time = 100000; + period_time = 20000; + totalTimeValue = 0; + intervalTime = 1000; + audioBuffer = 0; + errorState = QAudio::NoError; + deviceState = QAudio::StopState; + audioSource = 0; + pullMode = true; + resuming = false; + opened = false; + + QStringList list1 = QString(tr(device)).split(tr(":")); + m_device = QByteArray(list1.at(0).toLocal8Bit().constData()); + + timer = new QTimer(this); + connect(timer,SIGNAL(timeout()),SLOT(userFeed())); +} + +QAudioOutputPrivate::~QAudioOutputPrivate() +{ + close(); + disconnect(timer, SIGNAL(timeout())); + QCoreApplication::processEvents(); + delete timer; +} + +QAudio::Error QAudioOutputPrivate::error() const +{ + return errorState; +} + +QAudio::State QAudioOutputPrivate::state() const +{ + return deviceState; +} + +void QAudioOutputPrivate::async_callback(snd_async_handler_t *ahandler) +{ + QAudioOutputPrivate* audioOut; + + audioOut = static_cast + (snd_async_handler_get_callback_private(ahandler)); + + if((audioOut->deviceState==QAudio::ActiveState)||(audioOut->resuming)) + audioOut->feedback(); +} + +int QAudioOutputPrivate::xrun_recovery(int err) +{ + int count = 0; + bool reset = false; + + if(err == -EPIPE) { + errorState = QAudio::UnderrunError; + err = snd_pcm_prepare(handle); + if(err < 0) + reset = true; + + } else if((err == -ESTRPIPE)||(err == -EIO)) { + errorState = QAudio::IOError; + while((err = snd_pcm_resume(handle)) == -EAGAIN){ + usleep(100); + count++; + if(count > 5) { + reset = true; + break; + } + } + if(err < 0) { + err = snd_pcm_prepare(handle); + if(err < 0) + reset = true; + } + } + if(reset) { + close(); + open(); + snd_pcm_prepare(handle); + return 0; + } + return err; +} + +int QAudioOutputPrivate::setFormat() +{ + snd_pcm_format_t pcmformat = SND_PCM_FORMAT_S16; + + if(settings.sampleSize() == 8) { + pcmformat = SND_PCM_FORMAT_U8; + + } else if(settings.sampleSize() == 16) { + if(settings.sampleType() == QAudioFormat::SignedInt) { + if(settings.byteOrder() == QAudioFormat::LittleEndian) + pcmformat = SND_PCM_FORMAT_S16_LE; + else + pcmformat = SND_PCM_FORMAT_S16_BE; + } else if(settings.sampleType() == QAudioFormat::UnSignedInt) { + if(settings.byteOrder() == QAudioFormat::LittleEndian) + pcmformat = SND_PCM_FORMAT_U16_LE; + else + pcmformat = SND_PCM_FORMAT_U16_BE; + } + } else if(settings.sampleSize() == 24) { + if(settings.sampleType() == QAudioFormat::SignedInt) { + if(settings.byteOrder() == QAudioFormat::LittleEndian) + pcmformat = SND_PCM_FORMAT_S24_LE; + else + pcmformat = SND_PCM_FORMAT_S24_BE; + } else if(settings.sampleType() == QAudioFormat::UnSignedInt) { + if(settings.byteOrder() == QAudioFormat::LittleEndian) + pcmformat = SND_PCM_FORMAT_U24_LE; + else + pcmformat = SND_PCM_FORMAT_U24_BE; + } + } else if(settings.sampleSize() == 32) { + if(settings.sampleType() == QAudioFormat::SignedInt) { + if(settings.byteOrder() == QAudioFormat::LittleEndian) + pcmformat = SND_PCM_FORMAT_S32_LE; + else + pcmformat = SND_PCM_FORMAT_S32_BE; + } else if(settings.sampleType() == QAudioFormat::UnSignedInt) { + if(settings.byteOrder() == QAudioFormat::LittleEndian) + pcmformat = SND_PCM_FORMAT_U32_LE; + else + pcmformat = SND_PCM_FORMAT_U32_BE; + } else if(settings.sampleType() == QAudioFormat::Float) { + if(settings.byteOrder() == QAudioFormat::LittleEndian) + pcmformat = SND_PCM_FORMAT_FLOAT_LE; + else + pcmformat = SND_PCM_FORMAT_FLOAT_BE; + } + } else if(settings.sampleSize() == 64) { + if(settings.byteOrder() == QAudioFormat::LittleEndian) + pcmformat = SND_PCM_FORMAT_FLOAT64_LE; + else + pcmformat = SND_PCM_FORMAT_FLOAT64_BE; + } + + return snd_pcm_hw_params_set_format( handle, hwparams, pcmformat); +} + +QIODevice* QAudioOutputPrivate::start(QIODevice* device) +{ + if(deviceState != QAudio::StopState) + deviceState = QAudio::StopState; + + errorState = QAudio::NoError; + + // Handle change of mode + if(audioSource && pullMode && !device) { + // pull -> push + close(); + audioSource = 0; + } else if(audioSource && !pullMode && device) { + // push -> pull + close(); + delete audioSource; + audioSource = 0; + } + + if(device) { + //set to pull mode + pullMode = true; + audioSource = device; + deviceState = QAudio::ActiveState; + } else { + //set to push mode + if(!audioSource) { + audioSource = new OutputPrivate(this); + audioSource->open(QIODevice::WriteOnly|QIODevice::Unbuffered); + } + pullMode = false; + deviceState = QAudio::IdleState; + } + + open(); + + emit stateChanged(deviceState); + + return audioSource; +} + +void QAudioOutputPrivate::stop() +{ + if(deviceState == QAudio::StopState) + return; + deviceState = QAudio::StopState; + close(); + emit stateChanged(deviceState); +} + +bool QAudioOutputPrivate::open() +{ + if(opened) + return true; + +#ifdef DEBUG_AUDIO + QTime now(QTime::currentTime()); + qDebug()<start(period_time/1000); + + errorState = QAudio::NoError; + totalTimeValue = 0; + opened = true; + + return true; +} + +void QAudioOutputPrivate::close() +{ + deviceState = QAudio::StopState; + timer->stop(); + + if ( handle ) { + snd_pcm_drain( handle ); + snd_pcm_close( handle ); + handle = 0; + delete [] audioBuffer; + audioBuffer=0; + } + if(!pullMode && audioSource) { + delete audioSource; + audioSource = 0; + } + opened = false; +} + +int QAudioOutputPrivate::bytesFree() const +{ + if(resuming) + return period_size; + + if(deviceState != QAudio::ActiveState && deviceState != QAudio::IdleState) + return 0; + int frames = snd_pcm_avail_update(handle); + if((int)frames > (int)buffer_frames) + frames = buffer_frames; + + return snd_pcm_frames_to_bytes(handle, frames); +} + +qint64 QAudioOutputPrivate::write( const char *data, qint64 len ) +{ + // Write out some audio data + if ( !handle ) + return 0; +#ifdef DEBUG_AUDIO + qDebug()<<"frames to write out = "<< + snd_pcm_bytes_to_frames( handle, (int)len )<<" ("< 0) { + totalTimeValue += err*1000000/settings.frequency(); + resuming = false; + errorState = QAudio::NoError; + deviceState = QAudio::ActiveState; + return snd_pcm_frames_to_bytes( handle, err ); + } else + err = xrun_recovery(err); + + if(err < 0) { + close(); + errorState = QAudio::FatalError; + deviceState = QAudio::StopState; + emit stateChanged(deviceState); + } + return 0; +} + +int QAudioOutputPrivate::periodSize() const +{ + return period_size; +} + +void QAudioOutputPrivate::setBufferSize(int value) +{ + if(deviceState == QAudio::StopState) + buffer_size = value; +} + +int QAudioOutputPrivate::bufferSize() const +{ + return buffer_size; +} + +void QAudioOutputPrivate::setNotifyInterval(int ms) +{ + intervalTime = ms; +} + +int QAudioOutputPrivate::notifyInterval() const +{ + return intervalTime; +} + +qint64 QAudioOutputPrivate::totalTime() const +{ + return totalTimeValue; +} + +void QAudioOutputPrivate::resume() +{ + if(deviceState == QAudio::SuspendState) { + int err = 0; + + if(handle) { + err = snd_pcm_prepare( handle ); + if(err < 0) + xrun_recovery(err); + + err = snd_pcm_start(handle); + if(err < 0) + xrun_recovery(err); + + bytesAvailable = (int)snd_pcm_frames_to_bytes(handle, buffer_frames); + } + resuming = true; + if(pullMode) + deviceState = QAudio::ActiveState; + else + deviceState = QAudio::IdleState; + + errorState = QAudio::NoError; + timer->start(period_time/1000); + emit stateChanged(deviceState); + } +} + +QAudioFormat QAudioOutputPrivate::format() const +{ + return settings; +} + +void QAudioOutputPrivate::suspend() +{ + if(deviceState == QAudio::ActiveState || deviceState == QAudio::IdleState || resuming) { + timer->stop(); + deviceState = QAudio::SuspendState; + errorState = QAudio::NoError; + emit stateChanged(deviceState); + } +} + +void QAudioOutputPrivate::userFeed() +{ + if(deviceState == QAudio::StopState || deviceState == QAudio::SuspendState) + return; +#ifdef DEBUG_AUDIO + QTime now(QTime::currentTime()); + qDebug()<acquireReadRegion((maxFrames - framesRead) * m_bytesPerFrame); + + if (region.second > 0) { + region.second -= region.second % m_bytesPerFrame; + memcpy(data + (framesRead * m_bytesPerFrame), region.first, region.second); + framesRead += region.second / m_bytesPerFrame; + } + else + wecan = false; + + m_buffer->releaseReadRegion(region); + } + + if (framesRead == 0 && m_deviceError) + framesRead = -1; + + return framesRead; + } + + qint64 writeBytes(const char* data, qint64 maxSize) + { + bool wecan = true; + qint64 bytesWritten = 0; + + maxSize -= maxSize % m_bytesPerFrame; + while (wecan && bytesWritten < maxSize) { + QAudioRingBuffer::Region region = m_buffer->acquireWriteRegion(maxSize - bytesWritten); + + if (region.second > 0) { + memcpy(region.first, data + bytesWritten, region.second); + bytesWritten += region.second; + } + else + wecan = false; + + m_buffer->releaseWriteRegion(region); + } + + if (bytesWritten > 0) + emit readyRead(); + + return bytesWritten; + } + + int available() const + { + return m_buffer->free(); + } + + void reset() + { + m_buffer->reset(); + m_deviceError = false; + } + + void setPrefetchDevice(QIODevice* device) + { + if (m_device != device) { + m_device = device; + if (m_device != 0) + fillBuffer(); + } + } + + void startFillTimer() + { + if (m_device != 0) + m_fillTimer->start(m_buffer->size() / 2 / m_maxPeriodSize * m_periodTime); + } + + void stopFillTimer() + { + m_fillTimer->stop(); + } + +signals: + void readyRead(); + +private slots: + void fillBuffer() + { + const int free = m_buffer->free(); + const int writeSize = free - (free % m_maxPeriodSize); + + if (writeSize > 0) { + bool wecan = true; + int filled = 0; + + while (!m_deviceError && wecan && filled < writeSize) { + QAudioRingBuffer::Region region = m_buffer->acquireWriteRegion(writeSize - filled); + + if (region.second > 0) { + region.second = m_device->read(region.first, region.second); + if (region.second > 0) + filled += region.second; + else if (region.second == 0) + wecan = false; + else if (region.second < 0) { + m_fillTimer->stop(); + region.second = 0; + m_deviceError = true; + } + } + else + wecan = false; + + m_buffer->releaseWriteRegion(region); + } + + if (filled > 0) + emit readyRead(); + } + } + +private: + bool m_deviceError; + int m_maxPeriodSize; + int m_bytesPerFrame; + int m_periodTime; + QIODevice* m_device; + QTimer* m_fillTimer; + QAudioRingBuffer* m_buffer; +}; + + +} + +class MacOutputDevice : public QIODevice +{ + Q_OBJECT + +public: + MacOutputDevice(QAudioOutputBuffer* audioBuffer, QObject* parent): + QIODevice(parent), + m_audioBuffer(audioBuffer) + { + open(QIODevice::WriteOnly | QIODevice::Unbuffered); + } + + qint64 readData(char* data, qint64 len) + { + Q_UNUSED(data); + Q_UNUSED(len); + + return 0; + } + + qint64 writeData(const char* data, qint64 len) + { + return m_audioBuffer->writeBytes(data, len); + } + + bool isSequential() const + { + return true; + } + +private: + QAudioOutputBuffer* m_audioBuffer; +}; + + +QAudioOutputPrivate::QAudioOutputPrivate(const QByteArray& device, const QAudioFormat& format): + audioFormat(format) +{ + QDataStream ds(device); + quint32 did, mode; + + ds >> did >> mode; + + if (QAudio::Mode(mode) == QAudio::AudioInput) + errorCode = QAudio::OpenError; + else { + isOpen = false; + audioDeviceId = AudioDeviceID(did); + audioUnit = 0; + audioIO = 0; + startTime = 0; + totalFrames = 0; + audioBuffer = 0; + internalBufferSize = default_buffer_size; + clockFrequency = AudioGetHostClockFrequency() / 1000; + errorCode = QAudio::NoError; + stateCode = QAudio::StopState; + audioThreadState = Stopped; + + intervalTimer = new QTimer(this); + intervalTimer->setInterval(1000); + connect(intervalTimer, SIGNAL(timeout()), SIGNAL(notify())); + } +} + +QAudioOutputPrivate::~QAudioOutputPrivate() +{ + close(); +} + +bool QAudioOutputPrivate::open() +{ + if (errorCode != QAudio::NoError) + return false; + + if (isOpen) + return true; + + ComponentDescription cd; + cd.componentType = kAudioUnitType_Output; + cd.componentSubType = kAudioUnitSubType_HALOutput; + cd.componentManufacturer = kAudioUnitManufacturer_Apple; + cd.componentFlags = 0; + cd.componentFlagsMask = 0; + + // Open + Component cp = FindNextComponent(NULL, &cd); + if (cp == 0) { + qWarning() << "QAudioOutput: Failed to find HAL Output component"; + return false; + } + + if (OpenAComponent(cp, &audioUnit) != noErr) { + qWarning() << "QAudioOutput: Unable to Open Output Component"; + return false; + } + + // register callback + AURenderCallbackStruct cb; + cb.inputProc = renderCallback; + cb.inputProcRefCon = this; + + if (AudioUnitSetProperty(audioUnit, + kAudioUnitProperty_SetRenderCallback, + kAudioUnitScope_Global, + 0, + &cb, + sizeof(cb)) != noErr) { + qWarning() << "QAudioOutput: Failed to set AudioUnit callback"; + return false; + } + + // Set Audio Device + if (AudioUnitSetProperty(audioUnit, + kAudioOutputUnitProperty_CurrentDevice, + kAudioUnitScope_Global, + 0, + &audioDeviceId, + sizeof(audioDeviceId)) != noErr) { + qWarning() << "QAudioOutput: Unable to use configured device"; + return false; + } + + // Set stream format + streamFormat = toAudioStreamBasicDescription(audioFormat); + + UInt32 size = sizeof(deviceFormat); + if (AudioUnitGetProperty(audioUnit, + kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Input, + 0, + &deviceFormat, + &size) != noErr) { + qWarning() << "QAudioOutput: Unable to retrieve device format"; + return false; + } + + if (AudioUnitSetProperty(audioUnit, + kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Input, + 0, + &streamFormat, + sizeof(streamFormat)) != noErr) { + qWarning() << "QAudioOutput: Unable to Set Stream information"; + return false; + } + + // Allocate buffer + UInt32 numberOfFrames = 0; + size = sizeof(UInt32); + if (AudioUnitGetProperty(audioUnit, + kAudioDevicePropertyBufferFrameSize, + kAudioUnitScope_Global, + 0, + &numberOfFrames, + &size) != noErr) { + qWarning() << "QAudioInput: Failed to get audio period size"; + return false; + } + + periodSizeBytes = (numberOfFrames * streamFormat.mSampleRate / deviceFormat.mSampleRate) * + streamFormat.mBytesPerFrame; + if (internalBufferSize < periodSizeBytes * 2) + internalBufferSize = periodSizeBytes * 2; + else + internalBufferSize -= internalBufferSize % streamFormat.mBytesPerFrame; + + audioBuffer = new QAudioOutputBuffer(internalBufferSize, periodSizeBytes, audioFormat); + connect(audioBuffer, SIGNAL(readyRead()), SLOT(inputReady())); // Pull + + audioIO = new MacOutputDevice(audioBuffer, this); + + // Init + if (AudioUnitInitialize(audioUnit)) { + qWarning() << "QAudioOutput: Failed to initialize AudioUnit"; + return false; + } + + isOpen = true; + + return true; +} + +void QAudioOutputPrivate::close() +{ + if (audioUnit != 0) { + AudioOutputUnitStop(audioUnit); + AudioUnitUninitialize(audioUnit); + CloseComponent(audioUnit); + } + + delete audioBuffer; +} + +QAudioFormat QAudioOutputPrivate::format() const +{ + return audioFormat; +} + +QIODevice* QAudioOutputPrivate::start(QIODevice* device) +{ + QIODevice* op = device; + + if (!open()) { + stateCode = QAudio::StopState; + errorCode = QAudio::OpenError; + return audioIO; + } + + reset(); + audioBuffer->reset(); + audioBuffer->setPrefetchDevice(op); + + if (op == 0) { + op = audioIO; + stateCode = QAudio::IdleState; + } + else + stateCode = QAudio::ActiveState; + + // Start + errorCode = QAudio::NoError; + totalFrames = 0; + startTime = AudioGetCurrentHostTime(); + + if (stateCode == QAudio::ActiveState) + audioThreadStart(); + + return op; +} + +void QAudioOutputPrivate::stop() +{ + QMutexLocker lock(&mutex); + if (stateCode != QAudio::StopState) { + audioThreadDrain(); + + stateCode = QAudio::StopState; + errorCode = QAudio::NoError; + QMetaObject::invokeMethod(this, "stateChanged", Qt::QueuedConnection, Q_ARG(QAudio::State, stateCode)); + } +} + +void QAudioOutputPrivate::reset() +{ + QMutexLocker lock(&mutex); + if (stateCode != QAudio::StopState) { + audioThreadStop(); + + stateCode = QAudio::StopState; + errorCode = QAudio::NoError; + QMetaObject::invokeMethod(this, "stateChanged", Qt::QueuedConnection, Q_ARG(QAudio::State, stateCode)); + } +} + +void QAudioOutputPrivate::suspend() +{ + QMutexLocker lock(&mutex); + if (stateCode == QAudio::ActiveState || stateCode == QAudio::IdleState) { + audioThreadStop(); + + stateCode = QAudio::SuspendState; + errorCode = QAudio::NoError; + QMetaObject::invokeMethod(this, "stateChanged", Qt::QueuedConnection, Q_ARG(QAudio::State, stateCode)); + } +} + +void QAudioOutputPrivate::resume() +{ + QMutexLocker lock(&mutex); + if (stateCode == QAudio::SuspendState) { + audioThreadStart(); + + stateCode = QAudio::ActiveState; + errorCode = QAudio::NoError; + QMetaObject::invokeMethod(this, "stateChanged", Qt::QueuedConnection, Q_ARG(QAudio::State, stateCode)); + } +} + +int QAudioOutputPrivate::bytesFree() const +{ + return audioBuffer->available(); +} + +int QAudioOutputPrivate::periodSize() const +{ + return periodSizeBytes; +} + +void QAudioOutputPrivate::setBufferSize(int bs) +{ + if (stateCode == QAudio::StopState) + internalBufferSize = bs; +} + +int QAudioOutputPrivate::bufferSize() const +{ + return internalBufferSize; +} + +void QAudioOutputPrivate::setNotifyInterval(int milliSeconds) +{ + intervalTimer->setInterval(milliSeconds); +} + +int QAudioOutputPrivate::notifyInterval() const +{ + return intervalTimer->interval(); +} + +qint64 QAudioOutputPrivate::totalTime() const +{ + return totalFrames * 1000000 / audioFormat.frequency(); +} + +qint64 QAudioOutputPrivate::clock() const +{ + return (AudioGetCurrentHostTime() - startTime) / (clockFrequency / 1000); +} + +QAudio::Error QAudioOutputPrivate::error() const +{ + return errorCode; +} + +QAudio::State QAudioOutputPrivate::state() const +{ + return stateCode; +} + +void QAudioOutputPrivate::audioThreadStart() +{ + startTimers(); + audioThreadState = Running; + AudioOutputUnitStart(audioUnit); +} + +void QAudioOutputPrivate::audioThreadStop() +{ + stopTimers(); + if (audioThreadState.testAndSetAcquire(Running, Stopped)) + threadFinished.wait(&mutex); +} + +void QAudioOutputPrivate::audioThreadDrain() +{ + stopTimers(); + if (audioThreadState.testAndSetAcquire(Running, Draining)) + threadFinished.wait(&mutex); +} + +void QAudioOutputPrivate::audioDeviceStop() +{ + AudioOutputUnitStop(audioUnit); + audioThreadState = Stopped; + threadFinished.wakeOne(); +} + +void QAudioOutputPrivate::audioDeviceIdle() +{ + QMutexLocker lock(&mutex); + if (stateCode == QAudio::ActiveState) { + audioDeviceStop(); + + errorCode = QAudio::UnderrunError; + stateCode = QAudio::IdleState; + QMetaObject::invokeMethod(this, "deviceStopped", Qt::QueuedConnection); + } +} + +void QAudioOutputPrivate::audioDeviceError() +{ + QMutexLocker lock(&mutex); + if (stateCode == QAudio::ActiveState) { + audioDeviceStop(); + + errorCode = QAudio::IOError; + stateCode = QAudio::StopState; + QMetaObject::invokeMethod(this, "deviceStopped", Qt::QueuedConnection); + } +} + +void QAudioOutputPrivate::startTimers() +{ + audioBuffer->startFillTimer(); + intervalTimer->start(); +} + +void QAudioOutputPrivate::stopTimers() +{ + audioBuffer->stopFillTimer(); + intervalTimer->stop(); +} + + +void QAudioOutputPrivate::deviceStopped() +{ + intervalTimer->stop(); + emit stateChanged(stateCode); +} + +void QAudioOutputPrivate::inputReady() +{ + QMutexLocker lock(&mutex); + if (stateCode == QAudio::IdleState) { + audioThreadStart(); + + stateCode = QAudio::ActiveState; + errorCode = QAudio::NoError; + + QMetaObject::invokeMethod(this, "stateChanged", Qt::QueuedConnection, Q_ARG(QAudio::State, stateCode)); + } +} + + +OSStatus QAudioOutputPrivate::renderCallback(void* inRefCon, + AudioUnitRenderActionFlags* ioActionFlags, + const AudioTimeStamp* inTimeStamp, + UInt32 inBusNumber, + UInt32 inNumberFrames, + AudioBufferList* ioData) +{ + Q_UNUSED(ioActionFlags) + Q_UNUSED(inTimeStamp) + Q_UNUSED(inBusNumber) + Q_UNUSED(inNumberFrames) + + QAudioOutputPrivate* d = static_cast(inRefCon); + + const int threadState = d->audioThreadState.fetchAndAddAcquire(0); + if (threadState == Stopped) { + ioData->mBuffers[0].mDataByteSize = 0; + d->audioDeviceStop(); + } + else { + const UInt32 bytesPerFrame = d->streamFormat.mBytesPerFrame; + qint64 framesRead; + + framesRead = d->audioBuffer->readFrames((char*)ioData->mBuffers[0].mData, + ioData->mBuffers[0].mDataByteSize / bytesPerFrame); + + if (framesRead > 0) { + ioData->mBuffers[0].mDataByteSize = framesRead * bytesPerFrame; + d->totalFrames += framesRead; + } + else { + ioData->mBuffers[0].mDataByteSize = 0; + if (framesRead == 0) { + if (threadState == Draining) + d->audioDeviceStop(); + else + d->audioDeviceIdle(); + } + else + d->audioDeviceError(); + } + } + + return noErr; +} + + +QT_END_NAMESPACE + +#include "qaudiooutput_mac_p.moc" + diff --git a/src/multimedia/audio/qaudiooutput_mac_p.h b/src/multimedia/audio/qaudiooutput_mac_p.h new file mode 100644 index 000000000..c85cab454 --- /dev/null +++ b/src/multimedia/audio/qaudiooutput_mac_p.h @@ -0,0 +1,171 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QAUDIOOUTPUT_MAC_P_H +#define QAUDIOOUTPUT_MAC_P_H + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QIODevice; + +namespace +{ +class QAudioOutputBuffer; +} + +class QAudioOutputPrivate : public QAbstractAudioOutput +{ + Q_OBJECT + +public: + bool isOpen; + int internalBufferSize; + int periodSizeBytes; + qint64 totalFrames; + QAudioFormat audioFormat; + QIODevice* audioIO; + AudioDeviceID audioDeviceId; + AudioUnit audioUnit; + Float64 clockFrequency; + UInt64 startTime; + AudioStreamBasicDescription deviceFormat; + AudioStreamBasicDescription streamFormat; + QAudioOutputBuffer* audioBuffer; + QAtomicInt audioThreadState; + QWaitCondition threadFinished; + QMutex mutex; + QTimer* intervalTimer; + + QAudio::Error errorCode; + QAudio::State stateCode; + + QAudioOutputPrivate(const QByteArray& device, const QAudioFormat& format); + ~QAudioOutputPrivate(); + + bool open(); + void close(); + + QAudioFormat format() const; + + QIODevice* start(QIODevice* device); + void stop(); + void reset(); + void suspend(); + void resume(); + + int bytesFree() const; + int periodSize() const; + + void setBufferSize(int value); + int bufferSize() const; + + void setNotifyInterval(int milliSeconds); + int notifyInterval() const; + + qint64 totalTime() const; + qint64 clock() const; + + QAudio::Error error() const; + QAudio::State state() const; + + void audioThreadStart(); + void audioThreadStop(); + void audioThreadDrain(); + + void audioDeviceStop(); + void audioDeviceIdle(); + void audioDeviceError(); + + void startTimers(); + void stopTimers(); + +signals: + void stateChanged(QAudio::State); + void notify(); + +private slots: + void deviceStopped(); + void inputReady(); + +private: + enum { Running, Draining, Stopped }; + + static OSStatus renderCallback(void* inRefCon, + AudioUnitRenderActionFlags* ioActionFlags, + const AudioTimeStamp* inTimeStamp, + UInt32 inBusNumber, + UInt32 inNumberFrames, + AudioBufferList* ioData); +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/multimedia/audio/qaudiooutput_win32_p.cpp b/src/multimedia/audio/qaudiooutput_win32_p.cpp new file mode 100644 index 000000000..f681936bf --- /dev/null +++ b/src/multimedia/audio/qaudiooutput_win32_p.cpp @@ -0,0 +1,502 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qaudiooutput_win32_p.h" + +//#define DEBUG_AUDIO 1 + +QAudioOutputPrivate::QAudioOutputPrivate(const QByteArray &device, const QAudioFormat& audioFormat): + settings(audioFormat) +{ + bytesAvailable = 0; + buffer_size = 0; + period_size = 0; + m_device = device; + totalTimeValue = 0; + intervalTime = 1000; + audioBuffer = 0; + errorState = QAudio::NoError; + deviceState = QAudio::StopState; + audioSource = 0; + pullMode = true; + InitializeCriticalSection(&waveOutCriticalSection); +} + +QAudioOutputPrivate::~QAudioOutputPrivate() +{ + close(); + DeleteCriticalSection(&waveOutCriticalSection); +} + +void CALLBACK QAudioOutputPrivate::waveOutProc( HWAVEOUT hWaveOut, UINT uMsg, + DWORD dwInstance, DWORD dwParam1, DWORD dwParam2 ) +{ + Q_UNUSED(dwParam1) + Q_UNUSED(dwParam2) + Q_UNUSED(hWaveOut) + + QAudioOutputPrivate* qAudio; + qAudio = (QAudioOutputPrivate*)(dwInstance); + if(!qAudio) + return; + + switch(uMsg) { + case WOM_OPEN: + qAudio->feedback(); + break; + case WOM_CLOSE: + return; + case WOM_DONE: + EnterCriticalSection(&waveOutCriticalSection); + qAudio->waveFreeBlockCount++; + if(qAudio->waveFreeBlockCount >= qAudio->buffer_size/qAudio->period_size) + qAudio->waveFreeBlockCount = qAudio->buffer_size/qAudio->period_size; + LeaveCriticalSection(&waveOutCriticalSection); + qAudio->feedback(); + break; + default: + return; + } +} + +WAVEHDR* QAudioOutputPrivate::allocateBlocks(int size, int count) +{ + int i; + unsigned char* buffer; + WAVEHDR* blocks; + DWORD totalBufferSize = (size + sizeof(WAVEHDR))*count; + + if((buffer=(unsigned char*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, + totalBufferSize)) == 0) { + qWarning("QAudioOutput: Memory allocation error"); + return 0; + } + blocks = (WAVEHDR*)buffer; + buffer += sizeof(WAVEHDR)*count; + for(i = 0; i < count; i++) { + blocks[i].dwBufferLength = size; + blocks[i].lpData = (LPSTR)buffer; + buffer += size; + } + return blocks; +} + +void QAudioOutputPrivate::freeBlocks(WAVEHDR* blockArray) +{ + HeapFree(GetProcessHeap(), 0, blockArray); +} + +QAudioFormat QAudioOutputPrivate::format() const +{ + return settings; +} + +QIODevice* QAudioOutputPrivate::start(QIODevice* device) +{ + if(deviceState != QAudio::StopState) + close(); + + if(!pullMode && audioSource) { + delete audioSource; + } + + if(device) { + //set to pull mode + pullMode = true; + audioSource = device; + deviceState = QAudio::ActiveState; + } else { + //set to push mode + pullMode = false; + audioSource = new OutputPrivate(this); + audioSource->open(QIODevice::WriteOnly|QIODevice::Unbuffered); + deviceState = QAudio::IdleState; + } + + if( !open() ) + return 0; + + emit stateChanged(deviceState); + + return audioSource; +} + +void QAudioOutputPrivate::stop() +{ + if(deviceState == QAudio::StopState) + return; + deviceState = QAudio::StopState; + close(); + if(!pullMode && audioSource) { + delete audioSource; + audioSource = 0; + } + emit stateChanged(deviceState); +} + +bool QAudioOutputPrivate::open() +{ +#ifdef DEBUG_AUDIO + QTime now(QTime::currentTime()); + qDebug()<> 3) * wfx.nChannels; + wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec; + + UINT_PTR devId = WAVE_MAPPER; + + WAVEOUTCAPS woc; + unsigned long iNumDevs,ii; + iNumDevs = waveOutGetNumDevs(); + for(ii=0;ii 0) { + if(waveFreeBlockCount==0) + break; + + if(current->dwFlags & WHDR_PREPARED) + waveOutUnprepareHeader(hWaveOut, current, sizeof(WAVEHDR)); + + if(l < period_size) + remain = l; + else + remain = period_size; + memcpy(current->lpData, p, remain); + + l -= remain; + p += remain; + current->dwBufferLength = remain; + waveOutPrepareHeader(hWaveOut, current, sizeof(WAVEHDR)); + waveOutWrite(hWaveOut, current, sizeof(WAVEHDR)); + + EnterCriticalSection(&waveOutCriticalSection); + waveFreeBlockCount--; + LeaveCriticalSection(&waveOutCriticalSection); +#ifdef DEBUG_AUDIO + qDebug("write out l=%d, waveFreeBlockCount=%d", + current->dwBufferLength,waveFreeBlockCount); +#endif + totalTimeValue += current->dwBufferLength + /(settings.channels()*(settings.sampleSize()/8)) + *1000000/settings.frequency();; + waveCurrentBlock++; + waveCurrentBlock %= buffer_size/period_size; + current = &waveBlocks[waveCurrentBlock]; + current->dwUser = 0; + } + return (len-l); +} + +void QAudioOutputPrivate::resume() +{ + if(deviceState == QAudio::SuspendState) { + deviceState = QAudio::ActiveState; + errorState = QAudio::NoError; + waveOutRestart(hWaveOut); + QTimer::singleShot(10, this, SLOT(feedback())); + emit stateChanged(deviceState); + } +} + +void QAudioOutputPrivate::suspend() +{ + if(deviceState == QAudio::ActiveState) { + waveOutPause(hWaveOut); + deviceState = QAudio::SuspendState; + errorState = QAudio::NoError; + emit stateChanged(deviceState); + } +} + +void QAudioOutputPrivate::feedback() +{ +#ifdef DEBUG_AUDIO + QTime now(QTime::currentTime()); + qDebug()<= period_size) + QMetaObject::invokeMethod(this, "deviceReady", Qt::QueuedConnection); + } +} + +bool QAudioOutputPrivate::deviceReady() +{ + if(pullMode) { + int i = 0; + int chunks = bytesAvailable/period_size; +#ifdef DEBUG_AUDIO + qDebug()<<"deviceReady() avail="< +#include +#include +#include + +#include +#include + + +class tst_QAudioDeviceId : public QObject +{ + Q_OBJECT + +public: + tst_QAudioDeviceId(QObject* parent=0) : QObject(parent) {} + +private slots: + void checkNull(); + void checkEquality(); +}; + +void tst_QAudioDeviceId::checkNull() +{ + // Default constructed is null. + QAudioDeviceId deviceId0; + QVERIFY(deviceId0.isNull()); + + // Null is transferred + QAudioDeviceId deviceId1(deviceId0); + QVERIFY(deviceId1.isNull()); +} + +void tst_QAudioDeviceId::checkEquality() +{ + QAudioDeviceId deviceId0; + QAudioDeviceId deviceId1; + + // Null ids are equivalent + QVERIFY(deviceId0 == deviceId1); + QVERIFY(!(deviceId0 != deviceId1)); + + deviceId1 = QAudioDeviceInfo::defaultOutputDevice(); + + // Different + QVERIFY(deviceId0 != deviceId1); + QVERIFY(!(deviceId0 == deviceId1)); + + // Same + deviceId0 = deviceId1; + + QVERIFY(deviceId0 == deviceId1); + QVERIFY(!(deviceId0 != deviceId1)); +} + +QTEST_MAIN(tst_QAudioDeviceId) + +#include "tst_qaudiodeviceid.moc" diff --git a/tests/auto/qaudiodeviceinfo/qaudiodeviceinfo.pro b/tests/auto/qaudiodeviceinfo/qaudiodeviceinfo.pro new file mode 100644 index 000000000..695987c9e --- /dev/null +++ b/tests/auto/qaudiodeviceinfo/qaudiodeviceinfo.pro @@ -0,0 +1,7 @@ +load(qttest_p4) + +DEFINES += SRCDIR=\\\"$$PWD/\\\" + +SOURCES += tst_qaudiodeviceinfo.cpp + +QT = core multimedia diff --git a/tests/auto/qaudiodeviceinfo/tst_qaudiodeviceinfo.cpp b/tests/auto/qaudiodeviceinfo/tst_qaudiodeviceinfo.cpp new file mode 100644 index 000000000..c2cd97e34 --- /dev/null +++ b/tests/auto/qaudiodeviceinfo/tst_qaudiodeviceinfo.cpp @@ -0,0 +1,159 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include +#include +#include + +#include +#include + + +class tst_QAudioDeviceInfo : public QObject +{ + Q_OBJECT +public: + tst_QAudioDeviceInfo(QObject* parent=0) : QObject(parent) {} + +private slots: + void checkAvailableDefaultInput(); + void checkAvailableDefaultOutput(); + void outputList(); + void codecs(); + void channels(); + void sampleSizes(); + void byteOrders(); + void sampleTypes(); + void frequencies(); + void isformat(); + void preferred(); + void nearest(); + +private: + QAudioDeviceInfo* device; +}; + +void tst_QAudioDeviceInfo::checkAvailableDefaultInput() +{ + QVERIFY(!QAudioDeviceInfo::defaultInputDevice().isNull()); +} + +void tst_QAudioDeviceInfo::checkAvailableDefaultOutput() +{ + QVERIFY(!QAudioDeviceInfo::defaultOutputDevice().isNull()); +} + +void tst_QAudioDeviceInfo::outputList() +{ + QList devices = QAudioDeviceInfo::deviceList(QAudio::AudioOutput); + QVERIFY(devices.size() > 0); + device = new QAudioDeviceInfo(devices.at(0), this); +} + +void tst_QAudioDeviceInfo::codecs() +{ + QStringList avail = device->supportedCodecs(); + QVERIFY(avail.size() > 0); +} + +void tst_QAudioDeviceInfo::channels() +{ + QList avail = device->supportedChannels(); + QVERIFY(avail.size() > 0); +} + +void tst_QAudioDeviceInfo::sampleSizes() +{ + QList avail = device->supportedSampleSizes(); + QVERIFY(avail.size() > 0); +} + +void tst_QAudioDeviceInfo::byteOrders() +{ + QList avail = device->supportedByteOrders(); + QVERIFY(avail.size() > 0); +} + +void tst_QAudioDeviceInfo::sampleTypes() +{ + QList avail = device->supportedSampleTypes(); + QVERIFY(avail.size() > 0); +} + +void tst_QAudioDeviceInfo::frequencies() +{ + QList avail = device->supportedFrequencies(); + QVERIFY(avail.size() > 0); +} + +void tst_QAudioDeviceInfo::isformat() +{ + QAudioFormat format; + format.setFrequency(44100); + format.setChannels(2); + format.setSampleType(QAudioFormat::SignedInt); + format.setByteOrder(QAudioFormat::LittleEndian); + format.setSampleSize(16); + format.setCodec("audio/pcm"); + + // Should always be true for these format + QVERIFY(device->isFormatSupported(format)); +} + +void tst_QAudioDeviceInfo::preferred() +{ + QAudioFormat format = device->preferredFormat(); + QVERIFY(format.frequency() == 44100); + QVERIFY(format.channels() == 2); +} + +void tst_QAudioDeviceInfo::nearest() +{ + QAudioFormat format1, format2; + format1.setFrequency(8000); + format2 = device->nearestFormat(format1); + QVERIFY(format2.frequency() == 44100); +} + +QTEST_MAIN(tst_QAudioDeviceInfo) + +#include "tst_qaudiodeviceinfo.moc" diff --git a/tests/auto/qaudioformat/qaudioformat.pro b/tests/auto/qaudioformat/qaudioformat.pro new file mode 100644 index 000000000..78962d706 --- /dev/null +++ b/tests/auto/qaudioformat/qaudioformat.pro @@ -0,0 +1,7 @@ +load(qttest_p4) + +DEFINES += SRCDIR=\\\"$$PWD/\\\" + +SOURCES += tst_qaudioformat.cpp + +QT = core multimedia diff --git a/tests/auto/qaudioformat/tst_qaudioformat.cpp b/tests/auto/qaudioformat/tst_qaudioformat.cpp new file mode 100644 index 000000000..bcfc78f38 --- /dev/null +++ b/tests/auto/qaudioformat/tst_qaudioformat.cpp @@ -0,0 +1,180 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include +#include +#include + +#include +#include + + +class tst_QAudioFormat : public QObject +{ + Q_OBJECT + +public: + tst_QAudioFormat(QObject* parent=0) : QObject(parent) {} + +private slots: + void checkNull(); + void checkFrequency(); + void checkChannels(); + void checkSampleSize(); + void checkCodec(); + void checkByteOrder(); + void checkSampleType(); + void checkEquality(); + void checkAssignment(); +}; + +void tst_QAudioFormat::checkNull() +{ + // Default constructed QAudioFormat is null. + QAudioFormat audioFormat0; + QVERIFY(audioFormat0.isNull()); + + // Null is transferred + QAudioFormat audioFormat1(audioFormat0); + QVERIFY(audioFormat1.isNull()); + + // Null is voided on activity + audioFormat0.setFrequency(44100); + QVERIFY(!audioFormat0.isNull()); +} + +void tst_QAudioFormat::checkFrequency() +{ + QAudioFormat audioFormat; + audioFormat.setFrequency(44100); + QVERIFY(audioFormat.frequency() == 44100); +} + +void tst_QAudioFormat::checkChannels() +{ + QAudioFormat audioFormat; + audioFormat.setChannels(2); + QVERIFY(audioFormat.channels() == 2); +} + +void tst_QAudioFormat::checkSampleSize() +{ + QAudioFormat audioFormat; + audioFormat.setSampleSize(16); + QVERIFY(audioFormat.sampleSize() == 16); +} + +void tst_QAudioFormat::checkCodec() +{ + QAudioFormat audioFormat; + audioFormat.setCodec(QString::fromLatin1("audio/pcm")); + QVERIFY(audioFormat.codec() == QString::fromLatin1("audio/pcm")); +} + +void tst_QAudioFormat::checkByteOrder() +{ + QAudioFormat audioFormat; + audioFormat.setByteOrder(QAudioFormat::LittleEndian); + QVERIFY(audioFormat.byteOrder() == QAudioFormat::LittleEndian); +} + +void tst_QAudioFormat::checkSampleType() +{ + QAudioFormat audioFormat; + audioFormat.setSampleType(QAudioFormat::SignedInt); + QVERIFY(audioFormat.sampleType() == QAudioFormat::SignedInt); +} + +void tst_QAudioFormat::checkEquality() +{ + QAudioFormat audioFormat0; + QAudioFormat audioFormat1; + + // Null formats are equivalent + QVERIFY(audioFormat0 == audioFormat1); + QVERIFY(!(audioFormat0 != audioFormat1)); + + // on filled formats + audioFormat0.setFrequency(8000); + audioFormat0.setChannels(1); + audioFormat0.setSampleSize(8); + audioFormat0.setCodec("audio/pcm"); + audioFormat0.setByteOrder(QAudioFormat::LittleEndian); + audioFormat0.setSampleType(QAudioFormat::UnSignedInt); + + audioFormat1.setFrequency(8000); + audioFormat1.setChannels(1); + audioFormat1.setSampleSize(8); + audioFormat1.setCodec("audio/pcm"); + audioFormat1.setByteOrder(QAudioFormat::LittleEndian); + audioFormat1.setSampleType(QAudioFormat::UnSignedInt); + + QVERIFY(audioFormat0 == audioFormat1); + QVERIFY(!(audioFormat0 != audioFormat1)); + + audioFormat0.setFrequency(44100); + QVERIFY(audioFormat0 != audioFormat1); + QVERIFY(!(audioFormat0 == audioFormat1)); +} + +void tst_QAudioFormat::checkAssignment() +{ + QAudioFormat audioFormat0; + QAudioFormat audioFormat1; + + audioFormat0.setFrequency(8000); + audioFormat0.setChannels(1); + audioFormat0.setSampleSize(8); + audioFormat0.setCodec("audio/pcm"); + audioFormat0.setByteOrder(QAudioFormat::LittleEndian); + audioFormat0.setSampleType(QAudioFormat::UnSignedInt); + + audioFormat1 = audioFormat0; + QVERIFY(audioFormat1 == audioFormat0); + + QAudioFormat audioFormat2(audioFormat0); + QVERIFY(audioFormat2 == audioFormat0); +} + +QTEST_MAIN(tst_QAudioFormat) + +#include "tst_qaudioformat.moc" diff --git a/tests/auto/qaudioinput/qaudioinput.pro b/tests/auto/qaudioinput/qaudioinput.pro new file mode 100644 index 000000000..8a0374988 --- /dev/null +++ b/tests/auto/qaudioinput/qaudioinput.pro @@ -0,0 +1,7 @@ +load(qttest_p4) + +DEFINES += SRCDIR=\\\"$$PWD/\\\" + +SOURCES += tst_qaudioinput.cpp + +QT = core multimedia diff --git a/tests/auto/qaudioinput/tst_qaudioinput.cpp b/tests/auto/qaudioinput/tst_qaudioinput.cpp new file mode 100644 index 000000000..6e16320d0 --- /dev/null +++ b/tests/auto/qaudioinput/tst_qaudioinput.cpp @@ -0,0 +1,120 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include +#include + + +class tst_QAudioInput : public QObject +{ + Q_OBJECT +public: + tst_QAudioInput(QObject* parent=0) : QObject(parent) {} + +private slots: + void initTestCase(); + void settings(); + void notifyInterval(); + void pullFile(); + +private: + QAudioFormat format; + QAudioInput* audio; +}; + +void tst_QAudioInput::initTestCase() +{ + format.setFrequency(8000); + format.setChannels(1); + format.setSampleSize(8); + format.setCodec("audio/pcm"); + format.setByteOrder(QAudioFormat::LittleEndian); + format.setSampleType(QAudioFormat::UnSignedInt); + + audio = new QAudioInput(format, this); +} + +void tst_QAudioInput::settings() +{ + QAudioFormat f = audio->format(); + + QVERIFY(format.channels() == f.channels()); + QVERIFY(format.frequency() == f.frequency()); + QVERIFY(format.sampleSize() == f.sampleSize()); + QVERIFY(format.codec() == f.codec()); + QVERIFY(format.byteOrder() == f.byteOrder()); + QVERIFY(format.sampleType() == f.sampleType()); +} + +void tst_QAudioInput::notifyInterval() +{ + QVERIFY(audio->notifyInterval() == 1000); // Default + + audio->setNotifyInterval(500); + QVERIFY(audio->notifyInterval() == 500); // Custom + + audio->setNotifyInterval(1000); // reset +} + +void tst_QAudioInput::pullFile() +{ + QFile filename(SRCDIR "test.raw"); + filename.open( QIODevice::WriteOnly | QIODevice::Truncate ); + + QSignalSpy readSignal(audio, SIGNAL(notify())); + audio->start(&filename); + + QTest::qWait(5000); + + QVERIFY(readSignal.count() > 0); + QVERIFY(audio->totalTime() > 0); + + audio->stop(); + filename.close(); +} + +QTEST_MAIN(tst_QAudioInput) + +#include "tst_qaudioinput.moc" diff --git a/tests/auto/qaudiooutput/4.wav b/tests/auto/qaudiooutput/4.wav new file mode 100644 index 000000000..e31b06090 Binary files /dev/null and b/tests/auto/qaudiooutput/4.wav differ diff --git a/tests/auto/qaudiooutput/qaudiooutput.pro b/tests/auto/qaudiooutput/qaudiooutput.pro new file mode 100644 index 000000000..6c07c645e --- /dev/null +++ b/tests/auto/qaudiooutput/qaudiooutput.pro @@ -0,0 +1,12 @@ +load(qttest_p4) + +DEFINES += SRCDIR=\\\"$$PWD/\\\" + +SOURCES += tst_qaudiooutput.cpp + +QT = core multimedia + +wince*: { + deploy.sources += 4.wav + DEPLOYMENT = deploy +} diff --git a/tests/auto/qaudiooutput/tst_qaudiooutput.cpp b/tests/auto/qaudiooutput/tst_qaudiooutput.cpp new file mode 100644 index 000000000..0f94faaf8 --- /dev/null +++ b/tests/auto/qaudiooutput/tst_qaudiooutput.cpp @@ -0,0 +1,156 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + + + +#include +#include +#include +#include +#include +#include + + +class tst_QAudioOutput : public QObject +{ + Q_OBJECT +public: + tst_QAudioOutput(QObject* parent=0) : QObject(parent) {} + +private slots: + void initTestCase(); + void settings(); + void notifyInterval(); + void pullFile(); + void pushFile(); + +private: + QAudioFormat format; + QAudioOutput* audio; +}; + +void tst_QAudioOutput::initTestCase() +{ + format.setFrequency(8000); + format.setChannels(1); + format.setSampleSize(8); + format.setCodec("audio/pcm"); + format.setByteOrder(QAudioFormat::LittleEndian); + format.setSampleType(QAudioFormat::UnSignedInt); + + audio = new QAudioOutput(format, this); +} + +void tst_QAudioOutput::settings() +{ + QAudioFormat f = audio->format(); + + QVERIFY(format.channels() == f.channels()); + QVERIFY(format.frequency() == f.frequency()); + QVERIFY(format.sampleSize() == f.sampleSize()); + QVERIFY(format.codec() == f.codec()); + QVERIFY(format.byteOrder() == f.byteOrder()); + QVERIFY(format.sampleType() == f.sampleType()); +} + +void tst_QAudioOutput::notifyInterval() +{ + QVERIFY(audio->notifyInterval() == 1000); // Default + + audio->setNotifyInterval(500); + QVERIFY(audio->notifyInterval() == 500); // Custom + + audio->setNotifyInterval(1000); // reset +} + +void tst_QAudioOutput::pullFile() +{ + QFile filename(SRCDIR "4.wav"); + QVERIFY(filename.exists()); + filename.open(QIODevice::ReadOnly); + + QSignalSpy readSignal(audio, SIGNAL(notify())); + audio->setNotifyInterval(100); + audio->start(&filename); + + QTestEventLoop::instance().enterLoop(1); + // 4.wav is a little less than 700ms, so notify should fire 6 times! + QVERIFY(readSignal.count() >= 6); + QVERIFY(audio->totalTime() == 692250); + + audio->stop(); + filename.close(); +} + +void tst_QAudioOutput::pushFile() +{ + QFile filename(SRCDIR "4.wav"); + QVERIFY(filename.exists()); + filename.open(QIODevice::ReadOnly); + + const qint64 fileSize = filename.size(); + + QIODevice* feed = audio->start(0); + + char* buffer = new char[fileSize]; + filename.read(buffer, fileSize); + + qint64 counter=0; + qint64 written=0; + while(written < fileSize) { + written+=feed->write(buffer+written,fileSize-written); + QTest::qWait(20); + counter++; + } + QTestEventLoop::instance().enterLoop(1); + + QVERIFY(written == fileSize); + QVERIFY(audio->totalTime() == 692250); + + audio->stop(); + filename.close(); + delete [] buffer; + delete audio; +} + +QTEST_MAIN(tst_QAudioOutput) + +#include "tst_qaudiooutput.moc" diff --git a/tests/auto/tests.xml b/tests/auto/tests.xml index a5386b25a..ccfc3807f 100644 --- a/tests/auto/tests.xml +++ b/tests/auto/tests.xml @@ -271,6 +271,10 @@ + + + + @@ -676,6 +680,10 @@ + + + + diff --git a/tools/configure/configureapp.cpp b/tools/configure/configureapp.cpp index c93891928..f32e7dc09 100644 --- a/tools/configure/configureapp.cpp +++ b/tools/configure/configureapp.cpp @@ -245,6 +245,7 @@ Configure::Configure( int& argc, char** argv ) dictionary[ "XMLPATTERNS" ] = "auto"; dictionary[ "PHONON" ] = "auto"; dictionary[ "PHONON_BACKEND" ] = "yes"; + dictionary[ "MULTIMEDIA" ] = "yes"; dictionary[ "DIRECTSHOW" ] = "no"; dictionary[ "WEBKIT" ] = "auto"; dictionary[ "PLUGIN_MANIFESTS" ] = "yes"; @@ -843,6 +844,10 @@ void Configure::parseCmdLine() dictionary[ "XMLPATTERNS" ] = "no"; } else if( configCmdLine.at(i) == "-xmlpatterns" ) { dictionary[ "XMLPATTERNS" ] = "yes"; + } else if( configCmdLine.at(i) == "-no-multimedia" ) { + dictionary[ "MULTIMEDIA" ] = "no"; + } else if( configCmdLine.at(i) == "-multimedia" ) { + dictionary[ "MULTIMEDIA" ] = "yes"; } else if( configCmdLine.at(i) == "-no-phonon" ) { dictionary[ "PHONON" ] = "no"; } else if( configCmdLine.at(i) == "-phonon" ) { @@ -1425,6 +1430,7 @@ bool Configure::displayHelp() "[-no-openssl] [-no-dbus] [-dbus] [-dbus-linked] [-platform ]\n" "[-qtnamespace ] [-qtlibinfix ] [-no-phonon]\n" "[-phonon] [-no-phonon-backend] [-phonon-backend]\n" + "[-no-multimedia] [-multimedia]\n" "[-no-webkit] [-webkit]\n" "[-no-scripttools] [-scripttools]\n" "[-graphicssystem raster|opengl]\n\n", 0, 7); @@ -1599,6 +1605,8 @@ bool Configure::displayHelp() desc("PHONON", "yes", "-phonon", "Compile the Phonon module (Phonon is built if a decent C++ compiler is used.)"); desc("PHONON_BACKEND","no", "-no-phonon-backend","Do not compile the platform-specific Phonon backend-plugin"); desc("PHONON_BACKEND","yes","-phonon-backend", "Compile in the platform-specific Phonon backend-plugin"); + desc("MULTIMEDIA", "no", "-no-multimedia", "Do not compile the multimedia module"); + desc("MULTIMEDIA", "yes","-multimedia", "Compile in multimedia module"); desc("WEBKIT", "no", "-no-webkit", "Do not compile in the WebKit module"); desc("WEBKIT", "yes", "-webkit", "Compile in the WebKit module (WebKit is built if a decent C++ compiler is used.)"); desc("SCRIPTTOOLS", "no", "-no-scripttools", "Do not build the QtScriptTools module."); @@ -1867,6 +1875,8 @@ bool Configure::checkAvailability(const QString &part) if (!findFile("msdmo.lib")) cout << "msdmo.lib not found" << endl; if (!findFile("d3d9.h")) cout << "d3d9.h not found" << endl; } + } else if (part == "MULTIMEDIA") { + available = true; } else if (part == "WEBKIT") { available = (dictionary.value("QMAKESPEC") == "win32-msvc2005") || (dictionary.value("QMAKESPEC") == "win32-msvc2008") || (dictionary.value("QMAKESPEC") == "win32-g++"); } else if (part == "SCRIPTTOOLS") { @@ -2302,6 +2312,9 @@ void Configure::generateOutputVars() qtConfig += "phonon-backend"; } + if (dictionary["MULTIMEDIA"] == "yes") + qtConfig += "multimedia"; + if (dictionary["WEBKIT"] == "yes") qtConfig += "webkit"; @@ -2662,6 +2675,7 @@ void Configure::generateConfigfiles() if(dictionary["IPV6"] == "no") qconfigList += "QT_NO_IPV6"; if(dictionary["WEBKIT"] == "no") qconfigList += "QT_NO_WEBKIT"; if(dictionary["PHONON"] == "no") qconfigList += "QT_NO_PHONON"; + if(dictionary["MULTIMEDIA"] == "no") qconfigList += "QT_NO_MULTIMEDIA"; if(dictionary["XMLPATTERNS"] == "no") qconfigList += "QT_NO_XMLPATTERNS"; if(dictionary["SCRIPTTOOLS"] == "no") qconfigList += "QT_NO_SCRIPTTOOLS"; @@ -2920,6 +2934,7 @@ void Configure::displayConfig() cout << "QtDBus support.............." << dictionary[ "DBUS" ] << endl; cout << "QtXmlPatterns support......." << dictionary[ "XMLPATTERNS" ] << endl; cout << "Phonon support.............." << dictionary[ "PHONON" ] << endl; + cout << "Multimedia support.........." << dictionary[ "MULTIMEDIA" ] << endl; cout << "WebKit support.............." << dictionary[ "WEBKIT" ] << endl; cout << "QtScriptTools support......." << dictionary[ "SCRIPTTOOLS" ] << endl; cout << "Graphics System............." << dictionary[ "GRAPHICS_SYSTEM" ] << endl; -- cgit v1.2.3 From bedfccd293740b00b7cc9f212c119433a4d82d12 Mon Sep 17 00:00:00 2001 From: Andreas Aardal Hanssen Date: Wed, 5 Aug 2009 07:35:40 +0200 Subject: Compile fix (QGraphicsItem::setXRotation was removed). a6ea9ce6990003856ecadcca8ce9ddf37949363d removed this function; the benchmark was not updated. Reviewed-by: TrustMe --- tests/benchmarks/qgraphicsitem/tst_qgraphicsitem.cpp | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/tests/benchmarks/qgraphicsitem/tst_qgraphicsitem.cpp b/tests/benchmarks/qgraphicsitem/tst_qgraphicsitem.cpp index d072d080d..42f2e6b60 100644 --- a/tests/benchmarks/qgraphicsitem/tst_qgraphicsitem.cpp +++ b/tests/benchmarks/qgraphicsitem/tst_qgraphicsitem.cpp @@ -34,7 +34,6 @@ private slots: void shear(); void translate(); void setRotation(); - void setRotationXYZ(); }; tst_QGraphicsItem::tst_QGraphicsItem() @@ -150,18 +149,7 @@ void tst_QGraphicsItem::setRotation() QGraphicsItem *item = scene.addRect(QRectF(0, 0, 100, 100)); QBENCHMARK { - item->setXRotation(45); - item->transform(); // prevent lazy optimizing - } -} - -void tst_QGraphicsItem::setRotationXYZ() -{ - QGraphicsScene scene; - QGraphicsItem *item = scene.addRect(QRectF(0, 0, 100, 100)); - - QBENCHMARK { - item->setRotation(45, 45, 45); + item->setRotation(45); item->transform(); // prevent lazy optimizing } } -- cgit v1.2.3 From b0470cd7553d26e73929bf9719eea9f49aeb6824 Mon Sep 17 00:00:00 2001 From: Andreas Aardal Hanssen Date: Wed, 5 Aug 2009 08:16:59 +0200 Subject: Add benchmarks for QGraphicsItem::setParenItem(). Ensure we test simple and deep constructs of setParentItem(). These benchmarks don't cover slowness in ancestor flag updating. QVariant is already identified as a contributor to this slowness, as is updating of the depth value (a deep tree crawl). Reviewed-by: Aaron Kennedy --- tests/benchmarks/qgraphicsitem/qgraphicsitem.pro | 1 - .../benchmarks/qgraphicsitem/tst_qgraphicsitem.cpp | 26 ++++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/tests/benchmarks/qgraphicsitem/qgraphicsitem.pro b/tests/benchmarks/qgraphicsitem/qgraphicsitem.pro index c8fc07bf1..726bb9613 100644 --- a/tests/benchmarks/qgraphicsitem/qgraphicsitem.pro +++ b/tests/benchmarks/qgraphicsitem/qgraphicsitem.pro @@ -3,4 +3,3 @@ TEMPLATE = app TARGET = tst_qgraphicsitem SOURCES += tst_qgraphicsitem.cpp - diff --git a/tests/benchmarks/qgraphicsitem/tst_qgraphicsitem.cpp b/tests/benchmarks/qgraphicsitem/tst_qgraphicsitem.cpp index 42f2e6b60..62a5b5c9e 100644 --- a/tests/benchmarks/qgraphicsitem/tst_qgraphicsitem.cpp +++ b/tests/benchmarks/qgraphicsitem/tst_qgraphicsitem.cpp @@ -25,6 +25,8 @@ public slots: void cleanup(); private slots: + void setParentItem(); + void setParentItem_deep(); void setPos_data(); void setPos(); void setTransform_data(); @@ -52,6 +54,30 @@ void tst_QGraphicsItem::cleanup() { } +void tst_QGraphicsItem::setParentItem() +{ + QBENCHMARK { + QGraphicsRectItem rect; + QGraphicsRectItem *childRect = new QGraphicsRectItem; + childRect->setParentItem(&rect); + } +} + +void tst_QGraphicsItem::setParentItem_deep() +{ + QBENCHMARK { + QGraphicsRectItem rect; + QGraphicsRectItem *lastRect = ▭ + for (int i = 0; i < 10; ++i) { + QGraphicsRectItem *childRect = new QGraphicsRectItem; + childRect->setParentItem(lastRect); + lastRect = childRect; + } + QGraphicsItem *first = rect.children().first(); + first->setParentItem(0); + } +} + void tst_QGraphicsItem::setPos_data() { QTest::addColumn("pos"); -- cgit v1.2.3 From b008dfbd67176948f6fdf830dc99d23a538a6b9c Mon Sep 17 00:00:00 2001 From: Andreas Aardal Hanssen Date: Wed, 5 Aug 2009 08:45:44 +0200 Subject: Add benchmark for deleting an item with many children. Task-number: 229124 Reviewed-by: TrustMe --- tests/benchmarks/qgraphicsitem/tst_qgraphicsitem.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/benchmarks/qgraphicsitem/tst_qgraphicsitem.cpp b/tests/benchmarks/qgraphicsitem/tst_qgraphicsitem.cpp index 62a5b5c9e..ee27ebe0e 100644 --- a/tests/benchmarks/qgraphicsitem/tst_qgraphicsitem.cpp +++ b/tests/benchmarks/qgraphicsitem/tst_qgraphicsitem.cpp @@ -27,6 +27,7 @@ public slots: private slots: void setParentItem(); void setParentItem_deep(); + void deleteItemWithManyChildren(); void setPos_data(); void setPos(); void setTransform_data(); @@ -78,6 +79,16 @@ void tst_QGraphicsItem::setParentItem_deep() } } +void tst_QGraphicsItem::deleteItemWithManyChildren() +{ + QBENCHMARK { + QGraphicsRectItem *rect = new QGraphicsRectItem; + for (int i = 0; i < 1000; ++i) + new QGraphicsRectItem(rect); + delete rect; + } +} + void tst_QGraphicsItem::setPos_data() { QTest::addColumn("pos"); -- cgit v1.2.3 From decc287134139c61da5610afc060a6ca8d09f368 Mon Sep 17 00:00:00 2001 From: Richard Moe Gustavsen Date: Tue, 4 Aug 2009 15:59:25 +0200 Subject: Cocoa: Menus show old selected values. We never told Cocoa that it needed to redraw the window view when a window was shown. This is implicit if the window is shown for the first time, but needs to be done explicit if you hide and show it again. Task-number: 254672 Reviewed-by: bnilsen --- src/gui/kernel/qwidget_mac.mm | 6 ++++++ tests/auto/qwidget_window/tst_qwidget_window.cpp | 24 +++++++++++++++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/gui/kernel/qwidget_mac.mm b/src/gui/kernel/qwidget_mac.mm index 8913c89da..057df8137 100644 --- a/src/gui/kernel/qwidget_mac.mm +++ b/src/gui/kernel/qwidget_mac.mm @@ -3249,6 +3249,12 @@ void QWidgetPrivate::show_sys() #ifndef QT_MAC_USE_COCOA SizeWindow(window, q->width(), q->height(), true); #endif + +#ifdef QT_MAC_USE_COCOA + // Make sure that we end up sending a repaint event to + // the widget if the window has been visible one before: + [qt_mac_get_contentview_for(window) setNeedsDisplay:YES]; +#endif if(qt_mac_is_macsheet(q)) { qt_event_request_showsheet(q); } else if(qt_mac_is_macdrawer(q)) { diff --git a/tests/auto/qwidget_window/tst_qwidget_window.cpp b/tests/auto/qwidget_window/tst_qwidget_window.cpp index f059abe50..6dddfe8b7 100644 --- a/tests/auto/qwidget_window/tst_qwidget_window.cpp +++ b/tests/auto/qwidget_window/tst_qwidget_window.cpp @@ -78,6 +78,7 @@ private slots: void tst_windowFilePath(); void tst_showWithoutActivating(); + void tst_paintEventOnSecondShow(); }; void tst_QWidget_window::initTestCase() @@ -150,7 +151,9 @@ class TestWidget : public QWidget { public: int m_first, m_next; - void reset(){ m_first = m_next = 0; } + bool paintEventReceived; + + void reset(){ m_first = m_next = 0; paintEventReceived = false; } bool event(QEvent *event) { switch (event->type()) { @@ -162,6 +165,10 @@ public: m_next = event->type(); else m_first = event->type(); + break; + case QEvent::Paint: + paintEventReceived = true; + break; default: break; } @@ -300,5 +307,20 @@ void tst_QWidget_window::tst_showWithoutActivating() #endif // Q_WS_X11 } +void tst_QWidget_window::tst_paintEventOnSecondShow() +{ + TestWidget w; + w.show(); + w.hide(); + + w.reset(); + w.show(); +#ifdef Q_WS_X11 + QTest::qWait(500); +#endif + QApplication::processEvents(); + QVERIFY(w.paintEventReceived); +} + QTEST_MAIN(tst_QWidget_window) #include "tst_qwidget_window.moc" -- cgit v1.2.3 From 83c76bb2d1eeca2003720d243ef656aa241a3d49 Mon Sep 17 00:00:00 2001 From: Martin Smith Date: Wed, 5 Aug 2009 10:27:44 +0200 Subject: qdoc: Removed the "No such group" qdoc error. This error was printed if you used a \ingroup xxx, but there was no \group xxx anywhere. Now we will stop using the \group command, but we will retain the \ingroup command for use with the \annotatedlist command. --- tools/qdoc3/tree.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/qdoc3/tree.cpp b/tools/qdoc3/tree.cpp index d75af70ee..f8320621e 100644 --- a/tools/qdoc3/tree.cpp +++ b/tools/qdoc3/tree.cpp @@ -575,10 +575,12 @@ void Tree::resolveGroups() if (fake && fake->subType() == Node::Group) { fake->addGroupMember(i.value()); } +#if 0 else { if (prevGroup != i.key()) i.value()->doc().location().warning(tr("No such group '%1'").arg(i.key())); } +#endif prevGroup = i.key(); } -- cgit v1.2.3 From a3cb29b310f3d8b4de919bb19d98ae93edde7c85 Mon Sep 17 00:00:00 2001 From: Thierry Bastian Date: Wed, 5 Aug 2009 11:01:12 +0200 Subject: sequential animation group: add autotest for pause/resume --- .../tst_qsequentialanimationgroup.cpp | 36 ++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/tests/auto/qsequentialanimationgroup/tst_qsequentialanimationgroup.cpp b/tests/auto/qsequentialanimationgroup/tst_qsequentialanimationgroup.cpp index 97ff04b2a..744ba5264 100644 --- a/tests/auto/qsequentialanimationgroup/tst_qsequentialanimationgroup.cpp +++ b/tests/auto/qsequentialanimationgroup/tst_qsequentialanimationgroup.cpp @@ -88,6 +88,7 @@ private slots: void currentAnimationWithZeroDuration(); void insertAnimation(); void clearAnimations(); + void pauseResume(); }; tst_QSequentialAnimationGroup::tst_QSequentialAnimationGroup() @@ -1644,5 +1645,40 @@ void tst_QSequentialAnimationGroup::clearAnimations() QCOMPARE(group.state(), QAbstractAnimation::Running); } +void tst_QSequentialAnimationGroup::pauseResume() +{ + QObject dummy; + dummy.setProperty("foo", 0); + QParallelAnimationGroup group; + QPropertyAnimation *anim = new QPropertyAnimation(&dummy, "foo", &group); + anim->setDuration(250); + anim->setEndValue(250); + QSignalSpy spy(anim, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State))); + QCOMPARE(group.duration(), 250); + group.start(); + QTest::qWait(100); + QCOMPARE(group.state(), QAnimationGroup::Running); + QCOMPARE(anim->state(), QAnimationGroup::Running); + QCOMPARE(spy.count(), 1); + spy.clear(); + const int currentTime = group.currentTime(); + QCOMPARE(anim->currentTime(), currentTime); + + group.pause(); + QCOMPARE(group.state(), QAnimationGroup::Paused); + QCOMPARE(group.currentTime(), currentTime); + QCOMPARE(anim->state(), QAnimationGroup::Paused); + QCOMPARE(anim->currentTime(), currentTime); + QCOMPARE(spy.count(), 1); + spy.clear(); + + group.resume(); + QCOMPARE(group.state(), QAnimationGroup::Running); + QCOMPARE(group.currentTime(), currentTime); + QCOMPARE(anim->state(), QAnimationGroup::Running); + QCOMPARE(anim->currentTime(), currentTime); + QCOMPARE(spy.count(), 1); +} + QTEST_MAIN(tst_QSequentialAnimationGroup) #include "tst_qsequentialanimationgroup.moc" -- cgit v1.2.3 From bcf41cf9dbe9921bb50b8cf2fcdcd9884e94412f Mon Sep 17 00:00:00 2001 From: Volker Hilsheimer Date: Wed, 5 Aug 2009 11:03:55 +0200 Subject: Make \annotatedlist work also in pages that are not \group pages. The command right now only lists the classes in the group, in alphabetical order. Not ideal for integrating into overviews, where the list should be ordered by relevance. --- tools/qdoc3/htmlgenerator.cpp | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/tools/qdoc3/htmlgenerator.cpp b/tools/qdoc3/htmlgenerator.cpp index 425c50b12..6b15f96c7 100644 --- a/tools/qdoc3/htmlgenerator.cpp +++ b/tools/qdoc3/htmlgenerator.cpp @@ -539,16 +539,13 @@ int HtmlGenerator::generateAtom(const Atom *atom, break; case Atom::AnnotatedList: { - const FakeNode *fake = static_cast(relative); - if (fake && !fake->groupMembers().isEmpty()) { - QList values = tre->groups().values(atom->string()); - QMap nodeMap; - for (int i = 0; i < values.size(); ++i) { - const Node* n = values.at(i); - nodeMap.insert(n->name(),n); - } - generateAnnotatedList(fake, marker, nodeMap); + QList values = tre->groups().values(atom->string()); + QMap nodeMap; + for (int i = 0; i < values.size(); ++i) { + const Node* n = values.at(i); + nodeMap.insert(n->name(),n); } + generateAnnotatedList(relative, marker, nodeMap); } break; case Atom::GeneratedList: -- cgit v1.2.3 From 118c82b0988c671045de448ffabc7ba95f015a69 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Wed, 5 Aug 2009 10:42:46 +0200 Subject: Fixes hangup when pressing key in QListWidget If there is severals matching items but all of them are disabled, it would have produced an infinite loop. Block the loop once we reach an already matched item. Task-number: 258949 Reviewed-by: Thierry --- src/gui/itemviews/qabstractitemview.cpp | 7 +++++++ tests/auto/qlistwidget/tst_qlistwidget.cpp | 23 ++++++++++++++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/gui/itemviews/qabstractitemview.cpp b/src/gui/itemviews/qabstractitemview.cpp index 859496809..f7d5f1b9e 100644 --- a/src/gui/itemviews/qabstractitemview.cpp +++ b/src/gui/itemviews/qabstractitemview.cpp @@ -2666,6 +2666,7 @@ void QAbstractItemView::keyboardSearch(const QString &search) QModelIndex current = start; QModelIndexList match; QModelIndex firstMatch; + QModelIndex startMatch; QModelIndexList previous; do { match = d->model->match(current, Qt::DisplayRole, searchString); @@ -2682,6 +2683,12 @@ void QAbstractItemView::keyboardSearch(const QString &search) if (row >= d->model->rowCount(firstMatch.parent())) row = 0; current = firstMatch.sibling(row, firstMatch.column()); + + //avoid infinite loop if all the matching items are disabled. + if (!startMatch.isValid()) + startMatch = firstMatch; + else if (startMatch == firstMatch) + break; } } while (current != start && firstMatch.isValid()); } diff --git a/tests/auto/qlistwidget/tst_qlistwidget.cpp b/tests/auto/qlistwidget/tst_qlistwidget.cpp index a56a47080..e38ef2079 100644 --- a/tests/auto/qlistwidget/tst_qlistwidget.cpp +++ b/tests/auto/qlistwidget/tst_qlistwidget.cpp @@ -128,6 +128,8 @@ private slots: void setSortingEnabled(); void task199503_crashWhenCleared(); void task217070_scrollbarsAdjusted(); + void task258949_keypressHangup(); + protected slots: void rowsAboutToBeInserted(const QModelIndex &parent, int first, int last) @@ -994,7 +996,7 @@ void tst_QListWidget::sortHiddenItems() for (int k = 0; k < tw->count(); ++k) QCOMPARE(persistent.at(k).row(), expectedRows.at(k)); - + delete tw; } @@ -1498,5 +1500,24 @@ void tst_QListWidget::task217070_scrollbarsAdjusted() } } +void tst_QListWidget::task258949_keypressHangup() +{ + QListWidget lw; + for (int y = 0; y < 5; y++) { + QListWidgetItem *lwi = new QListWidgetItem(&lw); + lwi->setText(y ? "1" : "0"); + if (y) + lwi->setFlags(Qt::ItemIsSelectable); + } + + lw.show(); + lw.setCurrentIndex(lw.model()->index(0,0)); + QCOMPARE(lw.currentIndex(), lw.model()->index(0,0)); + QTest::qWait(30); + QTest::keyPress(&lw, '1'); //this used to freeze + QTest::qWait(30); + QCOMPARE(lw.currentIndex(), lw.model()->index(0,0)); +} + QTEST_MAIN(tst_QListWidget) #include "tst_qlistwidget.moc" -- cgit v1.2.3 From e3e1ea6c52473f120f8baee57e189ddc1c8671cb Mon Sep 17 00:00:00 2001 From: Thierry Bastian Date: Wed, 5 Aug 2009 11:11:37 +0200 Subject: QMenu: fix a crash depending on styles We were calling pixelMetric and sizeFromContents with a NULL styleoption That crashes on mac and might also with other styles. --- src/gui/widgets/qmenu.cpp | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/gui/widgets/qmenu.cpp b/src/gui/widgets/qmenu.cpp index 67bb10a9f..05426a01f 100644 --- a/src/gui/widgets/qmenu.cpp +++ b/src/gui/widgets/qmenu.cpp @@ -225,13 +225,17 @@ void QMenuPrivate::updateActionRects() const dh = popupGeometry(QApplication::desktop()->screenNumber(q)).height(), y = 0; QStyle *style = q->style(); - const int hmargin = style->pixelMetric(QStyle::PM_MenuHMargin, 0, q), - vmargin = style->pixelMetric(QStyle::PM_MenuVMargin, 0, q), - icone = style->pixelMetric(QStyle::PM_SmallIconSize, 0, q); - const int fw = style->pixelMetric(QStyle::PM_MenuPanelWidth, 0, q); - - const int sfcMargin = style->sizeFromContents(QStyle::CT_Menu, 0, QApplication::globalStrut(), q).width() - QApplication::globalStrut().width(); + QStyleOption opt; + opt.init(q); + const int hmargin = style->pixelMetric(QStyle::PM_MenuHMargin, &opt, q), + vmargin = style->pixelMetric(QStyle::PM_MenuVMargin, &opt, q), + icone = style->pixelMetric(QStyle::PM_SmallIconSize, &opt, q); + const int fw = style->pixelMetric(QStyle::PM_MenuPanelWidth, &opt, q); + const int deskFw = style->pixelMetric(QStyle::PM_MenuDesktopFrameWidth, &opt, q); + + const int sfcMargin = style->sizeFromContents(QStyle::CT_Menu, &opt, QApplication::globalStrut(), q).width() - QApplication::globalStrut().width(); const int min_column_width = q->minimumWidth() - (sfcMargin + leftmargin + rightmargin + 2 * (fw + hmargin)); + const int tearoffHeight = tearoff ? style->pixelMetric(QStyle::PM_MenuTearoffHeight, &opt, q) : 0; //for compatability now - will have to refactor this away.. tabWidth = 0; @@ -307,7 +311,7 @@ void QMenuPrivate::updateActionRects() const max_column_width = qMax(min_column_width, qMax(max_column_width, sz.width())); //wrapping if (!scroll && - y+sz.height()+vmargin > dh - (style->pixelMetric(QStyle::PM_MenuDesktopFrameWidth, 0, q) * 2)) { + y+sz.height()+vmargin > dh - (deskFw * 2)) { ncols++; y = vmargin; } @@ -322,7 +326,7 @@ void QMenuPrivate::updateActionRects() const //calculate position const int base_y = vmargin + fw + topmargin + (scroll ? scroll->scrollOffset : 0) + - (tearoff ? style->pixelMetric(QStyle::PM_MenuTearoffHeight, 0, q) : 0); + tearoffHeight; int x = hmargin + fw + leftmargin; y = base_y; @@ -331,7 +335,7 @@ void QMenuPrivate::updateActionRects() const if (rect.isNull()) continue; if (!scroll && - y+rect.height() > dh - (style->pixelMetric(QStyle::PM_MenuDesktopFrameWidth, 0, q) * 2)) { + y+rect.height() > dh - deskFw * 2) { x += max_column_width + hmargin; y = base_y; } -- cgit v1.2.3 From 5f52d473eec0f1b46200b06dd7f5e16cb5c57c05 Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Wed, 5 Aug 2009 10:57:13 +0200 Subject: Fix compilation when QT_NO_HTTP is defined Note however you still need to -nomake examples -nomake demos when configuring Qt. Reviewed-by: Thiago Task: 259179 --- src/network/access/qhttpnetworkheader.cpp | 3 +++ src/network/access/qhttpnetworkreply_p.h | 1 + src/network/access/qhttpnetworkrequest.cpp | 4 ++++ src/qt3support/network/q3http.cpp | 2 +- src/qt3support/network/q3http.h | 5 ++--- src/qt3support/network/q3network.cpp | 2 +- tools/assistant/tools/assistant/installdialog.cpp | 2 ++ tools/assistant/tools/assistant/installdialog.h | 4 ++++ 8 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/network/access/qhttpnetworkheader.cpp b/src/network/access/qhttpnetworkheader.cpp index 5af9764e0..88cc48443 100644 --- a/src/network/access/qhttpnetworkheader.cpp +++ b/src/network/access/qhttpnetworkheader.cpp @@ -41,6 +41,7 @@ #include "qhttpnetworkheader_p.h" +#ifndef QT_NO_HTTP QT_BEGIN_NAMESPACE @@ -121,3 +122,5 @@ bool QHttpNetworkHeaderPrivate::operator==(const QHttpNetworkHeaderPrivate &othe QT_END_NAMESPACE + +#endif diff --git a/src/network/access/qhttpnetworkreply_p.h b/src/network/access/qhttpnetworkreply_p.h index 76aa947b3..65ed4ceaf 100644 --- a/src/network/access/qhttpnetworkreply_p.h +++ b/src/network/access/qhttpnetworkreply_p.h @@ -52,6 +52,7 @@ // // We mean it. // +#include #ifndef QT_NO_HTTP #ifndef QT_NO_COMPRESS diff --git a/src/network/access/qhttpnetworkrequest.cpp b/src/network/access/qhttpnetworkrequest.cpp index 02ba629d5..32d51f32f 100644 --- a/src/network/access/qhttpnetworkrequest.cpp +++ b/src/network/access/qhttpnetworkrequest.cpp @@ -41,6 +41,8 @@ #include "qhttpnetworkrequest_p.h" +#ifndef QT_NO_HTTP + QT_BEGIN_NAMESPACE QHttpNetworkRequestPrivate::QHttpNetworkRequestPrivate(QHttpNetworkRequest::Operation op, @@ -259,3 +261,5 @@ int QHttpNetworkRequest::minorVersion() const QT_END_NAMESPACE +#endif + diff --git a/src/qt3support/network/q3http.cpp b/src/qt3support/network/q3http.cpp index a38edad3c..e44dfe868 100644 --- a/src/qt3support/network/q3http.cpp +++ b/src/qt3support/network/q3http.cpp @@ -42,7 +42,7 @@ #include #include "q3http.h" -#ifndef QT_NO_NETWORKPROTOCOL_HTTP +#ifndef QT_NO_HTTP #include "q3socket.h" #include "qtextstream.h" diff --git a/src/qt3support/network/q3http.h b/src/qt3support/network/q3http.h index 93ab00e7f..5311764d7 100644 --- a/src/qt3support/network/q3http.h +++ b/src/qt3support/network/q3http.h @@ -52,8 +52,7 @@ QT_BEGIN_HEADER QT_BEGIN_NAMESPACE QT_MODULE(Qt3Support) - -#ifndef QT_NO_NETWORKPROTOCOL_HTTP +#ifndef QT_NO_HTTP class Q3Socket; class QTimerEvent; @@ -269,7 +268,7 @@ private: friend class Q3HttpPGHRequest; }; -#endif // QT_NO_NETWORKPROTOCOL_HTTP +#endif // QT_NO_HTTP QT_END_NAMESPACE diff --git a/src/qt3support/network/q3network.cpp b/src/qt3support/network/q3network.cpp index 3a6a6f034..1f918d138 100644 --- a/src/qt3support/network/q3network.cpp +++ b/src/qt3support/network/q3network.cpp @@ -63,7 +63,7 @@ void q3InitNetworkProtocols() #ifndef QT_NO_NETWORKPROTOCOL_FTP Q3NetworkProtocol::registerNetworkProtocol( QLatin1String("ftp"), new Q3NetworkProtocolFactory< Q3Ftp > ); #endif -#ifndef QT_NO_NETWORKPROTOCOL_HTTP +#ifndef QT_NO_HTTP Q3NetworkProtocol::registerNetworkProtocol( QLatin1String("http"), new Q3NetworkProtocolFactory< Q3Http > ); #endif } diff --git a/tools/assistant/tools/assistant/installdialog.cpp b/tools/assistant/tools/assistant/installdialog.cpp index 5a8dfeaf8..2574f1f8b 100644 --- a/tools/assistant/tools/assistant/installdialog.cpp +++ b/tools/assistant/tools/assistant/installdialog.cpp @@ -56,6 +56,7 @@ #include QT_BEGIN_NAMESPACE +#ifndef QT_NO_HTTP #define QCH_FILENAME 92943 #define QCH_NAMESPACE 92944 @@ -335,4 +336,5 @@ void InstallDialog::browseDirectories() m_ui.pathLineEdit->setText(dir); } +#endif QT_END_NAMESPACE diff --git a/tools/assistant/tools/assistant/installdialog.h b/tools/assistant/tools/assistant/installdialog.h index 62759ecd7..9e18a22b9 100644 --- a/tools/assistant/tools/assistant/installdialog.h +++ b/tools/assistant/tools/assistant/installdialog.h @@ -47,6 +47,8 @@ #include #include "ui_installdialog.h" +#ifndef QT_NO_HTTP + QT_BEGIN_NAMESPACE class QHttp; @@ -98,4 +100,6 @@ private: QT_END_NAMESPACE +#endif + #endif // INSTALLDIALOG_H -- cgit v1.2.3 From c379e151adc9c781f8f1e3d33cf68b3137868185 Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Wed, 5 Aug 2009 11:11:52 +0200 Subject: cetest: add support for cetcpsync (our simple ActiveSync replacement) Reviewed-By: mauricek --- .../qtestlib/wince/cetest/cetcpsyncconnection.cpp | 198 +++++++++++++++++++++ tools/qtestlib/wince/cetest/cetcpsyncconnection.h | 82 +++++++++ tools/qtestlib/wince/cetest/cetest.pro | 19 +- tools/qtestlib/wince/cetest/deployment.cpp | 2 + tools/qtestlib/wince/cetest/main.cpp | 11 +- 5 files changed, 305 insertions(+), 7 deletions(-) create mode 100644 tools/qtestlib/wince/cetest/cetcpsyncconnection.cpp create mode 100644 tools/qtestlib/wince/cetest/cetcpsyncconnection.h diff --git a/tools/qtestlib/wince/cetest/cetcpsyncconnection.cpp b/tools/qtestlib/wince/cetest/cetcpsyncconnection.cpp new file mode 100644 index 000000000..bebcd1cf1 --- /dev/null +++ b/tools/qtestlib/wince/cetest/cetcpsyncconnection.cpp @@ -0,0 +1,198 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "CeTcpSyncConnection.h" +#include +#include +#include + +extern void debugOutput(const QString& text, int level); + +CeTcpSyncConnection::CeTcpSyncConnection() + : AbstractRemoteConnection() + , connected(false) +{ +} + +CeTcpSyncConnection::~CeTcpSyncConnection() +{ + if (isConnected()) + disconnect(); +} + +bool CeTcpSyncConnection::connect(QVariantList&) +{ + // We connect with each command, so this is always true + // The command itself will fail then + if (system("cetcpsync noop") != 0) + return false; + connected = true; + return true; +} + +void CeTcpSyncConnection::disconnect() +{ + connected = false; +} + +bool CeTcpSyncConnection::isConnected() const +{ + return connected; +} + +inline QString boolToString(bool b) +{ + return b ? "true" : "false"; +} + +static bool fileTimeFromString(FILETIME& ft, const QString& str) +{ + int idx = str.indexOf("*"); + if (idx <= 0) + return false; + bool ok; + ft.dwLowDateTime = str.left(idx).toULong(&ok); + if (!ok) + return false; + ft.dwHighDateTime = str.mid(idx+1).toULong(&ok); + return ok; +} + +static QString fileTimeToString(FILETIME& ft) +{ + return QString::number(ft.dwLowDateTime) + "*" + QString::number(ft.dwHighDateTime); +} + +bool CeTcpSyncConnection::copyFileToDevice(const QString &localSource, const QString &deviceDest, bool failIfExists) +{ + QString cmd = "cetcpsync copyFileToDevice \"" + localSource + "\" \"" + deviceDest + "\" " + boolToString(failIfExists); + return system(qPrintable(cmd)) == 0; +} + +bool CeTcpSyncConnection::copyDirectoryToDevice(const QString &localSource, const QString &deviceDest, bool recursive) +{ + QString cmd = "cetcpsync copyDirectoryToDevice \"" + localSource + "\" \"" + deviceDest + "\" " + boolToString(recursive); + return system(qPrintable(cmd)) == 0; +} + +bool CeTcpSyncConnection::copyFileFromDevice(const QString &deviceSource, const QString &localDest, bool failIfExists) +{ + QString cmd = "cetcpsync copyFileFromDevice \"" + deviceSource + "\" \"" + localDest + "\" " + boolToString(failIfExists); + return system(qPrintable(cmd)) == 0; +} + +bool CeTcpSyncConnection::copyDirectoryFromDevice(const QString &deviceSource, const QString &localDest, bool recursive) +{ + QString cmd = "cetcpsync copyDirectoryFromDevice \"" + deviceSource + "\" \"" + localDest + "\" " + boolToString(recursive); + return system(qPrintable(cmd)) == 0; +} + +bool CeTcpSyncConnection::copyFile(const QString &srcFile, const QString &destFile, bool failIfExists) +{ + QString cmd = "cetcpsync copyFile \"" + srcFile + "\" \"" + destFile + "\" " + boolToString(failIfExists); + return system(qPrintable(cmd)) == 0; +} + +bool CeTcpSyncConnection::copyDirectory(const QString &srcDirectory, const QString &destDirectory, + bool recursive) +{ + QString cmd = "cetcpsync copyDirectory \"" + srcDirectory + "\" \"" + destDirectory + "\" " + boolToString(recursive); + return system(qPrintable(cmd)) == 0; +} + +bool CeTcpSyncConnection::deleteFile(const QString &fileName) +{ + QString cmd = "cetcpsync deleteFile \"" + fileName + "\""; + return system(qPrintable(cmd)) == 0; +} + +bool CeTcpSyncConnection::deleteDirectory(const QString &directory, bool recursive, bool failIfContentExists) +{ + QString cmd = "cetcpsync deleteDirectory \"" + directory + "\" " + boolToString(recursive) + " " + boolToString(failIfContentExists); + return system(qPrintable(cmd)) == 0; +} + +bool CeTcpSyncConnection::execute(QString program, QString arguments, int timeout, int *returnValue) +{ + QString cmd = "cetcpsync execute \"" + program + "\" \"" + arguments + "\" " + QString::number(timeout); + int exitCode = system(qPrintable(cmd)); + if (returnValue) + *returnValue = exitCode; + return true; +} + +bool CeTcpSyncConnection::createDirectory(const QString &path, bool deleteBefore) +{ + QString cmd = "cetcpsync createDirectory \"" + path + "\" " + boolToString(deleteBefore); + return system(qPrintable(cmd)) == 0; +} + +bool CeTcpSyncConnection::timeStampForLocalFileTime(FILETIME* fTime) const +{ + QString cmd = "cetcpsync timeStampForLocalFileTime " + fileTimeToString(*fTime) + " >filetime.txt"; + if (system(qPrintable(cmd)) != 0) + return false; + + QFile file("filetime.txt"); + if (!file.open(QIODevice::ReadOnly)) + return false; + + bool result = fileTimeFromString(*fTime, file.readLine()); + file.close(); + file.remove(); + return result; +} + +bool CeTcpSyncConnection::fileCreationTime(const QString &fileName, FILETIME* deviceCreationTime) const +{ + QString cmd = "cetcpsync fileCreationTime \"" + fileName + "\" >filetime.txt"; + if (system(qPrintable(cmd)) != 0) + return false; + + QFile file("filetime.txt"); + if (!file.open(QIODevice::ReadOnly)) + return false; + + bool result = fileTimeFromString(*deviceCreationTime, file.readLine()); + file.close(); + file.remove(); + return result; +} diff --git a/tools/qtestlib/wince/cetest/cetcpsyncconnection.h b/tools/qtestlib/wince/cetest/cetcpsyncconnection.h new file mode 100644 index 000000000..1ef8423cf --- /dev/null +++ b/tools/qtestlib/wince/cetest/cetcpsyncconnection.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CETCPSYNC_REMOTECONNECTION_H +#define CETCPSYNC_REMOTECONNECTION_H + +#include "remoteconnection.h" + +class CeTcpSyncConnection : public AbstractRemoteConnection +{ +public: + CeTcpSyncConnection(); + virtual ~CeTcpSyncConnection(); + + bool connect(QVariantList &list = QVariantList()); + void disconnect(); + bool isConnected() const; + + // These functions are designed for transfer between desktop and device + // Caution: deviceDest path has to be device specific (eg. no drive letters for CE) + bool copyFileToDevice(const QString &localSource, const QString &deviceDest, bool failIfExists = false); + bool copyDirectoryToDevice(const QString &localSource, const QString &deviceDest, bool recursive = true); + bool copyFileFromDevice(const QString &deviceSource, const QString &localDest, bool failIfExists = false); + bool copyDirectoryFromDevice(const QString &deviceSource, const QString &localDest, bool recursive = true); + + bool timeStampForLocalFileTime(FILETIME*) const; + bool fileCreationTime(const QString &fileName, FILETIME*) const; + + // These functions only work on files existing on the device + bool copyFile(const QString&, const QString&, bool failIfExists = false); + bool copyDirectory(const QString&, const QString&, bool recursive = true); + bool deleteFile(const QString&); + bool deleteDirectory(const QString&, bool recursive = true, bool failIfContentExists = false); + bool moveFile(const QString&, const QString&, bool FailIfExists = false); + bool moveDirectory(const QString&, const QString&, bool recursive = true); + + bool createDirectory(const QString&, bool deleteBefore=false); + + bool execute(QString program, QString arguments = QString(), int timeout = -1, int *returnValue = NULL); +private: + bool connected; +}; + +#endif diff --git a/tools/qtestlib/wince/cetest/cetest.pro b/tools/qtestlib/wince/cetest/cetest.pro index d66fa3318..c6eba7fdc 100644 --- a/tools/qtestlib/wince/cetest/cetest.pro +++ b/tools/qtestlib/wince/cetest/cetest.pro @@ -28,20 +28,27 @@ DEPENDPATH += $$QT_BUILD_TREE/src/corelib/tools $$QT_BUILD_TREE/src/corelib/io # Input HEADERS += \ remoteconnection.h \ - activesyncconnection.h \ deployment.h SOURCES += \ remoteconnection.cpp \ - activesyncconnection.cpp \ deployment.cpp \ main.cpp -win32-msvc*:LIBS += ole32.lib advapi32.lib rapi.lib +win32-msvc*:LIBS += ole32.lib advapi32.lib + +isEmpty(QT_CE_RAPI_INC) { + DEFINES += QT_CETEST_NO_ACTIVESYNC + HEADERS += cetcpsyncconnection.h + SOURCES += cetcpsyncconnection.cpp +} else { + HEADERS += activesyncconnection.h + SOURCES += activesyncconnection.cpp + win32-msvc*:LIBS += rapi.lib + INCLUDEPATH += $$QT_CE_RAPI_INC + LIBS += -L$$QT_CE_RAPI_LIB +} include(qmake_include.pri) include(bootstrapped.pri) include($$QT_SOURCE_TREE/src/script/script.pri) - -INCLUDEPATH += $$QT_CE_RAPI_INC -LIBS += -L$$QT_CE_RAPI_LIB diff --git a/tools/qtestlib/wince/cetest/deployment.cpp b/tools/qtestlib/wince/cetest/deployment.cpp index 68f0197f0..c64ae261e 100644 --- a/tools/qtestlib/wince/cetest/deployment.cpp +++ b/tools/qtestlib/wince/cetest/deployment.cpp @@ -168,6 +168,7 @@ void DeploymentHandler::initQtDeploy(QMakeProject *project, DeploymentList &depl } } +#ifndef QT_CETEST_NO_ACTIVESYNC // QtRemote deployment. We always deploy to \Windows if (!project->values("QMAKE_LIBDIR").isEmpty()) { QString remoteLibName = QLatin1String("QtRemote.dll"); @@ -177,6 +178,7 @@ void DeploymentHandler::initQtDeploy(QMakeProject *project, DeploymentList &depl else debugOutput(QString::fromLatin1("Could not find QtRemote. Might not be able to launch target executable"),0); } +#endif // C-runtime deployment QString runtime = project->values("QT_CE_C_RUNTIME").join(QLatin1String(" ")); diff --git a/tools/qtestlib/wince/cetest/main.cpp b/tools/qtestlib/wince/cetest/main.cpp index 782f6d953..e0e475ccc 100644 --- a/tools/qtestlib/wince/cetest/main.cpp +++ b/tools/qtestlib/wince/cetest/main.cpp @@ -39,7 +39,12 @@ ** ****************************************************************************/ -#include "activesyncconnection.h" +#ifdef QT_CETEST_NO_ACTIVESYNC +# include "cetcpsyncconnection.h" +#else +# include "activesyncconnection.h" +#endif + #include "deployment.h" #include #include @@ -290,7 +295,11 @@ int main(int argc, char **argv) projectDeploymentList.append(CopyItem(TestConfiguration::localExecutable , TestConfiguration::remoteExecutable)); // deploy +#ifdef QT_CETEST_NO_ACTIVESYNC + CeTcpSyncConnection connection; +#else ActiveSyncConnection connection; +#endif if (!connection.connect()) { cout << "Error: Could not connect to device!" << endl; return -1; -- cgit v1.2.3 From ad8247fcbe7d7e3e3c0227d54f6abc2ef6160f9b Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Wed, 5 Aug 2009 11:33:22 +0200 Subject: initial revision of cetcpsyncserver cetcpsync is our simple ActiveSync replacement for Windows CE devices. This is the server which has to run on the device. Reviewed-By: mauricek --- .../wince/cetcpsyncserver/cetcpsyncserver.pro | 17 + tools/qtestlib/wince/cetcpsyncserver/commands.cpp | 646 +++++++++++++++++++++ tools/qtestlib/wince/cetcpsyncserver/commands.h | 292 ++++++++++ .../wince/cetcpsyncserver/connectionmanager.cpp | 138 +++++ .../wince/cetcpsyncserver/connectionmanager.h | 83 +++ tools/qtestlib/wince/cetcpsyncserver/main.cpp | 63 ++ .../wince/cetcpsyncserver/transfer_global.h | 159 +++++ 7 files changed, 1398 insertions(+) create mode 100644 tools/qtestlib/wince/cetcpsyncserver/cetcpsyncserver.pro create mode 100644 tools/qtestlib/wince/cetcpsyncserver/commands.cpp create mode 100644 tools/qtestlib/wince/cetcpsyncserver/commands.h create mode 100644 tools/qtestlib/wince/cetcpsyncserver/connectionmanager.cpp create mode 100644 tools/qtestlib/wince/cetcpsyncserver/connectionmanager.h create mode 100644 tools/qtestlib/wince/cetcpsyncserver/main.cpp create mode 100644 tools/qtestlib/wince/cetcpsyncserver/transfer_global.h diff --git a/tools/qtestlib/wince/cetcpsyncserver/cetcpsyncserver.pro b/tools/qtestlib/wince/cetcpsyncserver/cetcpsyncserver.pro new file mode 100644 index 000000000..bd01d2dab --- /dev/null +++ b/tools/qtestlib/wince/cetcpsyncserver/cetcpsyncserver.pro @@ -0,0 +1,17 @@ +TEMPLATE = app +TARGET = cetcpsyncsvr +DEPENDPATH += . +QT -= gui +QT += network + +CONFIG += console + +HEADERS += \ + connectionmanager.h \ + commands.h \ + transfer_global.h + +SOURCES += \ + connectionmanager.cpp \ + commands.cpp \ + main.cpp diff --git a/tools/qtestlib/wince/cetcpsyncserver/commands.cpp b/tools/qtestlib/wince/cetcpsyncserver/commands.cpp new file mode 100644 index 000000000..64869c450 --- /dev/null +++ b/tools/qtestlib/wince/cetcpsyncserver/commands.cpp @@ -0,0 +1,646 @@ +#include "commands.h" +#include +#include +#include +#include + +#ifdef Q_OS_WINCE +#include +#endif + +///////////////////////////////////////////////////// +// Abstract Command Implementation // +///////////////////////////////////////////////////// +AbstractCommand::AbstractCommand() +: m_socket(0) +{ +} + +AbstractCommand::~AbstractCommand() +{ +} + +void AbstractCommand::reportSuccess() +{ + m_socket->write(COMMAND_SUCCESS, strlen(COMMAND_SUCCESS)); + m_socket->waitForBytesWritten(); +} + +void AbstractCommand::reportError() +{ + m_socket->write(COMMAND_ERROR, strlen(COMMAND_ERROR)); + m_socket->waitForBytesWritten(); +} + +void AbstractCommand::dataReceived(QByteArray&) +{ + debugOutput(1, "AbstractCommand::dataReceived NOT SUPPOSED TO BE HERE"); +} + +void AbstractCommand::commandFinished() +{ + debugOutput(1, "AbstractCommand::commandFinished()NOT SUPPOSED TO BE HERE"); +} + +void AbstractCommand::setSocket(QTcpSocket* socket) +{ + debugOutput(0, "AbstractCommand::setSocket()"); + Q_ASSERT(socket); + m_socket = socket; + connect(m_socket, SIGNAL(readyRead()), this, SLOT(_readData())); + reportSuccess(); +} + +QTcpSocket* AbstractCommand::socket() +{ + return m_socket; +} + +void AbstractCommand::_readData() +{ + QByteArray arr = m_socket->readAll(); + dataReceived(arr); +} + +void AbstractCommand::_disconnect() +{ +} + +///////////////////////////////////////////////////// +// Create File Command Implementation // +///////////////////////////////////////////////////// +CreateFileCommand::CreateFileCommand() +: m_dataCount(0) +{ + debugOutput(0, "CreateFileCommand::CreateFileCommand"); + m_options.fileSize= -1; +} + +CreateFileCommand::~CreateFileCommand() +{ + debugOutput(0, "CreateFileCommand::~CreateFileCommand"); + if (m_file.isOpen()) { + fprintf(stderr, "****************FILE IS STILL OPENED AND HAVENT FINISHED WRITING**********************\n"); + fprintf(stderr, "Current: %d Expected: %d\n", m_dataCount , m_options.fileSize); + m_file.close(); + } +} + +void CreateFileCommand::dataReceived(QByteArray &data) +{ + bool successful = true; + // If we haven't received the options yet + if (m_options.fileSize == -1) { + CreateFileOptions* opt = (CreateFileOptions*) data.data(); + memcpy(&m_options , opt , sizeof(CreateFileOptions)); + + if (QFileInfo(QString::fromLatin1(m_options.fileName)).exists()) { + if (m_options.overwriteExisting) { +#ifdef Q_OS_WINCE + SetFileAttributes(QFileInfo(m_options.fileName).absoluteFilePath().utf16(), FILE_ATTRIBUTE_NORMAL); +#endif + QFile::remove(m_options.fileName); + } else + successful = false; + } + m_file.setFileName(QString::fromLatin1(m_options.fileName)); + if (!m_file.open(QIODevice::WriteOnly)) + successful = false; + else + debugOutput(3, QString::fromLatin1("Creating file: %1").arg(m_options.fileName)); + } else { // write buffer on disc + if (!m_file.isOpen()) + return; + m_file.write(data); + m_dataCount += data.size(); + if (m_dataCount >= m_options.fileSize) { + // We do not care about more data than announced + m_file.close(); + } + } + + if (successful) + reportSuccess(); + else + reportError(); +} + +void CreateFileCommand::commandFinished() +{ + debugOutput(0, "CreateFileCommand::commandFinished"); +#ifdef Q_OS_WIN + // We need to set the file attributes for intelligent time comparisons + QString tmpFile = QString::fromLatin1(m_options.fileName); + HANDLE handle = CreateFile(tmpFile.utf16(), GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); + if (handle != INVALID_HANDLE_VALUE) { + SetFileTime(handle, &(m_options.fileTime), NULL, NULL); + CloseHandle(handle); + } + SetFileAttributes(tmpFile.utf16(), m_options.fileAttributes); +#endif +} + +///////////////////////////////////////////////////// +// Create Directory Command Implementation // +///////////////////////////////////////////////////// +CreateDirectoryCommand::CreateDirectoryCommand() + : AbstractCommand() +{ + debugOutput(0, "CreateDirectoryCommand::CreateDirectoryCommand"); +} + +CreateDirectoryCommand::~CreateDirectoryCommand() +{ + debugOutput(0, "CreateDirectoryCommand::~CreateDirectoryCommand()"); +} + +void CreateDirectoryCommand::dataReceived(QByteArray &data) +{ + debugOutput(0, "CreateDirectoryCommand::dataReceived()"); + CreateDirectoryOptions* options = (CreateDirectoryOptions*) data.data(); + debugOutput(3, QString::fromLatin1("Creating directory: %1").arg(options->dirName)); + bool success = true; + QDir dir; + if (options->recursively) + success = dir.mkpath(options->dirName); + else + success = dir.mkdir(options->dirName); + + if (success) + reportSuccess(); + else + reportError(); +} + +void CreateDirectoryCommand::commandFinished() +{ + debugOutput(0, "CreateDirectoryCommand::commandFinished()"); +} + +///////////////////////////////////////////////////// +// Copy File Command Implementation // +///////////////////////////////////////////////////// +CopyFileCommand::CopyFileCommand() + : AbstractCommand() +{ + debugOutput(0, "CopyFileCommand::CopyFileCommand()"); +} + +CopyFileCommand::~CopyFileCommand() +{ + debugOutput(0, "CopyFileCommand::~CopyFileCommand()"); +} + +void CopyFileCommand::dataReceived(QByteArray &data) +{ + debugOutput(0, "CopyFileCommand::dataReceived()"); + CopyFileOptions* options = (CopyFileOptions*) data.data(); + debugOutput(3, QString::fromLatin1("Copy File: %1 -> %2").arg(options->from).arg(options->to)); + bool success = true; + if (QFileInfo(options->to).exists()) { + if (options->overwriteExisting) + QFile::remove(options->to); + else + success = false; + } + if (success) + if (!QFile::copy(options->from , options->to)) + success = false; + + if (success) + reportSuccess(); + else + reportError(); +} + +void CopyFileCommand::commandFinished() +{ + debugOutput(0, "CopyFileCommand::commandFinished()"); +} + +///////////////////////////////////////////////////// +// Copy Directory Command Implementation // +///////////////////////////////////////////////////// +CopyDirectoryCommand::CopyDirectoryCommand() + : AbstractCommand() +{ + debugOutput(0, "CopyDirectoryCommand::CopyDirectoryCommand()"); +} + +CopyDirectoryCommand::~CopyDirectoryCommand() +{ + debugOutput(0, "CopyDirectoryCommand::~CopyDirectoryCommand()"); +} + +void CopyDirectoryCommand::dataReceived(QByteArray &data) +{ + debugOutput(0, "CopyDirectoryCommand::dataReceived()"); + CopyDirectoryOptions* options = (CopyDirectoryOptions*) data.data(); + debugOutput(3, QString::fromLatin1("Copy Directory: %1 %2").arg(options->from).arg(options->to)); + if (copyDir(QLatin1String(options->from) , QLatin1String(options->to) , options->recursive)) + reportSuccess(); + else + reportError(); +} + +void CopyDirectoryCommand::commandFinished() +{ + debugOutput(0, "CopyDirectoryCommand::commandFinished()"); +} + +bool CopyDirectoryCommand::copyDir(const QString &from, const QString &to, bool recursive) +{ + QDir().mkpath(to); + QDir sourceDir(from); + QDir destDir(to); + QStringList entries = sourceDir.entryList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot); + foreach (QString item , entries) { + QString itemFrom = sourceDir.absoluteFilePath(item); + QString itemTo = destDir.absoluteFilePath(item); + if (QFileInfo(item).isDir()) { + if (recursive && !copyDir(itemFrom, itemTo, recursive)) + return false; + } else { + if (!QFile::copy(itemFrom, itemTo)) + return false; + } + } + return true; +} + +///////////////////////////////////////////////////// +// Delete File Command Implementation // +///////////////////////////////////////////////////// +DeleteFileCommand::DeleteFileCommand() + : AbstractCommand() +{ + debugOutput(0, "DeleteFileCommand::DeleteFileCommand()"); +} + +DeleteFileCommand::~DeleteFileCommand() +{ + debugOutput(0, "DeleteFileCommand::~DeleteFileCommand()"); +} + +void DeleteFileCommand::dataReceived(QByteArray &data) +{ + debugOutput(0, "DeleteFileCommand::dataReceived()"); + DeleteFileOptions* options = (DeleteFileOptions*) data.data(); + debugOutput(3, QString::fromLatin1("Delete File: %1").arg(options->fileName)); + bool success = true; + QFile file(options->fileName); + if (file.exists()) { +#ifdef Q_OS_WINCE + SetFileAttributes(QFileInfo(options->fileName).absoluteFilePath().utf16(), FILE_ATTRIBUTE_NORMAL); +#endif + success = file.remove(); + } else + success = false; + + if (success) + reportSuccess(); + else + reportError(); +} + +void DeleteFileCommand::commandFinished() +{ + debugOutput(0, "DeleteFileCommand::commandFinished()"); +} + +///////////////////////////////////////////////////// +// Delete Directory Command Implementation // +///////////////////////////////////////////////////// +DeleteDirectoryCommand::DeleteDirectoryCommand() + : AbstractCommand() +{ + debugOutput(0, "DeleteDirectoryCommand::DeleteDirectoryCommand()"); +} + +DeleteDirectoryCommand::~DeleteDirectoryCommand() +{ + debugOutput(0, "DeleteDirectoryCommand::~DeleteDirectoryCommand()"); +} + +void DeleteDirectoryCommand::dataReceived(QByteArray &data) +{ + debugOutput(0, "DeleteDirectoryCommand::dataReceived()"); + DeleteDirectoryOptions* options = (DeleteDirectoryOptions*) data.data(); + debugOutput(3, QString::fromLatin1("Delete directory: %1").arg(options->dirName)); + if (deleteDirectory(QLatin1String(options->dirName), options->recursive, options->failIfContentExists)) + reportSuccess(); + else + reportError(); +} + +void DeleteDirectoryCommand::commandFinished() +{ + debugOutput(0, "DeleteDirectoryCommand::commandFinished()"); +} + +bool DeleteDirectoryCommand::deleteDirectory(const QString &dirName, bool recursive, bool failIfContentExists) +{ + QDir dir(dirName); + if (!dir.exists()) + return false; + + QStringList itemList = dir.entryList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot); + if (itemList.size() > 0 && failIfContentExists) + return false; + + foreach (QString item, itemList) { + QString itemName = dir.absoluteFilePath(item); + if (QFileInfo(itemName).isDir()) { + if (recursive && !deleteDirectory(itemName, recursive, failIfContentExists)) + return false; + } else { + if (!dir.remove(item)) + return false; + } + } + QString lastName = dir.dirName(); + dir.cdUp(); + dir.rmpath(lastName); + return true; +} + +///////////////////////////////////////////////////// +// Execute Command Implementation // +///////////////////////////////////////////////////// +ExecuteCommand::ExecuteCommand() + : AbstractCommand() + , m_argumentCount(0) + , m_timeout(-1) +{ + debugOutput(0, "ExecuteCommand::ExecuteCommand()"); +} + +ExecuteCommand::~ExecuteCommand() +{ + debugOutput(0, "ExecuteCommand::~ExecuteCommand()"); +} + +void ExecuteCommand::dataReceived(QByteArray &data) +{ + debugOutput(0, "ExecuteCommand::dataReceived()"); + + if (m_argumentCount == 0) { + ExecuteOptions* options = (ExecuteOptions*) data.data(); + if (!QFileInfo(options->appName).exists()) { + debugOutput(1, "Error execute: application does not exist"); + reportError(); + return; + } + + m_program = QLatin1String(options->appName); + m_argumentCount = options->argumentsCount; + m_waitFinished = options->waitForFinished; + m_timeout = options->timeout; + if (m_argumentCount == 0) + m_argumentCount = -1; // to trigger startup on next receive + reportSuccess(); + } else if (m_arguments.size() < m_argumentCount) { + m_arguments += data; + reportSuccess(); + } else { // do the execution + if (data == COMMAND_SUCCESS) + _doExecute(); + } +} + +void ExecuteCommand::_doExecute() +{ + debugOutput(0, "ExecuteCommand::_doExecute()"); + debugOutput(3, QString::fromLatin1("Execute: %1 %2").arg(m_program).arg(m_arguments.join(" "))); + if (m_waitFinished) { + QProcess process; + process.start(m_program, m_arguments); + if (process.waitForFinished(m_timeout) == false || process.exitCode() < 0) + reportError(); + else + reportSuccess(); + } else { + if (QProcess::startDetached(m_program, m_arguments)) + reportSuccess(); + else + reportError(); + } +} +void ExecuteCommand::commandFinished() +{ + debugOutput(0,"ExecuteCommand::commandFinished()"); +} + +///////////////////////////////////////////////////// +// Read File Implementation // +///////////////////////////////////////////////////// +ReadFileCommand::ReadFileCommand() + : AbstractCommand() + , m_currentPos(0) +{ + debugOutput(0, "ReadFileCommand::ReadFileCommand()"); + m_fileName.clear(); +} + +ReadFileCommand::~ReadFileCommand() +{ + debugOutput(0, "ReadFileCommand::~ReadFileCommand()"); + if (m_file.isOpen()) + m_file.close(); +} + +void ReadFileCommand::dataReceived(QByteArray &data) +{ + debugOutput(0, "ReadFileCommand::dataReceived()"); + if (m_fileName.isEmpty()) { + ReadFileOptions* option = (ReadFileOptions*) data.data(); + m_fileName = QLatin1String(option->fileName); + QFileInfo info(m_fileName); + m_file.setFileName(m_fileName); + ReadFileReply reply; + if (!info.exists() || !info.isFile() || !m_file.open(QIODevice::ReadOnly)) + reply.fileValid = false; + else + reply.fileValid = true; + reply.fileSize = info.size(); + m_fileSize = reply.fileSize; + socket()->write((char*) &reply, sizeof(reply)); + debugOutput(3, QString::fromLatin1("Reading file: %1").arg(m_fileName)); + } else { + QTcpSocket* sock = socket(); // design failure??? + if (data != COMMAND_SUCCESS || m_currentPos >= m_fileSize) { + sock->disconnectFromHost(); + return; + } + const int bufferSize = 1024; + QByteArray buffer = m_file.read(bufferSize); + m_currentPos += buffer.size(); + sock->write(buffer); + sock->waitForBytesWritten(); + } +} + +void ReadFileCommand::commandFinished() +{ + debugOutput(0, "ReadFileCommand::commandFinished()"); +} + +///////////////////////////////////////////////////// +// Read Directory Implementation // +///////////////////////////////////////////////////// +ReadDirectoryCommand::ReadDirectoryCommand() + : AbstractCommand() + , m_iterator(0) +{ + debugOutput(0, "ReadDirectoryCommand::ReadDirectoryCommand"); + m_dirName.clear(); +} + +ReadDirectoryCommand::~ReadDirectoryCommand() +{ + debugOutput(0, "ReadDirectoryCommand::~ReadDirectoryCommand()"); + delete m_iterator; +} + +void ReadDirectoryCommand::dataReceived(QByteArray &data) +{ + debugOutput(0, "ReadDirectoryCommand::dataReceived()"); + QTcpSocket* sock = socket(); + if (m_dirName.isEmpty()) { + ReadDirectoryOptions* option = (ReadDirectoryOptions*) data.data(); + QFileInfo info(QLatin1String(option->dirName)); + debugOutput(3, QString::fromLatin1("Reading Directory entries: %1").arg(option->dirName)); + ReadDirectoryReply reply; + if (!info.exists() || !info.isDir()) { + reply.itemCount = -1; + reply.entryValid = false; + } else { + m_dirName = QLatin1String(option->dirName); + m_dir.setPath(m_dirName); + m_iterator = new QDirIterator(m_dir); + reply.itemCount = m_dir.entryList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot).size(); + reply.entryValid = true; + } + sock->write((char*) &reply, sizeof(reply)); + sock->waitForBytesWritten(); + } else { + if (data != COMMAND_SUCCESS) { + qDebug() << "Something went wrong in the meantime"; + return; + } + ReadDirectoryItem reply; + if (m_iterator->hasNext()) { + m_iterator->next(); + QFileInfo info = m_iterator->fileInfo(); + strcpy(reply.name, qPrintable(info.absoluteFilePath())); + reply.isDirectory = info.isDir(); + if (!reply.isDirectory) + reply.size = info.size(); + } + reply.hasMore = m_iterator->hasNext(); + sock->write((char*) &reply, sizeof(reply)); + sock->waitForBytesWritten(); + } +} + +void ReadDirectoryCommand::commandFinished() +{ + debugOutput(0, "ReadDirectoryCommand::commandFinished()"); +} + +///////////////////////////////////////////////////// +// File Time Implementation // +///////////////////////////////////////////////////// +FileTimeCommand::FileTimeCommand() + : AbstractCommand() +{ + debugOutput(0, "FileTimeCommand::FileTimeCommand()"); +} + +FileTimeCommand::~FileTimeCommand() +{ + debugOutput(0, "FileTimeCommand::~FileTimeCommand()"); +} + +void FileTimeCommand::dataReceived(QByteArray &data) +{ + debugOutput(0, "FileTimeCommand::dataReceived()"); + FileTimeOptions* option = (FileTimeOptions*) data.data(); + + FILETIME resultTime; + resultTime.dwLowDateTime = -1; + resultTime.dwHighDateTime = -1; + +#ifdef Q_OS_WIN + QString fileName = QLatin1String(option->fileName); + HANDLE deviceHandle = CreateFile(fileName.utf16(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0); + debugOutput(3, QString::fromLatin1("Asking FileTime: %1").arg(fileName)); + if (deviceHandle != INVALID_HANDLE_VALUE) { + FILETIME deviceCreationTime; + if (GetFileTime(deviceHandle, &deviceCreationTime, NULL, NULL)) { + resultTime = deviceCreationTime; + } + CloseHandle(deviceHandle); + } +#endif + QTcpSocket* sock = socket(); + sock->write((char*) &resultTime, sizeof(resultTime)); + sock->waitForBytesWritten(); +} + +void FileTimeCommand::commandFinished() +{ + debugOutput(0, "FileTimeCommand::commandFinished()"); +} + +///////////////////////////////////////////////////// +// Time Stamp Implementation // +///////////////////////////////////////////////////// +TimeStampCommand::TimeStampCommand() + : AbstractCommand() +{ + debugOutput(0, "TimeStampCommand::TimeStampCommand()"); +} + +TimeStampCommand::~TimeStampCommand() +{ + debugOutput(0, "TimeStampCommand::~TimeStampCommand()"); +} + +void TimeStampCommand::dataReceived(QByteArray &data) +{ + debugOutput(0, "TimeStampCommand::dataReceived()"); + FILETIME resultTime; + resultTime.dwLowDateTime = -1; + resultTime.dwHighDateTime = -1; + +#ifdef Q_OS_WIN + FILETIME stampTime = *((FILETIME*)data.data()); + + QString tmpFile = QString::fromLatin1("\\qt_tmp_ftime_convert"); + HANDLE remoteHandle = CreateFile(tmpFile.utf16(), GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); + if (remoteHandle != INVALID_HANDLE_VALUE) { + if (!SetFileTime(remoteHandle, &stampTime, NULL, NULL)) { + CloseHandle(remoteHandle); + } else { + CloseHandle(remoteHandle); + remoteHandle = CreateFile(tmpFile.utf16(), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); + if (remoteHandle != INVALID_HANDLE_VALUE) { + if (GetFileTime(remoteHandle, &stampTime, NULL, NULL)) + resultTime = stampTime; + CloseHandle(remoteHandle); + DeleteFile(tmpFile.utf16()); + } + } + } + debugOutput(3, QString::fromLatin1("Asking TimeStamp")); +#endif + QTcpSocket* sock = socket(); + sock->write((char*) &resultTime, sizeof(resultTime)); + sock->waitForBytesWritten(); +} + +void TimeStampCommand::commandFinished() +{ + debugOutput(0, "TimeStampCommand::commandFinished()"); +} diff --git a/tools/qtestlib/wince/cetcpsyncserver/commands.h b/tools/qtestlib/wince/cetcpsyncserver/commands.h new file mode 100644 index 000000000..356c1aa36 --- /dev/null +++ b/tools/qtestlib/wince/cetcpsyncserver/commands.h @@ -0,0 +1,292 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef COMMANDS_INCL +#define COMMANDS_INCL + +#include "transfer_global.h" + +#include +#include +#include +#include +#include +#include + +// debug output +#define DEBUG_LEVEL 2 +inline void debugOutput(int level, const char* text) +{ + if (level >= DEBUG_LEVEL) + qDebug() << text; +} + +inline void debugOutput(int level, const QString &text) +{ + if (level >= DEBUG_LEVEL) + qDebug() << text; +} +// Basic abtract command class +class AbstractCommand : public QObject +{ + Q_OBJECT +public: + AbstractCommand(); + virtual ~AbstractCommand(); + + void setSocket(QTcpSocket*); + QTcpSocket* socket(); + + void reportSuccess(); + void reportError(); + +public slots: + virtual void dataReceived(QByteArray&); + virtual void commandFinished(); + +private slots: + void _readData(); + void _disconnect(); + +private: + QTcpSocket* m_socket; +}; + +// File Creation class +class CreateFileCommand : public AbstractCommand +{ + Q_OBJECT +public: + CreateFileCommand(); + ~CreateFileCommand(); + +public slots: + void dataReceived(QByteArray&); + void commandFinished(); + +private: + CreateFileOptions m_options; + QFile m_file; + int m_dataCount; +}; + +inline AbstractCommand* instCreateFile() { return new CreateFileCommand(); } + +// Directory Creation class +class CreateDirectoryCommand : public AbstractCommand +{ + Q_OBJECT +public: + CreateDirectoryCommand(); + ~CreateDirectoryCommand(); + +public slots: + void dataReceived(QByteArray&); + void commandFinished(); +}; +inline AbstractCommand* instCreateDirectory() { return new CreateDirectoryCommand(); } + +// File copy class +class CopyFileCommand : public AbstractCommand +{ + Q_OBJECT +public: + CopyFileCommand(); + ~CopyFileCommand(); + +public slots: + void dataReceived(QByteArray&); + void commandFinished(); +}; +inline AbstractCommand* instCopyFile() { return new CopyFileCommand(); } + +// Copy directory class +class CopyDirectoryCommand : public AbstractCommand +{ + Q_OBJECT +public: + CopyDirectoryCommand(); + ~CopyDirectoryCommand(); + +public slots: + void dataReceived(QByteArray&); + void commandFinished(); +private: + bool copyDir(const QString &from, const QString &to, bool recursive); +}; +inline AbstractCommand* instCopyDirectory() { return new CopyDirectoryCommand(); } + +// Delete File class +class DeleteFileCommand : public AbstractCommand +{ + Q_OBJECT +public: + DeleteFileCommand(); + ~DeleteFileCommand(); +public slots: + void dataReceived(QByteArray&); + void commandFinished(); +}; +inline AbstractCommand* instDeleteFile() { return new DeleteFileCommand(); } + +// Delete Directory class +class DeleteDirectoryCommand : public AbstractCommand +{ + Q_OBJECT +public: + DeleteDirectoryCommand(); + ~DeleteDirectoryCommand(); +public slots: + void dataReceived(QByteArray&); + void commandFinished(); +private: + bool deleteDirectory(const QString &dirName, bool recursive, bool failIfContentExists); +}; +inline AbstractCommand* instDeleteDirectory() { return new DeleteDirectoryCommand(); } + +// Execute application class +class ExecuteCommand : public AbstractCommand +{ + Q_OBJECT +public: + ExecuteCommand(); + ~ExecuteCommand(); +public slots: + void dataReceived(QByteArray&); + void commandFinished(); +private: + void _doExecute(); + QString m_program; + QStringList m_arguments; + int m_argumentCount; + bool m_waitFinished; + int m_timeout; +}; +inline AbstractCommand* instExecution() { return new ExecuteCommand(); } + +// Read File class +class ReadFileCommand : public AbstractCommand +{ + Q_OBJECT +public: + ReadFileCommand(); + ~ReadFileCommand(); +public slots: + void dataReceived(QByteArray&); + void commandFinished(); +private: + QString m_fileName; + QFile m_file; + qint64 m_currentPos; + qint64 m_fileSize; +}; +inline AbstractCommand* instReadFile() { return new ReadFileCommand(); } + +// Read Directory class +class ReadDirectoryCommand : public AbstractCommand +{ + Q_OBJECT +public: + ReadDirectoryCommand(); + ~ReadDirectoryCommand(); +public slots: + void dataReceived(QByteArray&); + void commandFinished(); +private: + QString m_dirName; + QDir m_dir; + QDirIterator* m_iterator; +}; +inline AbstractCommand* instReadDirectory() { return new ReadDirectoryCommand(); } + +// Read File Time class +class FileTimeCommand : public AbstractCommand +{ + Q_OBJECT +public: + FileTimeCommand(); + ~FileTimeCommand(); +public slots: + void dataReceived(QByteArray&); + void commandFinished(); +}; +inline AbstractCommand* instFileTime() { return new FileTimeCommand(); } + +// Time stamp class +class TimeStampCommand : public AbstractCommand +{ + Q_OBJECT +public: + TimeStampCommand(); + ~TimeStampCommand(); +public slots: + void dataReceived(QByteArray&); + void commandFinished(); +}; +inline AbstractCommand* instTimeStamp() { return new TimeStampCommand(); } + +// Access part +typedef AbstractCommand* (*instantiator)(); + +struct CommandInfo +{ + CommandInfo(const QString &name, instantiator func) : commandName(name) , commandFunc(func) { } + QString commandName; + instantiator commandFunc; +}; + +inline QList availableCommands() +{ + QList list; + list.append(CommandInfo(QLatin1String(COMMAND_CREATE_FILE), instCreateFile)); + list.append(CommandInfo(QLatin1String(COMMAND_CREATE_DIRECTORY), instCreateDirectory)); + list.append(CommandInfo(QLatin1String(COMMAND_COPY_FILE), instCopyFile)); + list.append(CommandInfo(QLatin1String(COMMAND_COPY_DIRECTORY), instCopyDirectory)); + list.append(CommandInfo(QLatin1String(COMMAND_DELETE_FILE), instDeleteFile)); + list.append(CommandInfo(QLatin1String(COMMAND_DELETE_DIRECTORY), instDeleteDirectory)); + list.append(CommandInfo(QLatin1String(COMMAND_EXECUTE), instExecution)); + list.append(CommandInfo(QLatin1String(COMMAND_READ_FILE), instReadFile)); + list.append(CommandInfo(QLatin1String(COMMAND_READ_DIRECTORY), instReadDirectory)); + list.append(CommandInfo(QLatin1String(COMMAND_FILE_TIME), instFileTime)); + list.append(CommandInfo(QLatin1String(COMMAND_TIME_STAMP), instTimeStamp)); + return list; +} + +#endif diff --git a/tools/qtestlib/wince/cetcpsyncserver/connectionmanager.cpp b/tools/qtestlib/wince/cetcpsyncserver/connectionmanager.cpp new file mode 100644 index 000000000..901cd1240 --- /dev/null +++ b/tools/qtestlib/wince/cetcpsyncserver/connectionmanager.cpp @@ -0,0 +1,138 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "connectionmanager.h" +#include "commands.h" +#include + +ConnectionManager::ConnectionManager() + : QObject() + , m_server(0) +{ + debugOutput(0, "ConnectionManager::ConnectionManager()"); +} + +ConnectionManager::~ConnectionManager() +{ + debugOutput(0, "ConnectionManager::~ConnectionManager()"); + cleanUp(); +} + +bool ConnectionManager::init() +{ + debugOutput(0, "ConnectionManager::init()"); + debugOutput(3, "Initializing server..."); + cleanUp(); + m_server = new QTcpServer(this); + connect(m_server, SIGNAL(newConnection()), this, SLOT(newConnection())); + bool result = m_server->listen(QHostAddress::Any, SERVER_PORT); + if (!result) + debugOutput(3, QString::fromLatin1(" Error: Server start failed:") + m_server->errorString()); + debugOutput(3, " Waiting for action"); + return result; +} + +void ConnectionManager::cleanUp() +{ + debugOutput(0, "ConnectionManager::cleanUp()"); + + if (m_server) { + debugOutput(1, "Removing server instance..."); + disconnect(m_server, SIGNAL(newConnection()), this, SLOT(newConnection())); + delete m_server; + m_server = 0; + } +} + +void ConnectionManager::newConnection() +{ + debugOutput(0, "ConnectionManager::newConnection()"); + + QTcpSocket* connection = m_server->nextPendingConnection(); + if (!connection) { + debugOutput(3, "Received connection has empty socket"); + return; + } + debugOutput(0, QString::fromLatin1(" received a connection: %1").arg((int) connection)); + new Connection(connection); +} + +Connection::Connection(QTcpSocket *socket) + : QObject() + , m_connection(socket) + , m_command(0) +{ + connect(m_connection, SIGNAL(readyRead()), this, SLOT(receiveCommand())); + connect(m_connection, SIGNAL(disconnected()), this, SLOT(closedConnection())); +} + +Connection::~Connection() +{ + if (m_command) { + m_command->commandFinished(); + delete m_command; + m_command = 0; + } + delete m_connection; +} + +void Connection::receiveCommand() +{ + QByteArray arr = m_connection->readAll(); + debugOutput(1, QString::fromLatin1("Command received: ") + (arr)); + QList commands = availableCommands(); + for(QList::iterator it = commands.begin(); it != commands.end(); ++it) { + if (it->commandName == QString::fromLatin1(arr)) { + debugOutput(1, "Found command in list"); + disconnect(m_connection, SIGNAL(readyRead()), this, SLOT(receiveCommand())); + AbstractCommand* command = (*it).commandFunc(); + command->setSocket(m_connection); + m_command = command; + return; + } + } + debugOutput(2, QString::fromLatin1("Unknown command received: ") + (arr)); +} + +void Connection::closedConnection() +{ + debugOutput(0, "connection being closed..."); + this->deleteLater(); +} diff --git a/tools/qtestlib/wince/cetcpsyncserver/connectionmanager.h b/tools/qtestlib/wince/cetcpsyncserver/connectionmanager.h new file mode 100644 index 000000000..21183ac71 --- /dev/null +++ b/tools/qtestlib/wince/cetcpsyncserver/connectionmanager.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef CONNECTION_MANAGER_INCL +#define CONNECTION_MANAGER_INCL + +#include "transfer_global.h" +#include "commands.h" + +#include +#include + +class Connection : public QObject +{ + Q_OBJECT +public: + Connection(QTcpSocket* socket); + ~Connection(); + +public slots: + void receiveCommand(); + void closedConnection(); + +private: + QTcpSocket* m_connection; + AbstractCommand* m_command; +}; + +class ConnectionManager : public QObject +{ + Q_OBJECT +public: + ConnectionManager(); + ~ConnectionManager(); + + bool init(); + +public slots: + void cleanUp(); + void newConnection(); + +private: + QTcpServer* m_server; +}; + +#endif diff --git a/tools/qtestlib/wince/cetcpsyncserver/main.cpp b/tools/qtestlib/wince/cetcpsyncserver/main.cpp new file mode 100644 index 000000000..19d38ea80 --- /dev/null +++ b/tools/qtestlib/wince/cetcpsyncserver/main.cpp @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "connectionmanager.h" + +#include +#include + +void messageOutput(QtMsgType type, const char *msg) +{ + switch(type) { + case QtDebugMsg: fprintf(stderr, "Debug: %s\n", msg); break; + case QtWarningMsg: fprintf(stderr, "Warning: %s\n", msg); break; + default: fprintf(stderr, "Some Msg: %s\n", msg); break; + } +} + +int main(int argc, char **argv) +{ + qInstallMsgHandler(messageOutput); + + QCoreApplication app(argc, argv); + ConnectionManager manager; + manager.init(); + return app.exec(); +} diff --git a/tools/qtestlib/wince/cetcpsyncserver/transfer_global.h b/tools/qtestlib/wince/cetcpsyncserver/transfer_global.h new file mode 100644 index 000000000..5b6ff23d3 --- /dev/null +++ b/tools/qtestlib/wince/cetcpsyncserver/transfer_global.h @@ -0,0 +1,159 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef TRANSFER_GLOBAL_H +#define TRANSFER_GLOBAL_H + +#include +#ifdef Q_OS_WIN +#include +#endif + +#define SERVER_PORT 12145 + +#define MAX_NAME_LENGTH 512 +#define MAX_ARGUMENTS 10 + +// Defines for commands sent/received +#define COMMAND_CREATE_FILE "CREATEFILE" +#define COMMAND_CREATE_DIRECTORY "CREATEDIR" +#define COMMAND_COPY_FILE "COPYFILE" +#define COMMAND_COPY_DIRECTORY "COPYDIR" +#define COMMAND_DELETE_FILE "DELETEFILE" +#define COMMAND_DELETE_DIRECTORY "DELETEDIR" +#define COMMAND_EXECUTE "EXECUTE" +#define COMMAND_QUIT_SERVER "QUIT" +#define COMMAND_FILE_TIME "FILETIME" +#define COMMAND_TIME_STAMP "TIMESTAMP" + +// Report back commands +#define COMMAND_SUCCESS "SUCCESS" +#define COMMAND_ERROR "ERROR" + +// Defines for commands that send data back to requester +#define COMMAND_READ_FILE "READFILE" +#define COMMAND_READ_DIRECTORY "READDIR" + +#include +// Option-Structures for commands + +struct CreateFileOptions +{ + char fileName[MAX_NAME_LENGTH]; +#ifdef Q_OS_WIN + FILETIME fileTime; + DWORD fileAttributes; +#endif + int fileSize; + bool overwriteExisting; +}; + +struct CreateDirectoryOptions +{ + char dirName[MAX_NAME_LENGTH]; + bool recursively; // in case of \foo\bar create \foo if it does not exist +}; + +struct CopyFileOptions +{ + char from[MAX_NAME_LENGTH]; + char to[MAX_NAME_LENGTH]; + bool overwriteExisting; +}; + +struct CopyDirectoryOptions +{ + char from[MAX_NAME_LENGTH]; + char to[MAX_NAME_LENGTH]; + bool recursive; +}; + +struct DeleteFileOptions +{ + char fileName[MAX_NAME_LENGTH]; +}; + +struct DeleteDirectoryOptions +{ + char dirName[MAX_NAME_LENGTH]; + bool recursive; + bool failIfContentExists; +}; + +struct ExecuteOptions +{ + char appName[MAX_NAME_LENGTH]; + int argumentsCount; + bool waitForFinished; + int timeout; +}; + +struct ReadFileOptions +{ + char fileName[MAX_NAME_LENGTH]; +}; + +struct ReadFileReply +{ + qint64 fileSize; + bool fileValid; +}; + +struct ReadDirectoryOptions +{ + char dirName[MAX_NAME_LENGTH]; +}; + +struct ReadDirectoryItem +{ + char name[MAX_NAME_LENGTH]; + qint64 size; + bool isDirectory; + bool hasMore; +}; + +#define FileTimeOptions ReadFileOptions + +struct ReadDirectoryReply +{ + bool entryValid; + int itemCount; // might change during iteration +}; +#endif -- cgit v1.2.3 From a34ec3bf9d6077bdc62cb48e116751788996fd99 Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Wed, 5 Aug 2009 11:34:48 +0200 Subject: initial revision of cetcpsync This is the desktop client for communicating with a Windows CE device that runs the cetcpsync server. Reviewed-By: mauricek --- tools/qtestlib/wince/cetcpsync/cetcpsync.pro | 22 + tools/qtestlib/wince/cetcpsync/main.cpp | 191 +++++++ .../wince/cetcpsync/qtcesterconnection.cpp | 551 +++++++++++++++++++++ .../qtestlib/wince/cetcpsync/qtcesterconnection.h | 86 ++++ .../qtestlib/wince/cetcpsync/remoteconnection.cpp | 65 +++ tools/qtestlib/wince/cetcpsync/remoteconnection.h | 81 +++ 6 files changed, 996 insertions(+) create mode 100644 tools/qtestlib/wince/cetcpsync/cetcpsync.pro create mode 100644 tools/qtestlib/wince/cetcpsync/main.cpp create mode 100644 tools/qtestlib/wince/cetcpsync/qtcesterconnection.cpp create mode 100644 tools/qtestlib/wince/cetcpsync/qtcesterconnection.h create mode 100644 tools/qtestlib/wince/cetcpsync/remoteconnection.cpp create mode 100644 tools/qtestlib/wince/cetcpsync/remoteconnection.h diff --git a/tools/qtestlib/wince/cetcpsync/cetcpsync.pro b/tools/qtestlib/wince/cetcpsync/cetcpsync.pro new file mode 100644 index 000000000..d1d7c999a --- /dev/null +++ b/tools/qtestlib/wince/cetcpsync/cetcpsync.pro @@ -0,0 +1,22 @@ +TARGET = cetcpsync +DESTDIR = ../../../../bin +CONFIG += console +CONFIG -= app_bundle +QT += network +QT -= gui +TEMPLATE = app + +build_all:!build_pass { + CONFIG -= build_all + CONFIG += release +} + +INCLUDEPATH += ../cetcpsyncserver + +SOURCES += main.cpp \ + remoteconnection.cpp \ + qtcesterconnection.cpp + +HEADERS += \ + remoteconnection.h \ + qtcesterconnection.h diff --git a/tools/qtestlib/wince/cetcpsync/main.cpp b/tools/qtestlib/wince/cetcpsync/main.cpp new file mode 100644 index 000000000..73c7350de --- /dev/null +++ b/tools/qtestlib/wince/cetcpsync/main.cpp @@ -0,0 +1,191 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include +#include "qtcesterconnection.h" + +using namespace std; + +static void showUsage() +{ + cout << "cetcpsync is meant to be used by cetest internally." << endl + << "For usage instructions remoteconnection.h could be useful." << endl; +} + +const int debugLevel = 0; +void debugOutput(const QString& text, int level) +{ + if (level <= debugLevel) + cout << qPrintable(text) << endl; +} + +class Exception +{ +public: + Exception(const QString& msg = QString()) + : m_message(msg) + {} + + QString message() { return m_message; } + +protected: + QString m_message; +}; + +class TooFewParametersException : public Exception +{ +public: + TooFewParametersException(const QLatin1String& cmd, int expectedParameterCount) + { + m_message = QLatin1String("Command ") + cmd + QLatin1String(" needs at least "); + m_message.append(QString::number(expectedParameterCount)); + m_message.append(QLatin1String(" parameters.")); + } +}; + +static void fileTimeFromString(FILETIME& ft, const QString& str) +{ + int idx = str.indexOf("*"); + if (idx <= 0) + return; + ft.dwLowDateTime = str.left(idx).toULong(); + ft.dwHighDateTime = str.mid(idx+1).toULong(); +} + +static QString fileTimeToString(FILETIME& ft) +{ + return QString::number(ft.dwLowDateTime) + "*" + QString::number(ft.dwHighDateTime); +} + +static int execCommand(const QLatin1String& cmd, int argc, char* argv[]) +{ + int retval = 0; + bool success = true; + QtCesterConnection connection; + if (cmd == "copyFileToDevice") { + if (argc < 3) + throw TooFewParametersException(cmd, 3); + success = connection.copyFileToDevice(argv[0], argv[1], argv[2] == "true"); + } else if (cmd == "copyDirectoryToDevice") { + if (argc < 3) + throw TooFewParametersException(cmd, 3); + success = connection.copyDirectoryToDevice(argv[0], argv[1], argv[2] == "true"); + } else if (cmd == "copyFileFromDevice") { + if (argc < 3) + throw TooFewParametersException(cmd, 3); + success = connection.copyFileFromDevice(argv[0], argv[1], argv[2] == "true"); + } else if (cmd == "copyDirectoryFromDevice") { + if (argc < 3) + throw TooFewParametersException(cmd, 3); + success = connection.copyDirectoryFromDevice(argv[0], argv[1], argv[2] == "true"); + } else if (cmd == "timeStampForLocalFileTime") { + if (argc < 1) + throw TooFewParametersException(cmd, 1); + FILETIME ft; + fileTimeFromString(ft, argv[0]); + success = connection.timeStampForLocalFileTime(&ft); + if (success) + cout << qPrintable(fileTimeToString(ft)); + } else if (cmd == "fileCreationTime") { + if (argc < 1) + throw TooFewParametersException(cmd, 1); + FILETIME ft; + success = connection.fileCreationTime(argv[0], &ft); + if (success) + cout << qPrintable(fileTimeToString(ft)); + } else if (cmd == "copyFile") { + if (argc < 3) + throw TooFewParametersException(cmd, 3); + success = connection.copyFile(argv[0], argv[1], argv[2] == "true"); + } else if (cmd == "copyDirectory") { + if (argc < 3) + throw TooFewParametersException(cmd, 3); + success = connection.copyDirectory(argv[0], argv[1], argv[2] == "true"); + } else if (cmd == "deleteFile") { + if (argc < 1) + throw TooFewParametersException(cmd, 1); + success = connection.deleteFile(argv[0]); + } else if (cmd == "deleteDirectory") { + if (argc < 3) + throw TooFewParametersException(cmd, 3); + success = connection.deleteDirectory(argv[0], argv[1] == "true", argv[2] == "true"); + } else if (cmd == "moveFile") { + if (argc < 3) + throw TooFewParametersException(cmd, 3); + success = connection.moveFile(argv[0], argv[1], argv[2] == "true"); + } else if (cmd == "moveDirectory") { + if (argc < 3) + throw TooFewParametersException(cmd, 3); + success = connection.moveDirectory(argv[0], argv[1], argv[2] == "true"); + } else if (cmd == "createDirectory") { + if (argc < 2) + throw TooFewParametersException(cmd, 2); + success = connection.createDirectory(argv[0], argv[1] == "true"); + } else if (cmd == "execute") { + if (argc < 3) + throw TooFewParametersException(cmd, 3); + int timeout = QString(argv[2]).toInt(); + success = connection.execute(argv[0], argv[1], timeout, &retval); + } else if (cmd == "noop") { + // do nothing :) + success = true; + } else { + throw Exception("unknown command"); + } + + return success ? retval : 1; +} + +int main(int argc, char *argv[]) +{ + if (argc <= 1) { + showUsage(); + return 0; + } + + QLatin1String param(argv[1]); + int result = 1; + try { + result = execCommand(param, argc - 2, argv + 2); + } catch (Exception e) { + cerr << "Error: " << qPrintable(e.message()); + } + return result; +} diff --git a/tools/qtestlib/wince/cetcpsync/qtcesterconnection.cpp b/tools/qtestlib/wince/cetcpsync/qtcesterconnection.cpp new file mode 100644 index 000000000..4a8ae2b69 --- /dev/null +++ b/tools/qtestlib/wince/cetcpsync/qtcesterconnection.cpp @@ -0,0 +1,551 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "qtcesterconnection.h" +#include +#include +#include +#include +#include +#include + +extern void debugOutput(const QString& text, int level); + +#pragma warning(disable:4996) + +#define END_ERROR(s, a) \ + if(a) qDebug() << a; \ + _freeSocket(s); \ + return false; + +QtCesterConnection::QtCesterConnection() + : AbstractRemoteConnection() +{ +} + +QtCesterConnection::~QtCesterConnection() +{ +} + +bool QtCesterConnection::connect(QVariantList&) +{ + // We connect with each command, so this is always true + // The command itself will fail then + connected = true; + return true; +} + +void QtCesterConnection::disconnect() +{ + connected = false; +} + +bool QtCesterConnection::isConnected() const +{ + return connected; +} + +bool QtCesterConnection::copyFileToDevice(const QString &localSource, const QString &deviceDest, bool failIfExists) +{ + debugOutput( qPrintable(QString::fromLatin1("Copy File: %1 -> %2").arg(localSource).arg(deviceDest)),0); + QFile localFile(localSource); + QFileInfo info(localSource); + if (!localFile.exists() || !localFile.open(QIODevice::ReadOnly)) { + qDebug() << "Could not open File!"; + return false; + } + + QTcpSocket* socket = 0; + if (!_initCommand(socket, COMMAND_CREATE_FILE)) { + END_ERROR(socket, "Could not initialized command"); + } + + CreateFileOptions option; + strcpy(option.fileName, qPrintable(deviceDest)); +#ifdef Q_OS_WIN + // Copy FileTime for update verification + FILETIME creationTime, accessTime, writeTime; + HANDLE localHandle = CreateFile(localSource.utf16(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0); + if (localHandle != INVALID_HANDLE_VALUE) { + if (GetFileTime(localHandle, &creationTime, &accessTime, &writeTime)) { + LocalFileTimeToFileTime(&writeTime, &writeTime); + option.fileTime = writeTime; + } + CloseHandle(localHandle); + } + DWORD attributes = GetFileAttributes(localSource.utf16()); + if (attributes != -1 ) + option.fileAttributes = attributes; +#endif + option.fileSize = info.size(); + option.overwriteExisting = !failIfExists; + + if (!_sendData(socket, (char*) &option, sizeof(option))) { + END_ERROR(socket, "Could not send options..."); + } + + if (!_checkResult(socket)) { + END_ERROR(socket, "Server did not accept configuration"); + } + + int bytesWritten = 0; + const int bufferSize = 1024; + QByteArray data; + while (bytesWritten < option.fileSize) { + data = localFile.read(bufferSize); + bytesWritten += data.size(); +#ifdef Q_OS_WIN + wprintf( L"%s -> %s (%d / %d) %d %%\r", localSource.utf16() , deviceDest.utf16(), + bytesWritten , option.fileSize, (100*bytesWritten)/option.fileSize ); +#endif + if (!_sendData(socket, data.constData(), data.size())) { + END_ERROR(socket, "Error during file transfer"); + } + if (!_checkResult(socket)) { + END_ERROR(socket, "Got some strange result"); + } + } +#ifdef Q_OS_WIN + wprintf( L"\n"); // We should jump to next line... +#endif + if (bytesWritten != option.fileSize) { + END_ERROR(socket, "Did not send sufficient data"); + } + _freeSocket(socket); + return true; +} + +bool QtCesterConnection::copyDirectoryToDevice(const QString &localSource, const QString &deviceDest, bool recursive) +{ + QTcpSocket* socket = NULL; + QFileInfo info(localSource); + if (!info.exists() || !info.isDir()) { + END_ERROR(socket, "Input directory invalid"); + } + + createDirectory(deviceDest, true); + QDir dir(localSource); + QFileInfoList list = dir.entryInfoList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot); + foreach(QFileInfo item, list) { + QString targetName = deviceDest + QLatin1String("\\") + item.fileName(); + if (item.isDir()) { + if (recursive) { + if (!copyDirectoryToDevice(item.absoluteFilePath() , targetName, recursive)) + return false; + } + } else { + if (!copyFileToDevice(item.absoluteFilePath(), targetName)) + return false; + } + } + return true; +} + +bool QtCesterConnection::copyFileFromDevice(const QString &deviceSource, const QString &localDest, bool failIfExists) +{ + QFile targetFile(localDest); + QTcpSocket* socket = 0; + if (targetFile.exists() && failIfExists) { + END_ERROR(socket, "Local file not supposed to be overwritten"); + } + + if (!targetFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) { + END_ERROR(socket, "Could not open local file for writing"); + } + + if (!_initCommand(socket, COMMAND_READ_FILE)) { + END_ERROR(socket, "Could not establish connection"); + } + + ReadFileOptions option; + strcpy(option.fileName, qPrintable(deviceSource)); + if (!_sendData(socket, (char*) &option, sizeof(option))) { + END_ERROR(socket, "Could not send options"); + } + + QByteArray data; + if (!_receiveData(socket, data)) { + END_ERROR(socket, "Did not receive any data"); + } + + ReadFileReply* reply = (ReadFileReply*) data.data(); + if (!reply->fileValid) { + END_ERROR(socket, "Requested file invalid"); + } + + int fileSize = reply->fileSize; + int currentSize = 0; + // ### TODO: make a little bit more error-prone + do { + _sendData(socket, COMMAND_SUCCESS, strlen(COMMAND_SUCCESS)); + _receiveData(socket, data); + currentSize += data.size(); + targetFile.write(data); + } while(currentSize < fileSize); + + _freeSocket(socket); + targetFile.close(); + return true; +} + +bool QtCesterConnection::copyDirectoryFromDevice(const QString& /*deviceSource*/ + , const QString& /*localDest*/ + , bool /*recursive*/) +{ + qDebug() << "To be implemented!! Should not be needed for autotest system"; + exit(-1); + return false; +} + +bool QtCesterConnection::copyFile(const QString &srcFile, const QString &destFile, bool failIfExists) +{ + QTcpSocket* socket = 0; + if (!_initCommand(socket, COMMAND_COPY_FILE)) { + END_ERROR(socket, "Could not establish connection for copy"); + } + + CopyFileOptions option; + strcpy(option.from, qPrintable(srcFile)); + strcpy(option.to, qPrintable(destFile)); + option.overwriteExisting = !failIfExists; + if (!_sendData(socket, (char*) &option, sizeof(option))) { + END_ERROR(socket, "Could not send copy options"); + } + + if (!_checkResult(socket)) { + END_ERROR(socket, "Copy failed"); + } + + _freeSocket(socket); + return true; +} + +bool QtCesterConnection::copyDirectory(const QString &srcDirectory, const QString &destDirectory, + bool recursive) +{ + QTcpSocket* socket = 0; + if (!_initCommand(socket, COMMAND_COPY_DIRECTORY)) { + END_ERROR(socket, "Could not establish connection for dir copy"); + } + + CopyDirectoryOptions option; + strcpy(option.from, qPrintable(srcDirectory)); + strcpy(option.to, qPrintable(destDirectory)); + option.recursive = recursive; + if (!_sendData(socket, (char*) &option, sizeof(option))) { + END_ERROR(socket, "Could not send dir copy options"); + } + + if (!_checkResult(socket)) { + END_ERROR(socket, "Dir Copy failed"); + } + + _freeSocket(socket); + return true; +} + +bool QtCesterConnection::deleteFile(const QString &fileName) +{ + QTcpSocket* socket = 0; + if (!_initCommand(socket, COMMAND_DELETE_FILE)) { + END_ERROR(socket, "Could not establish connection for file deletion"); + } + + DeleteFileOptions option; + strcpy(option.fileName, qPrintable(fileName)); + if (!_sendData(socket, (char*) &option, sizeof(option))) { + END_ERROR(socket, "Could not send file options"); + } + + if (!_checkResult(socket)) { + END_ERROR(socket, "File Deletion failed"); + } + + _freeSocket(socket); + return true; +} + +bool QtCesterConnection::deleteDirectory(const QString &directory, bool recursive, bool failIfContentExists) +{ + QTcpSocket* socket = 0; + if (!_initCommand(socket, COMMAND_DELETE_DIRECTORY)) { + END_ERROR(socket, "Could not establish connection for dir deletion"); + } + + DeleteDirectoryOptions option; + strcpy(option.dirName, qPrintable(directory)); + option.recursive = recursive; + option.failIfContentExists = failIfContentExists; + if (!_sendData(socket, (char*) &option, sizeof(option))) { + END_ERROR(socket, "Could not send dir options"); + } + + if (!_checkResult(socket)) { + // we do not write an error as this will fail a lot on recursive. + END_ERROR(socket, 0); + } + + _freeSocket(socket); + return true; +} + +bool QtCesterConnection::execute(QString program, + QString arguments, + int timeout, + int *returnValue) +{ + QTcpSocket* socket = 0; + if (!_initCommand(socket, COMMAND_EXECUTE)) { + END_ERROR(socket, "Could not establish connection for dir deletion"); + } + + ExecuteOptions options; + strcpy(options.appName, qPrintable(program)); + QStringList argList = arguments.split(QLatin1Char(' ')); + options.argumentsCount = qMin(argList.size(), MAX_ARGUMENTS); + options.waitForFinished = true; + options.timeout = timeout; + if (!_sendData(socket, (char*) &options, sizeof(options))) { + END_ERROR(socket, "Could not send dir options"); + } + if (!_checkResult(socket)) { + END_ERROR(socket, "Did not receive an answer"); + } + + for (int i=0; i < options.argumentsCount; ++i) { + char someData[MAX_NAME_LENGTH]; + strcpy(someData, qPrintable(argList[i])); + if (!_sendData(socket, someData, MAX_NAME_LENGTH)) { + END_ERROR(socket, "Could not send argument"); + } + if (!_checkResult(socket)) { + END_ERROR(socket, "Failure in argument send"); + } + } + + // trigger the startup + if (!_sendData(socket, COMMAND_SUCCESS, strlen(COMMAND_SUCCESS))) { + END_ERROR(socket, "Could not trigger startup"); + } + + const int waitTime = 60 * 60 * 1000; + if (!socket->waitForReadyRead(waitTime)) { + END_ERROR(socket, "Process timed out"); + } + + QByteArray result = socket->readAll(); + if (result != COMMAND_SUCCESS) { + if (returnValue) + *returnValue = -1; // just some at least + END_ERROR(socket, "Application did not start or returned error"); + } + + if (returnValue) + *returnValue = 0; + _freeSocket(socket); + return true; +} + +bool QtCesterConnection::createDirectory(const QString &path, bool deleteBefore) +{ + if (deleteBefore) + deleteDirectory(path, true, true); + + QTcpSocket* socket = 0; + if (!_initCommand(socket, COMMAND_CREATE_DIRECTORY)) { + END_ERROR(socket, "Could not establish connection for dir creation"); + } + + CreateDirectoryOptions option; + strcpy(option.dirName, qPrintable(path)); + option.recursively = true; + if (!_sendData(socket, (char*) &option, sizeof(option))) { + END_ERROR(socket, "Could not send dir options"); + } + + if (!_checkResult(socket)) { + END_ERROR(socket, "Dir creation failed"); + } + + _freeSocket(socket); + return true; +} + +bool QtCesterConnection::timeStampForLocalFileTime(FILETIME* fTime) const +{ + if (!fTime) + return false; + + FILETIME copyTime = *fTime; + LocalFileTimeToFileTime(©Time, ©Time); + + QTcpSocket* socket = 0; + if (!_initCommand(socket, COMMAND_TIME_STAMP)) { + END_ERROR(socket, "Could not establish time stamp connection"); + } + + if (!_sendData(socket, (char*) ©Time, sizeof(copyTime))) { + END_ERROR(socket, "Could not send stamp time"); + } + + QByteArray data; + if (!_receiveData(socket, data)) { + END_ERROR(socket, "Did not receive time stamp or connection interrupted"); + } + + copyTime = *((FILETIME*)data.data()); + if (copyTime.dwLowDateTime == -1 && copyTime.dwHighDateTime == -1) { + END_ERROR(socket, "remote Time stamp failed!"); + } + + *fTime = copyTime; + _freeSocket(socket); + return true; +} + +bool QtCesterConnection::fileCreationTime(const QString &fileName, FILETIME* deviceCreationTime) const +{ + if (!deviceCreationTime) + return false; + + QTcpSocket* socket = 0; + if (!_initCommand(socket, COMMAND_FILE_TIME)) { + END_ERROR(socket, "Could not establish connection for file time access"); + } + + FileTimeOptions option; + strcpy(option.fileName, qPrintable(fileName)); + if (!_sendData(socket, (char*) &option, sizeof(option))) { + END_ERROR(socket, "Could not send file time name"); + } + + QByteArray data; + if (!_receiveData(socket, data)) { + END_ERROR(socket, "File Time request failed"); + } + + FILETIME* resultTime = (FILETIME*) data.data(); + if (resultTime->dwLowDateTime == -1 && resultTime->dwHighDateTime == -1) { + END_ERROR(socket, 0); + debugOutput("Could not access file time", 0); + } + + *deviceCreationTime = *resultTime; + _freeSocket(socket); + return true; +} + +bool QtCesterConnection::_createSocket(QTcpSocket*& result) const +{ + QTcpSocket* sock = new QTcpSocket(); + QByteArray ipAddress = qgetenv("DEVICE_IP"); + if (ipAddress.isEmpty()) { + qWarning("Error: You need to have DEVICE_IP set"); + exit(0); + } + sock->connectToHost(QHostAddress(QString(ipAddress)), 12145); + + if (!sock->waitForConnected()) { + qDebug() << "connection timeout..."; + result = NULL; + return false; + } + result = sock; + return true; +} + +void QtCesterConnection::_freeSocket(QTcpSocket*& sock) const +{ + if (!sock) + return; + if (sock->state() == QAbstractSocket::ConnectedState) { + sock->disconnectFromHost(); + // seems like no need to wait + //sock->waitForDisconnected(); + } + delete sock; + sock = NULL; +#ifdef Q_OS_WIN + Sleep(100); +#endif +} + +bool QtCesterConnection::_initCommand(QTcpSocket*& sock, const char* command) const +{ + QTcpSocket* socket = NULL; + if (!_createSocket(socket)) { + END_ERROR(socket, "Could not connect to server"); + } + + if (!_sendData(socket, command, strlen(command)) || + !_checkResult(socket)) { + END_ERROR(socket, "Cound not send command"); + } + sock = socket; + return true; +} + +bool QtCesterConnection::_sendData(QTcpSocket*& sock, const char* data, int dataSize) const +{ + int amount = sock->write(data, dataSize); + if (amount != dataSize) { + fprintf(stderr, "*******COULD NOT SEND ENOUGH DATA*************\n"); + } + return sock->waitForBytesWritten(); +} + +bool QtCesterConnection::_receiveData(QTcpSocket*& sock, QByteArray& data) const +{ + if (!sock->waitForReadyRead()) { + qDebug() << "did not receive any data"; + return false; + } + data = sock->readAll(); + return true; +} + +bool QtCesterConnection::_checkResult(QTcpSocket*& sock) const +{ + QByteArray response; + if (!_receiveData(sock, response) || response != COMMAND_SUCCESS) + return false; + return true; +} + diff --git a/tools/qtestlib/wince/cetcpsync/qtcesterconnection.h b/tools/qtestlib/wince/cetcpsync/qtcesterconnection.h new file mode 100644 index 000000000..d7b8393eb --- /dev/null +++ b/tools/qtestlib/wince/cetcpsync/qtcesterconnection.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef ACTIVESYNC_REMOTECONNECTION_H +#define ACTIVESYNC_REMOTECONNECTION_H + +#include "remoteconnection.h" + +class QTcpSocket; + +class QtCesterConnection : public AbstractRemoteConnection +{ +public: + QtCesterConnection(); + virtual ~QtCesterConnection(); + + bool connect(QVariantList &list = QVariantList()); + void disconnect(); + bool isConnected() const; + + // These functions are designed for transfer between desktop and device + // Caution: deviceDest path has to be device specific (eg. no drive letters for CE) + bool copyFileToDevice(const QString &localSource, const QString &deviceDest, bool failIfExists = false); + bool copyDirectoryToDevice(const QString &localSource, const QString &deviceDest, bool recursive = true); + bool copyFileFromDevice(const QString &deviceSource, const QString &localDest, bool failIfExists = false); + bool copyDirectoryFromDevice(const QString &deviceSource, const QString &localDest, bool recursive = true); + + bool timeStampForLocalFileTime(FILETIME*) const; + bool fileCreationTime(const QString &fileName, FILETIME*) const; + + // These functions only work on files existing on the device + bool copyFile(const QString&, const QString&, bool failIfExists = false); + bool copyDirectory(const QString&, const QString&, bool recursive = true); + bool deleteFile(const QString&); + bool deleteDirectory(const QString&, bool recursive = true, bool failIfContentExists = false); + bool createDirectory(const QString&, bool deleteBefore=false); + + bool execute(QString program, QString arguments = QString(), int timeout = -1, int *returnValue = NULL); +private: + bool _createSocket(QTcpSocket*&) const; + void _freeSocket(QTcpSocket*&) const; + bool _initCommand(QTcpSocket*&, const char*) const; + bool _sendData(QTcpSocket*&, const char* data, int dataSize) const; + bool _receiveData(QTcpSocket*&, QByteArray&) const; + bool _checkResult(QTcpSocket*&) const; + bool connected; +}; + +#endif diff --git a/tools/qtestlib/wince/cetcpsync/remoteconnection.cpp b/tools/qtestlib/wince/cetcpsync/remoteconnection.cpp new file mode 100644 index 000000000..b197c5c66 --- /dev/null +++ b/tools/qtestlib/wince/cetcpsync/remoteconnection.cpp @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "remoteconnection.h" + +AbstractRemoteConnection::AbstractRemoteConnection() +{ +} + +AbstractRemoteConnection::~AbstractRemoteConnection() +{ +} + +// Slow but should be ok... +bool AbstractRemoteConnection::moveFile(const QString &src, const QString &dest, bool FailIfExists) +{ + bool result = copyFile(src, dest, FailIfExists); + deleteFile(src); + return result; +} + +// Slow but should be ok... +bool AbstractRemoteConnection::moveDirectory(const QString &src, const QString &dest, bool recursive) +{ + bool result = copyDirectory(src, dest, true); + deleteDirectory(src, recursive); + return result; +} diff --git a/tools/qtestlib/wince/cetcpsync/remoteconnection.h b/tools/qtestlib/wince/cetcpsync/remoteconnection.h new file mode 100644 index 000000000..fae6f7f75 --- /dev/null +++ b/tools/qtestlib/wince/cetcpsync/remoteconnection.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef REMOTECONNECTION_H +#define REMOTECONNECTION_H + +#include +#include +#include +class AbstractRemoteConnection +{ +public: + AbstractRemoteConnection(); + virtual ~AbstractRemoteConnection(); + + virtual bool connect(QVariantList&) = 0; + virtual void disconnect() = 0; + virtual bool isConnected() const = 0; + + // These functions are designed for transfer between desktop and device + // Caution: deviceDest path has to be device specific (eg. no drive letters for CE) + virtual bool copyFileToDevice(const QString &localSource, const QString &deviceDest, bool failIfExists = false) = 0; + virtual bool copyDirectoryToDevice(const QString &localSource, const QString &deviceDest, bool recursive = true) = 0; + virtual bool copyFileFromDevice(const QString &deviceSource, const QString &localDest, bool failIfExists = false) = 0; + virtual bool copyDirectoryFromDevice(const QString &deviceSource, const QString &localDest, bool recursive = true) = 0; + + // For "intelligent deployment" we need to investigate on filetimes on the device + virtual bool timeStampForLocalFileTime(FILETIME*) const = 0; + virtual bool fileCreationTime(const QString &fileName, FILETIME*) const = 0; + + // These functions only work on files existing on the device + virtual bool copyFile(const QString&, const QString&, bool failIfExists = false) = 0; + virtual bool copyDirectory(const QString&, const QString&, bool recursive = true) = 0; + virtual bool deleteFile(const QString&) = 0; + virtual bool deleteDirectory(const QString&, bool recursive = true, bool failIfContentExists = false) = 0; + bool moveFile(const QString&, const QString&, bool FailIfExists = false); + bool moveDirectory(const QString&, const QString&, bool recursive = true); + + virtual bool createDirectory(const QString&, bool deleteBefore=false) = 0; + + virtual bool execute(QString program, QString arguments = QString(), int timeout = -1, int *returnValue = NULL) = 0; +}; + +#endif -- cgit v1.2.3 From f78bd88cbb8fd4c32e487eed716f089b6f5cfe28 Mon Sep 17 00:00:00 2001 From: Volker Hilsheimer Date: Wed, 5 Aug 2009 12:58:39 +0200 Subject: Workaround a crash in qdoc. Caused by an odd number of classes it seems. --- tools/qdoc3/htmlgenerator.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/qdoc3/htmlgenerator.cpp b/tools/qdoc3/htmlgenerator.cpp index 6b15f96c7..df6313827 100644 --- a/tools/qdoc3/htmlgenerator.cpp +++ b/tools/qdoc3/htmlgenerator.cpp @@ -2097,6 +2097,11 @@ void HtmlGenerator::generateCompactList(const Node *relative, currentOffsetInParagraph[i] = 0; } + if (currentParagraphNo[i] >= NumParagraphs) { + qDebug() << "### Internal error ###" << __FILE__ << __LINE__; + currentParagraphNo[i] = NumParagraphs - 1; + } + out() << ""; if (currentOffsetInParagraph[i] == 0) { // start a new paragraph -- cgit v1.2.3 From 0002516329cbbf5fb0b677835353bf7ccd4e425f Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Wed, 5 Aug 2009 13:01:02 +0200 Subject: missing license header added in cetcpsyncsvr Reviewed-by: TrustMe --- tools/qtestlib/wince/cetcpsyncserver/commands.cpp | 40 +++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/tools/qtestlib/wince/cetcpsyncserver/commands.cpp b/tools/qtestlib/wince/cetcpsyncserver/commands.cpp index 64869c450..0c4d3bc03 100644 --- a/tools/qtestlib/wince/cetcpsyncserver/commands.cpp +++ b/tools/qtestlib/wince/cetcpsyncserver/commands.cpp @@ -1,3 +1,43 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ #include "commands.h" #include #include -- cgit v1.2.3 From 770ce0a8cd7493e3be3e7accf7133778336c6f5d Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Wed, 5 Aug 2009 13:02:18 +0200 Subject: small cleanup in cetest Reviewed-by: TrustMe --- .../qtestlib/wince/cetest/cetcpsyncconnection.cpp | 31 +++++++++++----------- tools/qtestlib/wince/cetest/cetest.pro | 4 +-- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/tools/qtestlib/wince/cetest/cetcpsyncconnection.cpp b/tools/qtestlib/wince/cetest/cetcpsyncconnection.cpp index bebcd1cf1..f00d2b8ce 100644 --- a/tools/qtestlib/wince/cetest/cetcpsyncconnection.cpp +++ b/tools/qtestlib/wince/cetest/cetcpsyncconnection.cpp @@ -44,6 +44,7 @@ #include #include +static const QString ceTcpSyncProgram = ceTcpSyncProgram + ""; extern void debugOutput(const QString& text, int level); CeTcpSyncConnection::CeTcpSyncConnection() @@ -62,7 +63,7 @@ bool CeTcpSyncConnection::connect(QVariantList&) { // We connect with each command, so this is always true // The command itself will fail then - if (system("cetcpsync noop") != 0) + if (system(ceTcpSyncProgram + " noop") != 0) return false; connected = true; return true; @@ -103,56 +104,56 @@ static QString fileTimeToString(FILETIME& ft) bool CeTcpSyncConnection::copyFileToDevice(const QString &localSource, const QString &deviceDest, bool failIfExists) { - QString cmd = "cetcpsync copyFileToDevice \"" + localSource + "\" \"" + deviceDest + "\" " + boolToString(failIfExists); + QString cmd = ceTcpSyncProgram + " copyFileToDevice \"" + localSource + "\" \"" + deviceDest + "\" " + boolToString(failIfExists); return system(qPrintable(cmd)) == 0; } bool CeTcpSyncConnection::copyDirectoryToDevice(const QString &localSource, const QString &deviceDest, bool recursive) { - QString cmd = "cetcpsync copyDirectoryToDevice \"" + localSource + "\" \"" + deviceDest + "\" " + boolToString(recursive); + QString cmd = ceTcpSyncProgram + " copyDirectoryToDevice \"" + localSource + "\" \"" + deviceDest + "\" " + boolToString(recursive); return system(qPrintable(cmd)) == 0; } bool CeTcpSyncConnection::copyFileFromDevice(const QString &deviceSource, const QString &localDest, bool failIfExists) { - QString cmd = "cetcpsync copyFileFromDevice \"" + deviceSource + "\" \"" + localDest + "\" " + boolToString(failIfExists); + QString cmd = ceTcpSyncProgram + " copyFileFromDevice \"" + deviceSource + "\" \"" + localDest + "\" " + boolToString(failIfExists); return system(qPrintable(cmd)) == 0; } bool CeTcpSyncConnection::copyDirectoryFromDevice(const QString &deviceSource, const QString &localDest, bool recursive) { - QString cmd = "cetcpsync copyDirectoryFromDevice \"" + deviceSource + "\" \"" + localDest + "\" " + boolToString(recursive); + QString cmd = ceTcpSyncProgram + " copyDirectoryFromDevice \"" + deviceSource + "\" \"" + localDest + "\" " + boolToString(recursive); return system(qPrintable(cmd)) == 0; } bool CeTcpSyncConnection::copyFile(const QString &srcFile, const QString &destFile, bool failIfExists) { - QString cmd = "cetcpsync copyFile \"" + srcFile + "\" \"" + destFile + "\" " + boolToString(failIfExists); + QString cmd = ceTcpSyncProgram + " copyFile \"" + srcFile + "\" \"" + destFile + "\" " + boolToString(failIfExists); return system(qPrintable(cmd)) == 0; } bool CeTcpSyncConnection::copyDirectory(const QString &srcDirectory, const QString &destDirectory, bool recursive) { - QString cmd = "cetcpsync copyDirectory \"" + srcDirectory + "\" \"" + destDirectory + "\" " + boolToString(recursive); + QString cmd = ceTcpSyncProgram + " copyDirectory \"" + srcDirectory + "\" \"" + destDirectory + "\" " + boolToString(recursive); return system(qPrintable(cmd)) == 0; } bool CeTcpSyncConnection::deleteFile(const QString &fileName) { - QString cmd = "cetcpsync deleteFile \"" + fileName + "\""; + QString cmd = ceTcpSyncProgram + " deleteFile \"" + fileName + "\""; return system(qPrintable(cmd)) == 0; } bool CeTcpSyncConnection::deleteDirectory(const QString &directory, bool recursive, bool failIfContentExists) { - QString cmd = "cetcpsync deleteDirectory \"" + directory + "\" " + boolToString(recursive) + " " + boolToString(failIfContentExists); + QString cmd = ceTcpSyncProgram + " deleteDirectory \"" + directory + "\" " + boolToString(recursive) + " " + boolToString(failIfContentExists); return system(qPrintable(cmd)) == 0; } bool CeTcpSyncConnection::execute(QString program, QString arguments, int timeout, int *returnValue) { - QString cmd = "cetcpsync execute \"" + program + "\" \"" + arguments + "\" " + QString::number(timeout); + QString cmd = ceTcpSyncProgram + " execute \"" + program + "\" \"" + arguments + "\" " + QString::number(timeout); int exitCode = system(qPrintable(cmd)); if (returnValue) *returnValue = exitCode; @@ -161,17 +162,17 @@ bool CeTcpSyncConnection::execute(QString program, QString arguments, int timeou bool CeTcpSyncConnection::createDirectory(const QString &path, bool deleteBefore) { - QString cmd = "cetcpsync createDirectory \"" + path + "\" " + boolToString(deleteBefore); + QString cmd = ceTcpSyncProgram + " createDirectory \"" + path + "\" " + boolToString(deleteBefore); return system(qPrintable(cmd)) == 0; } bool CeTcpSyncConnection::timeStampForLocalFileTime(FILETIME* fTime) const { - QString cmd = "cetcpsync timeStampForLocalFileTime " + fileTimeToString(*fTime) + " >filetime.txt"; + QString cmd = ceTcpSyncProgram + " timeStampForLocalFileTime " + fileTimeToString(*fTime) + " >qt_cetcpsyncdata.txt"; if (system(qPrintable(cmd)) != 0) return false; - QFile file("filetime.txt"); + QFile file("qt_cetcpsyncdata.txt"); if (!file.open(QIODevice::ReadOnly)) return false; @@ -183,11 +184,11 @@ bool CeTcpSyncConnection::timeStampForLocalFileTime(FILETIME* fTime) const bool CeTcpSyncConnection::fileCreationTime(const QString &fileName, FILETIME* deviceCreationTime) const { - QString cmd = "cetcpsync fileCreationTime \"" + fileName + "\" >filetime.txt"; + QString cmd = ceTcpSyncProgram + " fileCreationTime \"" + fileName + "\" >qt_cetcpsyncdata.txt"; if (system(qPrintable(cmd)) != 0) return false; - QFile file("filetime.txt"); + QFile file("qt_cetcpsyncdata.txt"); if (!file.open(QIODevice::ReadOnly)) return false; diff --git a/tools/qtestlib/wince/cetest/cetest.pro b/tools/qtestlib/wince/cetest/cetest.pro index c6eba7fdc..a6b79dafd 100644 --- a/tools/qtestlib/wince/cetest/cetest.pro +++ b/tools/qtestlib/wince/cetest/cetest.pro @@ -35,7 +35,7 @@ SOURCES += \ deployment.cpp \ main.cpp -win32-msvc*:LIBS += ole32.lib advapi32.lib +LIBS += ole32.lib advapi32.lib isEmpty(QT_CE_RAPI_INC) { DEFINES += QT_CETEST_NO_ACTIVESYNC @@ -44,7 +44,7 @@ isEmpty(QT_CE_RAPI_INC) { } else { HEADERS += activesyncconnection.h SOURCES += activesyncconnection.cpp - win32-msvc*:LIBS += rapi.lib + LIBS += rapi.lib INCLUDEPATH += $$QT_CE_RAPI_INC LIBS += -L$$QT_CE_RAPI_LIB } -- cgit v1.2.3 From 0ba2e3c4fa088a5467279cf851b2b49697ccad5c Mon Sep 17 00:00:00 2001 From: Prasanth Ullattil Date: Wed, 5 Aug 2009 13:14:16 +0200 Subject: Re-enable the use of Common Item Dialog This was disabled by patch bf305bc2e488ad4f08c49767246f31a81218991e Reviewed-by: Thomas Hartmann --- src/gui/dialogs/qfiledialog_win.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/gui/dialogs/qfiledialog_win.cpp b/src/gui/dialogs/qfiledialog_win.cpp index 9bf82c334..c542ff085 100644 --- a/src/gui/dialogs/qfiledialog_win.cpp +++ b/src/gui/dialogs/qfiledialog_win.cpp @@ -59,7 +59,9 @@ #endif #include - +#if !defined(Q_WS_WINCE) +#include +#endif #include #if defined(__IFileDialog_INTERFACE_DEFINED__) \ -- cgit v1.2.3 From cb599c5ea32e8e5ff81318038b432272f107b1fe Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Thu, 30 Jul 2009 12:58:06 +0200 Subject: Fix compilation on AIX: -I/usr/include cannot be used. The reason is that the C++ compiler needs to add -I/usr/vacpp/include before -I/usr/include, so our adding of -I/usr/include changes the order. This causes a compilation error in the C++ header xlocinfo.h. In any case, these checks done in qmake are unnecessary. If the OpenSSL headers are in one of those include paths, they will be found on their own already. Reviewed-By: Bradley T. Hughes (cherry picked from commit 04f7834fcd8db4ecb6a4c53de42ac83f571b37c8) --- config.tests/unix/openssl/openssl.pri | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/config.tests/unix/openssl/openssl.pri b/config.tests/unix/openssl/openssl.pri index bc954794e..f069396f7 100644 --- a/config.tests/unix/openssl/openssl.pri +++ b/config.tests/unix/openssl/openssl.pri @@ -1,9 +1,3 @@ -!cross_compile { - TRY_INCLUDEPATHS = /include /usr/include /usr/local/include $$QMAKE_INCDIR $$INCLUDEPATH - # LSB doesn't allow using headers from /include or /usr/include - linux-lsb-g++:TRY_INCLUDEPATHS = $$QMAKE_INCDIR $$INCLUDEPATH - for(p, TRY_INCLUDEPATHS) { - pp = $$join(p, "", "", "/openssl") - exists($$pp):INCLUDEPATH *= $$p - } -} +# Empty file since Qt 4.6 +# I'm too lazy to find all places where this file is included + -- cgit v1.2.3 From b4f1f4de1a0df7028440faaff146ac1560dc6169 Mon Sep 17 00:00:00 2001 From: Thierry Bastian Date: Wed, 5 Aug 2009 13:17:39 +0200 Subject: MainWindow: fixed an update issue when moving a separator A non painted (ie. garbage) area could appear if you had a fixed size dock widget and you moved the separator. The previous place where the separator was painted was not updated --- src/gui/widgets/qmainwindowlayout.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/gui/widgets/qmainwindowlayout.cpp b/src/gui/widgets/qmainwindowlayout.cpp index 3936a6781..55afa7029 100644 --- a/src/gui/widgets/qmainwindowlayout.cpp +++ b/src/gui/widgets/qmainwindowlayout.cpp @@ -1988,6 +1988,9 @@ void QMainWindowLayout::timerEvent(QTimerEvent *e) if (movingSeparatorOrigin == movingSeparatorPos) return; + //when moving the separator, we need to update the previous position + parentWidget()->update(layoutState.dockAreaLayout.separatorRegion()); + layoutState = savedState; layoutState.dockAreaLayout.separatorMove(movingSeparator, movingSeparatorOrigin, movingSeparatorPos); -- cgit v1.2.3 From 90480b9a25568858d1383e0aab6f5708a7dabd4f Mon Sep 17 00:00:00 2001 From: Alexis Menard Date: Wed, 5 Aug 2009 13:19:29 +0200 Subject: Fix a bug when activating HideNameFilterDetails on Windows filedialog. The HideNameFilterDetails was not taken in account for windows file dialog. This patch fix that. For Windows Vista and later we use now the new COMMON_ITEM_DIALOG API (in master) where it add always the filter extension like *.txt so no point to take that flag in account. Task-number: None, during testing Reviewed-by: prasanth --- src/gui/dialogs/qfiledialog.cpp | 2 +- src/gui/dialogs/qfiledialog_win.cpp | 28 ++++++++++++++++++---------- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/gui/dialogs/qfiledialog.cpp b/src/gui/dialogs/qfiledialog.cpp index c8ce162df..6977731e4 100644 --- a/src/gui/dialogs/qfiledialog.cpp +++ b/src/gui/dialogs/qfiledialog.cpp @@ -219,7 +219,7 @@ Q_GUI_EXPORT _qt_filedialog_save_filename_hook qt_filedialog_save_filename_hook the native file dialog is used unless you use a subclass of QFileDialog that contains the Q_OBJECT macro. \value ReadOnly Indicates that the model is readonly. - \value HideNameFilterDetails Indicates if the is hidden or not. + \value HideNameFilterDetails Indicates if the filter extension (e.g. *.bmp) is hidden or not. This value is obsolete and does nothing since Qt 4.5: diff --git a/src/gui/dialogs/qfiledialog_win.cpp b/src/gui/dialogs/qfiledialog_win.cpp index 9a478aaaa..37a25e57c 100644 --- a/src/gui/dialogs/qfiledialog_win.cpp +++ b/src/gui/dialogs/qfiledialog_win.cpp @@ -163,15 +163,22 @@ static QStringList qt_win_make_filters_list(const QString &filter) } // Makes a NUL-oriented Windows filter from a Qt filter. -static QString qt_win_filter(const QString &filter) +static QString qt_win_filter(const QString &filter, bool hideFiltersDetails) { QStringList filterLst = qt_win_make_filters_list(filter); QStringList::Iterator it = filterLst.begin(); QString winfilters; + QRegExp r(QString::fromLatin1(qt_file_dialog_filter_reg_exp)); for (; it != filterLst.end(); ++it) { QString subfilter = *it; if (!subfilter.isEmpty()) { - winfilters += subfilter; + if (hideFiltersDetails) { + int index = r.indexIn(subfilter); + if (index >= 0) + winfilters += r.cap(1); + } else { + winfilters += subfilter; + } winfilters += QChar(); winfilters += qt_win_extract_filter(subfilter); winfilters += QChar(); @@ -377,11 +384,12 @@ QString qt_win_get_open_file_name(const QFileDialogArgs &args, modal_widget.setAttribute(Qt::WA_NoChildEventsForParent, true); modal_widget.setParent(args.parent, Qt::Window); QApplicationPrivate::enterModal(&modal_widget); + bool hideFiltersDetails = args.options & QFileDialog::HideNameFilterDetails; QT_WA({ // Use Unicode strings and API OPENFILENAME* ofn = qt_win_make_OFN(args.parent, args.selection, args.directory, args.caption, - qt_win_filter(args.filter), + qt_win_filter(args.filter, hideFiltersDetails), QFileDialog::ExistingFile, args.options); if (idx) @@ -395,7 +403,7 @@ QString qt_win_get_open_file_name(const QFileDialogArgs &args, // Use ANSI strings and API OPENFILENAMEA* ofn = qt_win_make_OFNA(args.parent, args.selection, args.directory, args.caption, - qt_win_filter(args.filter), + qt_win_filter(args.filter, hideFiltersDetails), QFileDialog::ExistingFile, args.options); if (idx) @@ -452,7 +460,7 @@ QString qt_win_get_save_file_name(const QFileDialogArgs &args, modal_widget.setAttribute(Qt::WA_NoChildEventsForParent, true); modal_widget.setParent(args.parent, Qt::Window); QApplicationPrivate::enterModal(&modal_widget); - + bool hideFiltersDetails = args.options & QFileDialog::HideNameFilterDetails; // This block is used below for the lpstrDefExt member. // Note that the current MSDN docs document this member wrong. // It should rather be documented as "the default extension if no extension was given and if the @@ -469,12 +477,11 @@ QString qt_win_get_save_file_name(const QFileDialogArgs &args, defaultSaveExt.clear(); } } - QT_WA({ // Use Unicode strings and API OPENFILENAME *ofn = qt_win_make_OFN(args.parent, args.selection, args.directory, args.caption, - qt_win_filter(args.filter), + qt_win_filter(args.filter, hideFiltersDetails), QFileDialog::AnyFile, args.options); @@ -491,7 +498,7 @@ QString qt_win_get_save_file_name(const QFileDialogArgs &args, // Use ANSI strings and API OPENFILENAMEA *ofn = qt_win_make_OFNA(args.parent, args.selection, args.directory, args.caption, - qt_win_filter(args.filter), + qt_win_filter(args.filter, hideFiltersDetails), QFileDialog::AnyFile, args.options); QByteArray asciiExt = defaultSaveExt.toAscii(); @@ -558,10 +565,11 @@ QStringList qt_win_get_open_file_names(const QFileDialogArgs &args, modal_widget.setAttribute(Qt::WA_NoChildEventsForParent, true); modal_widget.setParent(args.parent, Qt::Window); QApplicationPrivate::enterModal(&modal_widget); + bool hideFiltersDetails = args.options & QFileDialog::HideNameFilterDetails; QT_WA({ OPENFILENAME* ofn = qt_win_make_OFN(args.parent, args.selection, args.directory, args.caption, - qt_win_filter(args.filter), + qt_win_filter(args.filter, hideFiltersDetails), QFileDialog::ExistingFiles, args.options); if (idx) @@ -594,7 +602,7 @@ QStringList qt_win_get_open_file_names(const QFileDialogArgs &args, } , { OPENFILENAMEA* ofn = qt_win_make_OFNA(args.parent, args.selection, args.directory, args.caption, - qt_win_filter(args.filter), + qt_win_filter(args.filter, hideFiltersDetails), QFileDialog::ExistingFiles, args.options); if (idx) -- cgit v1.2.3 From ca2a9d87d81095f6ff7b821e3d8cbe120a6d9b23 Mon Sep 17 00:00:00 2001 From: Alexis Menard Date: Wed, 5 Aug 2009 13:13:33 +0200 Subject: Fix regressions introduced by 31edb4d5a63b9b3c28cce1c4ca6eb99f62a09759 The commit 31edb4d5a63b9b3c28cce1c4ca6eb99f62a09759 introduced regressions in filters which breaks the mac native dialog, the non native dialog with HideNameFilterDetails activated. Task-number:259105 Reviewed-by:olivier Reviewed-by:prasanth --- src/gui/dialogs/qfiledialog.cpp | 14 ++++++---- src/gui/dialogs/qfiledialog_win.cpp | 2 ++ tests/auto/qfiledialog/tst_qfiledialog.cpp | 43 ++++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 5 deletions(-) diff --git a/src/gui/dialogs/qfiledialog.cpp b/src/gui/dialogs/qfiledialog.cpp index 1ec94b644..f000033d9 100644 --- a/src/gui/dialogs/qfiledialog.cpp +++ b/src/gui/dialogs/qfiledialog.cpp @@ -394,6 +394,9 @@ QList QFileDialog::sidebarUrls() const static const qint32 QFileDialogMagic = 0xbe; +const char *qt_file_dialog_filter_reg_exp = +"^(.*)\\(([a-zA-Z0-9_.*? +;#\\-\\[\\]@\\{\\}/!<>\\$%&=^~:\\|]*)\\)$"; + /*! \since 4.3 Saves the state of the dialog's layout, history and current directory. @@ -984,8 +987,13 @@ void QFileDialog::setNameFilters(const QStringList &filters) if (testOption(HideNameFilterDetails)) { QStringList strippedFilters; + QRegExp r(QString::fromLatin1(qt_file_dialog_filter_reg_exp)); for (int i = 0; i < cleanedFilters.count(); ++i) { - strippedFilters.append(cleanedFilters[i].mid(0, cleanedFilters[i].indexOf(QLatin1String(" (")))); + QString filterName; + int index = r.indexIn(cleanedFilters[i]); + if (index >= 0) + filterName = r.cap(1); + strippedFilters.append(filterName.simplified()); } d->qFileDialogUi->fileTypeCombo->addItems(strippedFilters); } else { @@ -2837,10 +2845,6 @@ void QFileDialogPrivate::_q_goToDirectory(const QString &path) } } -const char *qt_file_dialog_filter_reg_exp = -"(\\W|[a-zA-Z0-9 -]*)\\(([a-zA-Z0-9_.*? +;#\\-\\[\\]@\\{\\}/!<>\\$%&=^~:\\|]*)\\)$"; - - // Makes a list of filters from a normal filter string "Image Files (*.png *.jpg)" QStringList qt_clean_filter_list(const QString &filter) { diff --git a/src/gui/dialogs/qfiledialog_win.cpp b/src/gui/dialogs/qfiledialog_win.cpp index c542ff085..02469b28f 100644 --- a/src/gui/dialogs/qfiledialog_win.cpp +++ b/src/gui/dialogs/qfiledialog_win.cpp @@ -443,6 +443,8 @@ static bool qt_win_set_IFileDialogOptions(IFileDialog *pfd, QString subfilter = *it; if (!subfilter.isEmpty()) { offsets< + diff --git a/doc/src/examples.qdoc b/doc/src/examples.qdoc index 74a9bd880..7f9264b7a 100644 --- a/doc/src/examples.qdoc +++ b/doc/src/examples.qdoc @@ -330,6 +330,7 @@ \o \l{statemachine/eventtransitions}{Event Transitions}\raisedaster \o \l{statemachine/factorial}{Factorial States}\raisedaster \o \l{statemachine/pingpong}{Ping Pong States}\raisedaster + \o \l{statemachine/rogue}{Rogue}\raisedaster \o \l{statemachine/trafficlight}{Traffic Light}\raisedaster \o \l{statemachine/twowaybutton}{Two-way Button}\raisedaster \endlist diff --git a/doc/src/examples/rogue.qdoc b/doc/src/examples/rogue.qdoc new file mode 100644 index 000000000..8fa2c6924 --- /dev/null +++ b/doc/src/examples/rogue.qdoc @@ -0,0 +1,222 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \example statemachine/rogue + \title Rogue Example + + The Rogue example shows how to use the Qt state machine for event + handling. + + \image rogue-example.png + + This example implements a simple text based game. Do you see the + \c{@} in the screenshot? That's you, the rogue. The \c{#} + characters are walls, and the dots represent floor. In a real + game, other ASCII characters would represent all kinds of objects + and creatures. For instance, ancient dragons (\c{D}'s) or food + rations (\c{%}'s). But let's not get carried away. In this game, + the rogue is simply running around in an empty room. + + The rogue is moved with the keypad (2, 4, 8, 6). That aside, we + have implemented a \c quit command that triggers if the player + types \c {q}. The player is then asked if he/she really wants to + quit. + + Most games have commands that need more than one key press and + that may require a different sequence of keys based on questions + asked the user. In this game, only the \c quit command falls under + this category, but for the sake of argument, let's imagine a + fully-fledged game with a rich set of commands. If we were to + implement these by catching key events in + \l{QWidget::}{keyPressEvent()}, we would have to keep a lot of + class member variables to track the sequence of keys already typed + (or find some other way of deducing the current state of a + command). This can easily lead to spaghetti, which is--as we all + well know, I'm sure--unpleasant. With a state machine, on the + other hand, separate states can wait for a single key press, and + that makes our lives a lot simpler. + + The example consists of two classes: + + \list + \o \c Window draws the text display of the game and sets + up the state machine. The window also has a status bar + above the area in which the rouge moves. + \o \c MovementTransition is a transition that carries out + a single move of the rogue. + \endlist + + Before we embark on a code walkthrough, it is necessary to take a + closer look at the design of the machine. Here is a state chart + that shows what we want to achieve: + + \image rogue-statechart.png + + The input state waits for a key press to start a new command. + When receiving a key it recognizes, it transitions to one of the + two commands of the game; though, as we will see, movement is + handled by the transition itself. The quit state waits for the + player to answer yes or no (by typing \c y or \c n) when asked + whether he/she really wants to quit the game. + + The chart demonstrates how we use one state to wait for a single + key press. The press received may trigger one of the transitions + connected to the state. + + \section1 Window Class Definition + + The \c Window class is a widget that draws the text display of the + game. It also sets up the state machine, i.e., creates and + connects the states in the machine. It is the key events from this + widget that are used by the machine. + + \snippet examples/statemachine/rogue/window.h 0 + + \c Direction specifies the direction in which the rogue is to + move. We use this in \c movePlayer(), which moves the rogue and + repaints the window. The game has a status line above the area in + which the rogue moves. The \c status property contains the text of + this line. We use a property because the QState class allows + setting any Qt \l{Qt's Property System}{property} when entered. + More on this later. + + \snippet examples/statemachine/rogue/window.h 1 + + The \c map is an array with the characters that are currently + displayed. We set up the array in \c setupMap(), and update it + when the rogue is moved. \c pX and \c pY is the current position + of the rogue. \c WIDTH and \c HEIGHT are macros specifying the + dimensions of the map. + + The \c paintEvent() function is left out of this walkthrough. We + also do not discuss other code that does not concern the state + machine (the \c setupMap(), \c status(), \c setStatus(), \c + movePlayer(), and \c sizeHint() functions). If you wish to take a + look at the code, click on the link for the \c window.cpp file at + the top of this page. + + \section1 Window Class Implementation + + Here is the constructor of \c Window: + + \snippet examples/statemachine/rogue/window.cpp 0 + \dots + \snippet examples/statemachine/rogue/window.cpp 1 + + The player starts off at position (5, 5). We then set up the map + and statemachine. Let's proceed with the \c buildMachine() + function: + + \snippet examples/statemachine/rogue/window.cpp 2 + + We enter \c inputState when the machine is started and from the \c + quitState if the user wants to continue playing. We then set the + status to a helpful reminder of how to play the game. + + First, the \c Movement transition is added to the input state. + This will enable the rogue to be moved with the keypad. Notice + that we don't set a target state for the movement transition. This + will cause the transition to be triggered (and the + \l{QAbstractTransition::}{onTransition()} function to be invoked), + but the machine will not leave the \c inputState. If we had set \c + inputState as the target state, we would first have left and then + entered the \c inputState again. + + \snippet examples/statemachine/rogue/window.cpp 3 + + When we enter \c quitState, we update the status bar of the + window. + + \c QKeyEventTransition is a utility class that removes the hassle + of implementing transitions for \l{QKeyEvent}s. We simply need to + specify the key on which the transition should trigger and the + target state of the transition. + + \snippet examples/statemachine/rogue/window.cpp 4 + + The transition from \c inputState allows triggering the quit state + when the player types \c {q}. + + \snippet examples/statemachine/rogue/window.cpp 5 + + The machine is set up, so it's time to start it. + + \section1 The MovementTransition Class + + \c MovementTransition is triggered when the player request the + rogue to be moved (by typing 2, 4, 6, or 8) when the machine is in + the \c inputState. + + \snippet examples/statemachine/rogue/movementtransition.h 0 + + In the constructor, we tell QEventTransition to only send + \l{QEvent::}{KeyPress} events to the + \l{QAbstractTransition::}{eventTest()} function: + + \snippet examples/statemachine/rogue/movementtransition.h 1 + + The KeyPress events come wrapped in \l{QWrappedEvent}s. \c event + must be confirmed to be a wrapped event because Qt uses other + events internally. After that, it is simply a matter of checking + which key has been pressed. + + Let's move on to the \c onTransition() function: + + \snippet examples/statemachine/rogue/movementtransition.h 2 + + When \c onTransition() is invoked, we know that we have a + \l{QEvent::}{KeyPress} event with 2, 4, 6, or 8, i.e., the event + is already unwrapped. + + \section1 The Roguelike Tradition + + You might have been wondering why the game features a rogue. Well, + these kinds of text based dungeon exploration games date back to a + game called, yes, "Rogue". Although outflanked by the technology + of modern 3D computer games, roguelikes have a solid community of + hard-core, devoted followers. + + Playing these games can be surprisingly addictive (despite the + lack of graphics). Angband, the perhaps most well-known rougelike, + is found here: \l{http://rephial.org/}. +*/ + diff --git a/doc/src/images/rogue-example.png b/doc/src/images/rogue-example.png new file mode 100644 index 000000000..7aeb0e54f Binary files /dev/null and b/doc/src/images/rogue-example.png differ diff --git a/doc/src/images/rogue-statechart.png b/doc/src/images/rogue-statechart.png new file mode 100644 index 000000000..c5f404892 Binary files /dev/null and b/doc/src/images/rogue-statechart.png differ diff --git a/examples/statemachine/rogue/main.cpp b/examples/statemachine/rogue/main.cpp new file mode 100644 index 000000000..0c2fb2d90 --- /dev/null +++ b/examples/statemachine/rogue/main.cpp @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "window.h" + +int main(int argv, char **args) +{ + QApplication app(argv, args); + + Window window; + window.show(); + + return app.exec(); +} + diff --git a/examples/statemachine/rogue/movementtransition.h b/examples/statemachine/rogue/movementtransition.h new file mode 100644 index 000000000..929077dc6 --- /dev/null +++ b/examples/statemachine/rogue/movementtransition.h @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef MOVEMENTTRANSITION_H +#define MOVEMENTTRANSITION_H + +#include + +#include "window.h" + +//![0] +class MovementTransition : public QEventTransition +{ + Q_OBJECT + +public: + MovementTransition(Window *window) : + QEventTransition(window, QEvent::KeyPress) { + this->window = window; + } +//![0] + +//![1] +protected: + bool eventTest(QEvent *event) { + if (event->type() == QEvent::Wrapped && + static_cast(event)->event()->type() == QEvent::KeyPress) { + QEvent *wrappedEvent = static_cast(event)->event(); + + QKeyEvent *keyEvent = static_cast(wrappedEvent); + int key = keyEvent->key(); + + return key == Qt::Key_2 || key == Qt::Key_8 || key == Qt::Key_6 || + key == Qt::Key_4; + } + return false; + } +//![1] + +//![2] + void onTransition(QEvent *event) { + QKeyEvent *keyEvent = static_cast( + static_cast(event)->event()); + + int key = keyEvent->key(); + switch (key) { + case Qt::Key_4: + window->movePlayer(Window::Left); + break; + case Qt::Key_8: + window->movePlayer(Window::Up); + break; + case Qt::Key_6: + window->movePlayer(Window::Right); + break; + case Qt::Key_2: + window->movePlayer(Window::Down); + break; + default: + ; + } + } +//![2] + +private: + Window *window; +}; + +#endif + diff --git a/examples/statemachine/rogue/rogue.pro b/examples/statemachine/rogue/rogue.pro new file mode 100644 index 000000000..15718540d --- /dev/null +++ b/examples/statemachine/rogue/rogue.pro @@ -0,0 +1,11 @@ +HEADERS = window.h \ + movementtransition.h +SOURCES = main.cpp \ + window.cpp + +# install +target.path = $$[QT_INSTALL_EXAMPLES]/statemachine/rogue +sources.files = $$SOURCES $$HEADERS *.pro +sources.path = $$[QT_INSTALL_EXAMPLES]/statemachine/rogue +INSTALLS += target sources + diff --git a/examples/statemachine/rogue/window.cpp b/examples/statemachine/rogue/window.cpp new file mode 100644 index 000000000..39565a30f --- /dev/null +++ b/examples/statemachine/rogue/window.cpp @@ -0,0 +1,201 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "window.h" +#include "movementtransition.h" + +//![0] +Window::Window() +{ + pX = 5; + pY = 5; +//![0] + + QFontDatabase database; + QFont font; + if (database.families().contains("Monospace")) + font = QFont("Monospace", 12); + else { + foreach (QString family, database.families()) { + if (database.isFixedPitch(family)) { + font = QFont(family, 12); + break; + } + } + } + setFont(font); + +//![1] + setupMap(); + buildMachine(); +} +//![1] + +void Window::setStatus(const QString &status) +{ + myStatus = status; + repaint(); +} + +QString Window::status() const +{ + return myStatus; +} + +void Window::paintEvent(QPaintEvent * /* event */) +{ + QFontMetrics metrics(font()); + QPainter painter(this); + int fontHeight = metrics.height(); + int fontWidth = metrics.width('X'); + int yPos = fontHeight; + int xPos; + + painter.fillRect(rect(), Qt::black); + painter.setPen(Qt::white); + + painter.drawText(QPoint(0, yPos), status()); + + for (int y = 0; y < HEIGHT; ++y) { + yPos += fontHeight; + xPos = 0; + + for (int x = 0; x < WIDTH; ++x) { + if (y == pY && x == pX) { + xPos += fontWidth; + continue; + } + + painter.drawText(QPoint(xPos, yPos), map[x][y]); + xPos += fontWidth; + } + } + painter.drawText(QPoint(pX * fontWidth, (pY + 2) * fontHeight), QChar('@')); +} + +QSize Window::sizeHint() const +{ + QFontMetrics metrics(font()); + + return QSize(metrics.width('X') * WIDTH, metrics.height() * (HEIGHT + 1)); +} + +//![2] +void Window::buildMachine() +{ + machine = new QStateMachine; + + QState *inputState = new QState(machine); + inputState->assignProperty(this, "status", "Move the rogue with 2, 4, 6, and 8"); + + MovementTransition *transition = new MovementTransition(this); + inputState->addTransition(transition); +//![2] + +//![3] + QState *quitState = new QState(machine); + quitState->assignProperty(this, "status", "Really quit(y/n)?"); + + QKeyEventTransition *yesTransition = new + QKeyEventTransition(this, QEvent::KeyPress, Qt::Key_Y); + yesTransition->setTargetState(new QFinalState(machine)); + quitState->addTransition(yesTransition); + + QKeyEventTransition *noTransition = + new QKeyEventTransition(this, QEvent::KeyPress, Qt::Key_N); + noTransition->setTargetState(inputState); + quitState->addTransition(noTransition); +//![3] + +//![4] + QKeyEventTransition *quitTransition = + new QKeyEventTransition(this, QEvent::KeyPress, Qt::Key_Q); + quitTransition->setTargetState(quitState); + inputState->addTransition(quitTransition); +//![4] + +//![5] + machine->setInitialState(inputState); + + connect(machine, SIGNAL(finished()), qApp, SLOT(quit())); + + machine->start(); +} +//![5] + +void Window::movePlayer(Direction direction) +{ + switch (direction) { + case Left: + if (map[pX - 1][pY] != '#') + --pX; + break; + case Right: + if (map[pX + 1][pY] != '#') + ++pX; + break; + case Up: + if (map[pX][pY - 1] != '#') + --pY; + break; + case Down: + if (map[pX][pY + 1] != '#') + ++pY; + break; + } + repaint(); +} + +void Window::setupMap() +{ + qsrand(QTime(0,0,0).secsTo(QTime::currentTime())); + + for (int x = 0; x < WIDTH; ++x) + for (int y = 0; y < HEIGHT; ++y) { + if (x == 0 || x == WIDTH - 1 || y == 0 || y == HEIGHT - 1 || qrand() % 40 == 0) + map[x][y] = '#'; + else + map[x][y] = '.'; + } +} + diff --git a/examples/statemachine/rogue/window.h b/examples/statemachine/rogue/window.h new file mode 100644 index 000000000..bcd86bd8a --- /dev/null +++ b/examples/statemachine/rogue/window.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef WINDOW_H +#define WINDOW_H + +#include + +class QState; +class QStateMachine; +class QTransition; + +#define WIDTH 35 +#define HEIGHT 20 + +//![0] +class Window : public QWidget +{ + Q_OBJECT + Q_PROPERTY(QString status READ status WRITE setStatus) + +public: + enum Direction { Up, Down, Left, Right }; + + Window(); + + void movePlayer(Direction direction); + void setStatus(const QString &status); + QString status() const; + + QSize sizeHint() const; + +protected: + void paintEvent(QPaintEvent *event); +//![0] + +//![1] +private: + void buildMachine(); + void setupMap(); + + QChar map[WIDTH][HEIGHT]; + int pX, pY; + + QStateMachine *machine; + QString myStatus; +}; +//![1] + +#endif + diff --git a/examples/statemachine/statemachine.pro b/examples/statemachine/statemachine.pro index ea3e7a809..298c0ae33 100644 --- a/examples/statemachine/statemachine.pro +++ b/examples/statemachine/statemachine.pro @@ -3,6 +3,7 @@ SUBDIRS = \ eventtransitions \ factorial \ pingpong \ + rogue \ trafficlight \ twowaybutton -- cgit v1.2.3 From 3c2b9047be4f4f835e59c13d5038b907c629451f Mon Sep 17 00:00:00 2001 From: Kent Hansen Date: Fri, 7 Aug 2009 14:01:11 +0200 Subject: adjust some ifdefs so they are easy to remove with a script In preparation of making the old QtScript back-end a separate package/solution. --- src/script/qscriptable.cpp | 4 ++-- src/script/qscriptable_p.h | 4 ++-- src/script/qscriptclassdata.cpp | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/script/qscriptable.cpp b/src/script/qscriptable.cpp index 5da9e9514..94468de2c 100644 --- a/src/script/qscriptable.cpp +++ b/src/script/qscriptable.cpp @@ -39,10 +39,10 @@ ** ****************************************************************************/ -#ifndef QT_NO_QOBJECT - #include "qscriptable.h" +#ifndef QT_NO_QOBJECT + #ifndef QT_NO_SCRIPT #include "qscriptable_p.h" diff --git a/src/script/qscriptable_p.h b/src/script/qscriptable_p.h index 8ea65ed00..1d297d960 100644 --- a/src/script/qscriptable_p.h +++ b/src/script/qscriptable_p.h @@ -55,7 +55,7 @@ // We mean it. // -#if !defined(QT_NO_QOBJECT) && !defined(QT_NO_SCRIPT) +#ifndef QT_NO_SCRIPT QT_BEGIN_NAMESPACE @@ -79,6 +79,6 @@ public: QT_END_NAMESPACE -#endif // QT_NO_QOBJECT && QT_NO_SCRIPT +#endif // QT_NO_SCRIPT #endif diff --git a/src/script/qscriptclassdata.cpp b/src/script/qscriptclassdata.cpp index 08e7220f7..576a51990 100644 --- a/src/script/qscriptclassdata.cpp +++ b/src/script/qscriptclassdata.cpp @@ -114,4 +114,4 @@ QScriptClassDataIterator::~QScriptClassDataIterator() QT_END_NAMESPACE -#endif +#endif // QT_NO_SCRIPT -- cgit v1.2.3 From f37b4ab8c8116abc2f71128e308b938c90ec5b8a Mon Sep 17 00:00:00 2001 From: Thierry Bastian Date: Fri, 7 Aug 2009 14:01:26 +0200 Subject: QDockWidget: Make visibilityChanged more accurate Task-number: 258459 --- src/gui/widgets/qdockarealayout.cpp | 2 +- src/gui/widgets/qdockwidget.cpp | 2 +- tests/auto/qdockwidget/tst_qdockwidget.cpp | 19 ++++++++++++++++++- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/gui/widgets/qdockarealayout.cpp b/src/gui/widgets/qdockarealayout.cpp index ee29b55f4..cad69036a 100644 --- a/src/gui/widgets/qdockarealayout.cpp +++ b/src/gui/widgets/qdockarealayout.cpp @@ -1545,7 +1545,7 @@ void QDockAreaLayoutInfo::apply(bool animate) QRect geo = w->geometry(); widgetAnimator.animate(w, r, animate); - if (!w->isHidden()) { + if (!w->isHidden() && w->window()->isVisible()) { QDockWidget *dw = qobject_cast(w); if (!r.isValid() && geo.right() >= 0 && geo.bottom() >= 0) { dw->lower(); diff --git a/src/gui/widgets/qdockwidget.cpp b/src/gui/widgets/qdockwidget.cpp index 5810c81c3..e60f099d9 100644 --- a/src/gui/widgets/qdockwidget.cpp +++ b/src/gui/widgets/qdockwidget.cpp @@ -1390,7 +1390,7 @@ bool QDockWidget::event(QEvent *event) break; case QEvent::Show: d->toggleViewAction->setChecked(true); - emit visibilityChanged(true); + emit visibilityChanged(geometry().right() >= 0 && geometry().bottom() >= 0); break; #endif case QEvent::ApplicationLayoutDirectionChange: diff --git a/tests/auto/qdockwidget/tst_qdockwidget.cpp b/tests/auto/qdockwidget/tst_qdockwidget.cpp index 9b0e7060d..16bb12d18 100644 --- a/tests/auto/qdockwidget/tst_qdockwidget.cpp +++ b/tests/auto/qdockwidget/tst_qdockwidget.cpp @@ -91,6 +91,7 @@ private slots: void task169808_setFloating(); void task237438_setFloatingCrash(); void task248604_infiniteResize(); + void task258459_visibilityChanged(); }; // Testing get/set functions @@ -730,7 +731,7 @@ void tst_QDockWidget::task169808_setFloating() return QSize(20,20); } - void paintEvent(QPaintEvent *e) + void paintEvent(QPaintEvent *) { QPainter p(this); p.fillRect(rect(), Qt::red); @@ -798,5 +799,21 @@ void tst_QDockWidget::task248604_infiniteResize() } +void tst_QDockWidget::task258459_visibilityChanged() +{ + QMainWindow win; + QDockWidget dock1, dock2; + win.addDockWidget(Qt::RightDockWidgetArea, &dock1); + win.tabifyDockWidget(&dock1, &dock2); + QSignalSpy spy1(&dock1, SIGNAL(visibilityChanged(bool))); + QSignalSpy spy2(&dock2, SIGNAL(visibilityChanged(bool))); + win.show(); + QTest::qWait(200); + QCOMPARE(spy1.count(), 1); + QCOMPARE(spy1.first().first().toBool(), false); //dock1 is invisible + QCOMPARE(spy2.count(), 1); + QCOMPARE(spy2.first().first().toBool(), true); //dock1 is visible +} + QTEST_MAIN(tst_QDockWidget) #include "tst_qdockwidget.moc" -- cgit v1.2.3 From f419f3f229444f31ca879276713799f6af73195e Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Tue, 12 May 2009 20:26:58 +0200 Subject: Refactor the code that reads the KDE config in one file Move the code out of qapplication_x11.cpp, and qcommonstyle.cpp to qkde.cpp into the QKde namespace. This removes few of the code duplication, and is much cleaner. This will also let us install hook easily later. Reviewed-by: Jens Bache-Wiig --- src/gui/kernel/kernel.pri | 6 +- src/gui/kernel/qapplication_p.h | 1 - src/gui/kernel/qapplication_x11.cpp | 202 ++++++------------------------------ src/gui/kernel/qkde.cpp | 159 ++++++++++++++++++++++++++++ src/gui/kernel/qkde_p.h | 76 ++++++++++++++ src/gui/kernel/qt_x11_p.h | 3 +- src/gui/styles/qcommonstyle.cpp | 39 ++++--- 7 files changed, 297 insertions(+), 189 deletions(-) create mode 100644 src/gui/kernel/qkde.cpp create mode 100644 src/gui/kernel/qkde_p.h diff --git a/src/gui/kernel/kernel.pri b/src/gui/kernel/kernel.pri index e6eff6ebc..d9deefe73 100644 --- a/src/gui/kernel/kernel.pri +++ b/src/gui/kernel/kernel.pri @@ -100,7 +100,8 @@ unix:x11 { INCLUDEPATH += ../3rdparty/xorg HEADERS += \ kernel/qx11embed_x11.h \ - kernel/qx11info_x11.h + kernel/qx11info_x11.h \ + kernel/qkde_p.h SOURCES += \ kernel/qapplication_x11.cpp \ @@ -114,7 +115,8 @@ unix:x11 { kernel/qwidgetcreate_x11.cpp \ kernel/qx11embed_x11.cpp \ kernel/qx11info_x11.cpp \ - kernel/qkeymapper_x11.cpp + kernel/qkeymapper_x11.cpp \ + kernel/qkde.cpp contains(QT_CONFIG, glib) { SOURCES += \ diff --git a/src/gui/kernel/qapplication_p.h b/src/gui/kernel/qapplication_p.h index 700d1ab90..c4ce2ea4d 100644 --- a/src/gui/kernel/qapplication_p.h +++ b/src/gui/kernel/qapplication_p.h @@ -284,7 +284,6 @@ public: #if defined(Q_WS_X11) #ifndef QT_NO_SETTINGS - static QString kdeHome(); static QString x11_desktop_style(); static bool x11_apply_settings(); #endif diff --git a/src/gui/kernel/qapplication_x11.cpp b/src/gui/kernel/qapplication_x11.cpp index 40165637f..32e7e3c8a 100644 --- a/src/gui/kernel/qapplication_x11.cpp +++ b/src/gui/kernel/qapplication_x11.cpp @@ -83,6 +83,7 @@ #include "qtimer.h" #include "qlibrary.h" #include +#include "qkde_p.h" #if !defined (QT_NO_TABLET) extern "C" { @@ -813,33 +814,6 @@ Q_GUI_EXPORT void qt_x11_apply_settings_in_all_apps() PropModeReplace, (unsigned char *)stamp.data(), stamp.size()); } -static int kdeSessionVersion() -{ - static int kdeVersion = 0; - if (!kdeVersion) - kdeVersion = QString::fromLocal8Bit(qgetenv("KDE_SESSION_VERSION")).toInt(); - return kdeVersion; -} - -/*! \internal - Gets the current KDE 3 or 4 home path -*/ -QString QApplicationPrivate::kdeHome() -{ - static QString kdeHomePath; - if (kdeHomePath.isEmpty()) { - kdeHomePath = QString::fromLocal8Bit(qgetenv("KDEHOME")); - if (kdeHomePath.isEmpty()) { - QDir homeDir(QDir::homePath()); - QString kdeConfDir(QLatin1String("/.kde")); - if (4 == kdeSessionVersion() && homeDir.exists(QLatin1String(".kde4"))) - kdeConfDir = QLatin1String("/.kde4"); - kdeHomePath = QDir::homePath() + kdeConfDir; - } - } - return kdeHomePath; -} - /*! \internal apply the settings to the application */ @@ -905,8 +879,8 @@ bool QApplicationPrivate::x11_apply_settings() QFont font(QApplication::font()); QString fontDescription; // Override Qt font if KDE4 settings can be used - if (4 == kdeSessionVersion()) { - QSettings kdeSettings(kdeHome() + QLatin1String("/share/config/kdeglobals"), QSettings::IniFormat); + if (X11->desktopEnvironment == DE_KDE && X11->desktopVersion >= 4) { + QSettings kdeSettings(QKde::kdeHome() + QLatin1String("/share/config/kdeglobals"), QSettings::IniFormat); fontDescription = kdeSettings.value(QLatin1String("font")).toString(); if (fontDescription.isEmpty()) { // KDE stores fonts without quotes @@ -936,7 +910,6 @@ bool QApplicationPrivate::x11_apply_settings() // read new QStyle QString stylename = settings.value(QLatin1String("style")).toString(); - if (stylename.isEmpty() && QApplicationPrivate::styleOverride.isNull() && X11->use_xrender) { stylename = x11_desktop_style(); } @@ -1094,22 +1067,6 @@ static void qt_set_input_encoding() XFree((char *)data); } -// Reads a KDE color setting -static QColor kdeColor(const QString &key, const QSettings &kdeSettings) -{ - QVariant variant = kdeSettings.value(key); - if (variant.isValid()) { - QStringList values = variant.toStringList(); - if (values.size() == 3) { - int r = values[0].toInt(); - int g = values[1].toInt(); - int b = values[2].toInt(); - return QColor(r, g, b); - } - } - return QColor(); -} - // set font, foreground and background from x11 resources. The // arguments may override the resource settings. static void qt_set_x11_resources(const char* font = 0, const char* fg = 0, @@ -1276,9 +1233,10 @@ static void qt_set_x11_resources(const char* font = 0, const char* fg = 0, QApplicationPrivate::setSystemFont(fnt); } + // QGtkStyle sets it's own system palette + bool gtkStyle = QApplicationPrivate::app_style && QApplicationPrivate::app_style->inherits("QGtkStyle"); bool kdeColors = (QApplication::desktopSettingsAware() && X11->desktopEnvironment == DE_KDE); - - if (kdeColors || (button || !resBG.isEmpty() || !resFG.isEmpty())) {// set app colors + if (!gtkStyle && (kdeColors || (button || !resBG.isEmpty() || !resFG.isEmpty()))) {// set app colors bool allowX11ColorNames = QColor::allowX11ColorNames(); QColor::setAllowX11ColorNames(true); @@ -1314,45 +1272,6 @@ static void qt_set_x11_resources(const char* font = 0, const char* fg = 0, bright_mode = true; } - if (kdeColors) { - const QSettings theKdeSettings( - QApplicationPrivate::kdeHome() - + QLatin1String("/share/config/kdeglobals"), QSettings::IniFormat); - - // Setup KDE palette - QColor color; - color = kdeColor(QLatin1String("buttonBackground"), theKdeSettings); - if (!color.isValid()) - color = kdeColor(QLatin1String("Colors:Button/BackgroundNormal"), theKdeSettings); - if (color.isValid()) - btn = color; - - color = kdeColor(QLatin1String("background"), theKdeSettings); - if (!color.isValid()) - color = kdeColor(QLatin1String("Colors:Window/BackgroundNormal"), theKdeSettings); - if (color.isValid()) - bg = color; - - color = kdeColor(QLatin1String("foreground"), theKdeSettings); - if (!color.isValid()) - color = kdeColor(QLatin1String("Colors:View/ForegroundNormal"), theKdeSettings); - if (color.isValid()) { - fg = color; - } - - color = kdeColor(QLatin1String("windowForeground"), theKdeSettings); - if (!color.isValid()) - color = kdeColor(QLatin1String("Colors:Window/ForegroundNormal"), theKdeSettings); - if (color.isValid()) - wfg = color; - - color = kdeColor(QLatin1String("windowBackground"), theKdeSettings); - if (!color.isValid()) - color = kdeColor(QLatin1String("Colors:View/BackgroundNormal"), theKdeSettings); - if (color.isValid()) - base = color; - } - QPalette pal(fg, btn, btn.lighter(125), btn.darker(130), btn.darker(120), wfg.isValid() ? wfg : fg, Qt::white, base, bg); QColor disabled((fg.red() + btn.red()) / 2, (fg.green() + btn.green())/ 2, @@ -1365,50 +1284,6 @@ static void qt_set_x11_resources(const char* font = 0, const char* fg = 0, highlight = QColor(selectBackground); highlightText = QColor(selectForeground); } - // Use KDE3 or KDE4 color settings if present - if (kdeColors) { - const QSettings theKdeSettings( - QApplicationPrivate::kdeHome() - + QLatin1String("/share/config/kdeglobals"), QSettings::IniFormat); - - QColor color = kdeColor(QLatin1String("selectBackground"), theKdeSettings); - if (!color.isValid()) - color = kdeColor(QLatin1String("Colors:Selection/BackgroundNormal"), theKdeSettings); - if (color.isValid()) - highlight = color; - - color = kdeColor(QLatin1String("selectForeground"), theKdeSettings); - if (!color.isValid()) - color = kdeColor(QLatin1String("Colors:Selection/ForegroundNormal"), theKdeSettings); - if (color.isValid()) - highlightText = color; - - color = kdeColor(QLatin1String("alternateBackground"), theKdeSettings); - if (!color.isValid()) - color = kdeColor(QLatin1String("Colors:View/BackgroundAlternate"), theKdeSettings); - if (color.isValid()) - pal.setColor(QPalette::AlternateBase, color); - else - pal.setBrush(QPalette::AlternateBase, pal.base().color().darker(110)); - - color = kdeColor(QLatin1String("buttonForeground"), theKdeSettings); - if (!color.isValid()) - color = kdeColor(QLatin1String("Colors:Button/ForegroundNormal"), theKdeSettings); - if (color.isValid()) - pal.setColor(QPalette::ButtonText, color); - - color = kdeColor(QLatin1String("linkColor"), theKdeSettings); - if (!color.isValid()) - color = kdeColor(QLatin1String("Colors:View/ForegroundLink"), theKdeSettings); - if (color.isValid()) - pal.setColor(QPalette::Link, color); - - color = kdeColor(QLatin1String("visitedLinkColor"), theKdeSettings); - if (!color.isValid()) - color = kdeColor(QLatin1String("Colors:View/ForegroundVisited"), theKdeSettings); - if (color.isValid()) - pal.setColor(QPalette::LinkVisited, color); - } if (highlight.isValid() && highlightText.isValid()) { pal.setColor(QPalette::Highlight, highlight); @@ -1431,10 +1306,9 @@ static void qt_set_x11_resources(const char* font = 0, const char* fg = 0, pal.setColor(QPalette::Disabled, QPalette::Highlight, Qt::darkBlue); } - // QGtkStyle sets it's own system palette - if (!(QApplicationPrivate::app_style && QApplicationPrivate::app_style->inherits("QGtkStyle"))) { - QApplicationPrivate::setSystemPalette(pal); - } + if (kdeColors) + pal = QKde::kdePalette().resolve(pal); + QApplicationPrivate::setSystemPalette(pal); QColor::setAllowX11ColorNames(allowX11ColorNames); } @@ -2315,6 +2189,7 @@ void qt_init(QApplicationPrivate *priv, int, X11->compositingManagerRunning = XGetSelectionOwner(X11->display, ATOM(_NET_WM_CM_S0)); X11->desktopEnvironment = DE_UNKNOWN; + X11->desktopVersion = 0; // See if the current window manager is using the freedesktop.org spec to give its name Window windowManagerWindow = XNone; @@ -2390,6 +2265,9 @@ void qt_init(QApplicationPrivate *priv, int, XFree((char *)data); } + if (X11->desktopEnvironment == DE_KDE) + X11->desktopVersion = QString::fromLocal8Bit(qgetenv("KDE_SESSION_VERSION")).toInt(); + qt_set_input_encoding(); qt_set_x11_resources(appFont, appFGCol, appBGCol, appBTNCol); @@ -2657,44 +2535,30 @@ void qt_init(QApplicationPrivate *priv, int, QString QApplicationPrivate::x11_desktop_style() { QString stylename; - QStringList availableStyles = QStyleFactory::keys(); - // Override Qt style if KDE4 settings can be used - if (4 == kdeSessionVersion()) { - QSettings kdeSettings(kdeHome() + QLatin1String("/share/config/kdeglobals"), QSettings::IniFormat); - QString kde4Style = kdeSettings.value(QLatin1String("widgetStyle"), - QLatin1String("Oxygen")).toString(); - foreach (const QString &style, availableStyles) { - if (style.toLower() == kde4Style.toLower()) - stylename = kde4Style; - } - // Set QGtkStyle for GNOME - } else if (X11->desktopEnvironment == DE_GNOME) { + switch(X11->desktopEnvironment) { + case DE_KDE: + stylename = QKde::kdeStyle(); + break; + case DE_GNOME: { + QStringList availableStyles = QStyleFactory::keys(); + // Set QGtkStyle for GNOME if available QString gtkStyleKey = QString::fromLatin1("GTK+"); - if (availableStyles.contains(gtkStyleKey)) + if (availableStyles.contains(gtkStyleKey)) { stylename = gtkStyleKey; - } - - if (stylename.isEmpty()) { - switch(X11->desktopEnvironment) { - case DE_KDE: - if (X11->use_xrender) - stylename = QLatin1String("plastique"); - else - stylename = QLatin1String("windows"); - break; - case DE_GNOME: - if (X11->use_xrender) - stylename = QLatin1String("cleanlooks"); - else - stylename = QLatin1String("windows"); - break; - case DE_CDE: - stylename = QLatin1String("cde"); - break; - default: - // Don't do anything break; } + if (X11->use_xrender) + stylename = QLatin1String("cleanlooks"); + else + stylename = QLatin1String("windows"); + break; + } + case DE_CDE: + stylename = QLatin1String("cde"); + break; + default: + // Don't do anything + break; } return stylename; } diff --git a/src/gui/kernel/qkde.cpp b/src/gui/kernel/qkde.cpp new file mode 100644 index 000000000..96ff21e85 --- /dev/null +++ b/src/gui/kernel/qkde.cpp @@ -0,0 +1,159 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include "qkde_p.h" +#include +#include +#include +#include +#include "QtGui/qstylefactory.h" +#include "qt_x11_p.h" + +#if defined(Q_WS_X11) + +QT_BEGIN_NAMESPACE + +/*! \internal +Gets the current KDE home path +like "/home/troll/.kde" +*/ +QString QKde::kdeHome() +{ + static QString kdeHomePath; + if (kdeHomePath.isEmpty()) { + kdeHomePath = QString::fromLocal8Bit(qgetenv("KDEHOME")); + if (kdeHomePath.isEmpty()) { + QDir homeDir(QDir::homePath()); + QString kdeConfDir(QLatin1String("/.kde")); + if (4 == X11->desktopVersion && homeDir.exists(QLatin1String(".kde4"))) + kdeConfDir = QLatin1String("/.kde4"); + kdeHomePath = QDir::homePath() + kdeConfDir; + } + } + return kdeHomePath; +} + +/*!\internal + Reads the color from the config, and store it in the palette with the given color role if found + */ +static bool kdeColor(QPalette *pal, QPalette::ColorRole role, const QSettings &kdeSettings, const QString &kde4Key, const QString &kde3Key = QString()) +{ + QVariant variant = kdeSettings.value(kde4Key); + if (!variant.isValid()) + QVariant variant = kdeSettings.value(kde3Key); + if (variant.isValid()) { + QStringList values = variant.toStringList(); + if (values.size() == 3) { + int r = values[0].toInt(); + int g = values[1].toInt(); + int b = values[2].toInt(); + pal->setBrush(role, QColor(r, g, b)); + return true; + } + } + return false; +} + + +/*!\internal + Returns the KDE palette +*/ +QPalette QKde::kdePalette() +{ + const QSettings theKdeSettings(QKde::kdeHome() + + QLatin1String("/share/config/kdeglobals"), QSettings::IniFormat); + QPalette pal; + + // Setup KDE palette + kdeColor(&pal, QPalette::Button, theKdeSettings, QLatin1String("Colors:Button/BackgroundNormal"), QLatin1String("buttonBackground")); + kdeColor(&pal, QPalette::Window, theKdeSettings, QLatin1String("Colors:Window/BackgroundNormal"), QLatin1String("background")); + kdeColor(&pal, QPalette::Text, theKdeSettings, QLatin1String("Colors:View/ForegroundNormal"), QLatin1String("foreground")); + kdeColor(&pal, QPalette::WindowText, theKdeSettings, QLatin1String("Colors:Window/ForegroundNormal"), QLatin1String("windowForeground")); + kdeColor(&pal, QPalette::Base, theKdeSettings, QLatin1String("Colors:View/BackgroundNormal"), QLatin1String("windowBackground")); + kdeColor(&pal, QPalette::Highlight, theKdeSettings, QLatin1String("Colors:Selection/BackgroundNormal"), QLatin1String("selectBackground")); + kdeColor(&pal, QPalette::HighlightedText, theKdeSettings, QLatin1String("Colors:Selection/ForegroundNormal"), QLatin1String("selectForeground")); + kdeColor(&pal, QPalette::AlternateBase, theKdeSettings, QLatin1String("Colors:View/BackgroundAlternate"), QLatin1String("alternateBackground")); + kdeColor(&pal, QPalette::ButtonText, theKdeSettings, QLatin1String("Colors:Button/ForegroundNormal"), QLatin1String("buttonForeground")); + kdeColor(&pal, QPalette::Link, theKdeSettings, QLatin1String("Colors:View/ForegroundLink"), QLatin1String("linkColor")); + kdeColor(&pal, QPalette::LinkVisited, theKdeSettings, QLatin1String("Colors:View/ForegroundVisited"), QLatin1String("visitedLinkColor")); + //## TODO tooltip color + + return pal; +} + +/*!\internal + Returns the name of the QStyle to use. + (read from the kde config if needed) +*/ +QString QKde::kdeStyle() +{ + if (X11->desktopVersion >= 4) { + QSettings kdeSettings(QKde::kdeHome() + QLatin1String("/share/config/kdeglobals"), QSettings::IniFormat); + QString style = kdeSettings.value(QLatin1String("widgetStyle"), QLatin1String("Oxygen")).toString(); + + QStringList availableStyles = QStyleFactory::keys(); + if(availableStyles.contains(style, Qt::CaseInsensitive)) + return style; + } + + if (X11->use_xrender) + return QLatin1String("plastique"); + else + return QLatin1String("windows"); + + return QString(); +} + +/*!\internal + placeholder to load icon from kde. + to be implemented + */ +QIcon QKde::kdeIcon(const QString &name) +{ + //###todo + return QIcon(); +} + +QT_END_NAMESPACE + +#endif //Q_WS_X11 + diff --git a/src/gui/kernel/qkde_p.h b/src/gui/kernel/qkde_p.h new file mode 100644 index 000000000..ac760bd05 --- /dev/null +++ b/src/gui/kernel/qkde_p.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QKDE_H +#define QKDE_H + +#include +#include +#include + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// +#if defined(Q_WS_X11) + + +QT_BEGIN_NAMESPACE + +// This namespace contains helper function to help KDE integration +namespace QKde { + QString kdeHome(); + QString kdeStyle(); + QPalette kdePalette(); + QIcon kdeIcon(const QString &name); +} + + +QT_END_NAMESPACE + +#endif // Q_WS_X11 +#endif // QKDE_H diff --git a/src/gui/kernel/qt_x11_p.h b/src/gui/kernel/qt_x11_p.h index 1ac51e01d..44652d316 100644 --- a/src/gui/kernel/qt_x11_p.h +++ b/src/gui/kernel/qt_x11_p.h @@ -515,7 +515,8 @@ struct QX11Data char *startupId; - DesktopEnvironment desktopEnvironment; + DesktopEnvironment desktopEnvironment : 8; + uint desktopVersion : 8; /* Used only for KDE */ /* Warning: if you modify this list, modify the names of atoms in qapplication_x11.cpp as well! */ enum X11Atom { diff --git a/src/gui/styles/qcommonstyle.cpp b/src/gui/styles/qcommonstyle.cpp index ba28e753d..c7feb2507 100644 --- a/src/gui/styles/qcommonstyle.cpp +++ b/src/gui/styles/qcommonstyle.cpp @@ -63,7 +63,7 @@ #include #include #include -#include +#include <../kernel/qkde_p.h> #include #include #include @@ -842,12 +842,6 @@ static void drawArrow(const QStyle *style, const QStyleOptionToolButton *toolbut #ifdef Q_WS_X11 // These functions are used to parse the X11 freedesktop icon spec -static int kdeVersion() -{ - static int kdeVersion = qgetenv("KDE_SESSION_VERSION").toInt(); - return kdeVersion; -} - void QCommonStylePrivate::lookupIconTheme() const { if (!themeName.isEmpty()) @@ -856,7 +850,7 @@ void QCommonStylePrivate::lookupIconTheme() const QString dataDirs = QString::fromLocal8Bit(getenv("XDG_DATA_DIRS")); if (dataDirs.isEmpty()) dataDirs = QLatin1String("/usr/local/share/:/usr/share/"); - dataDirs += QLatin1Char(':') + QApplicationPrivate::kdeHome() + QLatin1String("/share"); + dataDirs += QLatin1Char(':') + QKde::kdeHome() + QLatin1String("/share"); dataDirs.prepend(QDir::homePath() + QLatin1String("/:")); QStringList kdeDirs = QString::fromLocal8Bit(getenv("KDEDIRS")).split(QLatin1Char(':'), QString::SkipEmptyParts); foreach (const QString &dirName, kdeDirs) @@ -865,9 +859,10 @@ void QCommonStylePrivate::lookupIconTheme() const QFileInfo fileInfo(QLatin1String("/usr/share/icons/default.kde")); QDir dir(fileInfo.canonicalFilePath()); - QString kdeDefault = kdeVersion() >= 4 ? QString::fromLatin1("oxygen") : QString::fromLatin1("crystalsvg"); + QString kdeDefault = (X11->desktopEnvironment != DE_KDE || X11->desktopVersion >= 4) + ? QString::fromLatin1("oxygen") : QString::fromLatin1("crystalsvg"); QString defaultTheme = fileInfo.exists() ? dir.dirName() : kdeDefault; - QSettings settings(QApplicationPrivate::kdeHome() + + QSettings settings(QKde::kdeHome() + QLatin1String("/share/config/kdeglobals"), QSettings::IniFormat); settings.beginGroup(QLatin1String("Icons")); themeName = settings.value(QLatin1String("Theme"), defaultTheme).toString(); @@ -979,8 +974,15 @@ QPixmap QCommonStylePrivate::findIconHelper(int size, return pixmap; } +/*! \internal + find a pixmap with the given size and name from the freedesktop theme. +*/ QPixmap QCommonStylePrivate::findIcon(int size, const QString &name) const { + QIcon icon = QKde::kdeIcon(name); + if (!icon.isNull()) + return icon.pixmap(size); + QPixmap pixmap; QString pixmapName = QLatin1String("$qt") + name + QString::number(size); @@ -995,12 +997,17 @@ QPixmap QCommonStylePrivate::findIcon(int size, const QString &name) const return pixmap; } +/*! \internal + create an Icon from the freedesktop theme. + */ QIcon QCommonStylePrivate::createIcon(const QString &name) const { - QIcon icon; - icon.addPixmap(findIcon(16, name)); - icon.addPixmap(findIcon(24, name)); - icon.addPixmap(findIcon(32, name)); + QIcon icon = QKde::kdeIcon(name); + if (icon.isNull()) { + icon.addPixmap(findIcon(16, name)); + icon.addPixmap(findIcon(24, name)); + icon.addPixmap(findIcon(32, name)); + } return icon; } /*!internal @@ -1012,8 +1019,8 @@ from the KDE configuration file int QCommonStylePrivate::lookupToolButtonStyle() const { int result = Qt::ToolButtonIconOnly; - if (kdeVersion() >= 4) { - QSettings settings(QApplicationPrivate::kdeHome() + + if (X11->desktopEnvironment == DE_KDE && X11->desktopVersion >= 4) { + QSettings settings(QKde::kdeHome() + QLatin1String("/share/config/kdeglobals"), QSettings::IniFormat); settings.beginGroup(QLatin1String("Toolbar style")); QString toolbarStyle = settings.value(QLatin1String("ToolButtonStyle"), QLatin1String("TextBesideIcon")).toString(); -- cgit v1.2.3 From 6993e77d2cd147098c6ddab187469a9177ea134e Mon Sep 17 00:00:00 2001 From: Kavindra Devi Palaraja Date: Fri, 7 Aug 2009 15:06:23 +0200 Subject: Doc - Improving the documentation for QListWidget and QListWidgetItem Reviewed-By: TrustMe --- src/gui/itemviews/qlistwidget.cpp | 446 +++++++++++++++++++------------------- 1 file changed, 228 insertions(+), 218 deletions(-) diff --git a/src/gui/itemviews/qlistwidget.cpp b/src/gui/itemviews/qlistwidget.cpp index 25656571b..63514963e 100644 --- a/src/gui/itemviews/qlistwidget.cpp +++ b/src/gui/itemviews/qlistwidget.cpp @@ -447,21 +447,20 @@ Qt::DropActions QListModel::supportedDropActions() const \ingroup model-view - QListWidgetItem is used to represent items in a list provided by the - QListWidget class. Each item can hold several pieces of information, - and will display these appropriately. + A QListWidgetItem represents a single item in a QListWidget. Each item can + hold several pieces of information, and will display them appropriately. - The item view convenience classes use a classic item-based interface - rather than a pure model/view approach. For a more flexible list view - widget, consider using the QListView class with a standard model. + The item view convenience classes use a classic item-based interface rather + than a pure model/view approach. For a more flexible list view widget, + consider using the QListView class with a standard model. - List items can be automatically inserted into a list when they are - constructed by specifying the list widget: + List items can be inserted automatically into a list, when they are + constructed, by specifying the list widget: \snippet doc/src/snippets/qlistwidget-using/mainwindow.cpp 2 - They can also be created without a parent widget, and later inserted into - a list (see \l{QListWidget::insertItem()}). + Alternatively, list items can also be created without a parent widget, and + later inserted into a list using QListWidget::insertItem(). List items are typically used to display text() and an icon(). These are set with the setText() and setIcon() functions. The appearance of the text @@ -471,22 +470,24 @@ Qt::DropActions QListModel::supportedDropActions() const with setToolTip(), setStatusTip(), and setWhatsThis(). By default, items are enabled, selectable, checkable, and can be the source - of a drag and drop operation. + of drag and drop operations. + Each item's flags can be changed by calling setFlags() with the appropriate - value (see \l{Qt::ItemFlags}). Checkable items can be checked, unchecked and + value (see Qt::ItemFlags). Checkable items can be checked, unchecked and partially checked with the setCheckState() function. The corresponding - checkState() function indicates what check state the item currently has. + checkState() function indicates the item's current check state. + + The isHidden() function can be used to determine whether the item is + hidden. To hide an item, use setHidden(). - The isHidden() function can be used to determine whether the - item is hidden. Items can be hidden with setHidden(). \section1 Subclassing When subclassing QListWidgetItem to provide custom items, it is possible to - define new types for them so that they can be distinguished from standard - items. The constructors for subclasses that require this feature need to - call the base class constructor with a new type value equal to or greater - than \l UserType. + define new types for them enabling them to be distinguished from standard + items. For subclasses that require this feature, ensure that you call the + base class constructor with a new type value equal to or greater than + \l UserType, within \e your constructor. \sa QListWidget, {Model/View Programming}, QTreeWidgetItem, QTableWidgetItem */ @@ -515,59 +516,58 @@ Qt::DropActions QListModel::supportedDropActions() const /*! \fn QListWidget *QListWidgetItem::listWidget() const - Returns the list widget that contains the item. + Returns the list widget containing the item. */ /*! - \fn void QListWidgetItem::setSelected(bool select) - \since 4.2 + \fn void QListWidgetItem::setSelected(bool select) + \since 4.2 - Sets the selected state of the item to \a select. + Sets the selected state of the item to \a select. - \sa isSelected() + \sa isSelected() */ /*! - \fn bool QListWidgetItem::isSelected() const - \since 4.2 + \fn bool QListWidgetItem::isSelected() const + \since 4.2 - Returns true if the item is selected, otherwise returns false. + Returns true if the item is selected; otherwise returns false. - \sa setSelected() + \sa setSelected() */ /*! - \fn void QListWidgetItem::setHidden(bool hide) - \since 4.2 + \fn void QListWidgetItem::setHidden(bool hide) + \since 4.2 - Hides the item if \a hide is true, otherwise shows the item. + Hides the item if \a hide is true; otherwise shows the item. - \sa isHidden() + \sa isHidden() */ /*! - \fn bool QListWidgetItem::isHidden() const - \since 4.2 + \fn bool QListWidgetItem::isHidden() const + \since 4.2 - Returns true if the item is hidden, otherwise returns false. + Returns true if the item is hidden; otherwise returns false. - \sa setHidden() + \sa setHidden() */ /*! \fn QListWidgetItem::QListWidgetItem(QListWidget *parent, int type) Constructs an empty list widget item of the specified \a type with the - given \a parent. - If the parent is not specified, the item will need to be inserted into a - list widget with QListWidget::insertItem(). + given \a parent. If \a parent is not specified, the item will need to be + inserted into a list widget with QListWidget::insertItem(). - \note that this constructor inserts this same object into the model of - the parent that is passed to the constructor. If the model is sorted then - the behavior of the insert is undetermined since the model will call - the '<' operator method on this object which has still not yet been - constructed. In this case it would be better not to specify the parent - and use the QListWidget::insertItem method to insert the item instead. + This constructor inserts the item into the model of the parent that is + passed to the constructor. If the model is sorted then the behavior of the + insert is undetermined since the model will call the \c '<' operator method + on the item which, at this point, is not yet constructed. To avoid the + undetermined behavior, we recommend not to specify the parent and use + QListWidget::insertItem() instead. \sa type() */ @@ -586,16 +586,15 @@ QListWidgetItem::QListWidgetItem(QListWidget *view, int type) \fn QListWidgetItem::QListWidgetItem(const QString &text, QListWidget *parent, int type) Constructs an empty list widget item of the specified \a type with the - given \a text and \a parent. - If the parent is not specified, the item will need to be inserted into a - list widget with QListWidget::insertItem(). + given \a text and \a parent. If the parent is not specified, the item will + need to be inserted into a list widget with QListWidget::insertItem(). - \note that this constructor inserts this same object into the model of - the parent that is passed to the constructor. If the model is sorted then - the behavior of the insert is undetermined since the model will call - the '<' operator method on this object which has still not yet been - constructed. In this case it would be better not to specify the parent - and use the QListWidget::insertItem method to insert the item instead. + This constructor inserts the item into the model of the parent that is + passed to the constructor. If the model is sorted then the behavior of the + insert is undetermined since the model will call the \c '<' operator method + on the item which, at this point, is not yet constructed. To avoid the + undetermined behavior, we recommend not to specify the parent and use + QListWidget::insertItem() instead. \sa type() */ @@ -616,16 +615,16 @@ QListWidgetItem::QListWidgetItem(const QString &text, QListWidget *view, int typ \fn QListWidgetItem::QListWidgetItem(const QIcon &icon, const QString &text, QListWidget *parent, int type) Constructs an empty list widget item of the specified \a type with the - given \a icon, \a text and \a parent. - If the parent is not specified, the item will need to be inserted into a - list widget with QListWidget::insertItem(). + given \a icon, \a text and \a parent. If the parent is not specified, the + item will need to be inserted into a list widget with + QListWidget::insertItem(). - \note that this constructor inserts this same object into the model of - the parent that is passed to the constructor. If the model is sorted then - the behavior of the insert is undetermined since the model will call - the '<' operator method on this object which has still not yet been - constructed. In this case it would be better not to specify the parent - and use the QListWidget::insertItem method to insert the item instead. + This constructor inserts the item into the model of the parent that is + passed to the constructor. If the model is sorted then the behavior of the + insert is undetermined since the model will call the \c '<' operator method + on the item which, at this point, is not yet constructed. To avoid the + undetermined behavior, we recommend not to specify the parent and use + QListWidget::insertItem() instead. \sa type() */ @@ -645,7 +644,7 @@ QListWidgetItem::QListWidgetItem(const QIcon &icon,const QString &text, } /*! - Destroys the list item. + Destroys the list item. */ QListWidgetItem::~QListWidgetItem() { @@ -655,7 +654,7 @@ QListWidgetItem::~QListWidgetItem() } /*! - Creates an exact copy of the item. + Creates an exact copy of the item. */ QListWidgetItem *QListWidgetItem::clone() const { @@ -663,11 +662,10 @@ QListWidgetItem *QListWidgetItem::clone() const } /*! - This function sets the data for a given \a role to the given \a value (see - \l{Qt::ItemDataRole}). Reimplement this function if you need - extra roles or special behavior for certain roles. + Sets the data for a given \a role to the given \a value. Reimplement this + function if you need extra roles or special behavior for certain roles. - \sa Qt::ItemDataRole, data() + \sa Qt::ItemDataRole, data() */ void QListWidgetItem::setData(int role, const QVariant &value) { @@ -689,9 +687,10 @@ void QListWidgetItem::setData(int role, const QVariant &value) } /*! - This function returns the item's data for a given \a role (see - Qt::ItemDataRole). Reimplement this function if you need - extra roles or special behavior for certain roles. + Returns the item's data for a given \a role. Reimplement this function if + you need extra roles or special behavior for certain roles. + + \sa Qt::ItemDataRole, setData() */ QVariant QListWidgetItem::data(int role) const { @@ -703,8 +702,8 @@ QVariant QListWidgetItem::data(int role) const } /*! - Returns true if this item's text is less then \a other item's text; - otherwise returns false. + Returns true if this item's text is less then \a other item's text; + otherwise returns false. */ bool QListWidgetItem::operator<(const QListWidgetItem &other) const { @@ -740,8 +739,8 @@ void QListWidgetItem::write(QDataStream &out) const /*! \since 4.1 - Constructs a copy of \a other. Note that type() and listWidget() - are not copied. + Constructs a copy of \a other. Note that type() and listWidget() are not + copied. This function is useful when reimplementing clone(). @@ -756,8 +755,8 @@ QListWidgetItem::QListWidgetItem(const QListWidgetItem &other) } /*! - Assigns \a other's data and flags to this item. Note that type() - and listWidget() are not copied. + Assigns \a other's data and flags to this item. Note that type() and + listWidget() are not copied. This function is useful when reimplementing clone(). @@ -805,9 +804,9 @@ QDataStream &operator>>(QDataStream &in, QListWidgetItem &item) #endif // QT_NO_DATASTREAM /*! - \fn Qt::ItemFlags QListWidgetItem::flags() const + \fn Qt::ItemFlags QListWidgetItem::flags() const - Returns the item flags for this item (see \l{Qt::ItemFlags}). + Returns the item flags for this item (see \l{Qt::ItemFlags}). */ /*! @@ -851,15 +850,17 @@ QDataStream &operator>>(QDataStream &in, QListWidgetItem &item) */ /*! - \fn QFont QListWidgetItem::font() const + \fn QFont QListWidgetItem::font() const - Returns the font used to display this list item's text. + Returns the font used to display this list item's text. */ /*! - \fn int QListWidgetItem::textAlignment() const + \fn int QListWidgetItem::textAlignment() const + + Returns the text alignment for the list item. - Returns the text alignment for the list item (see \l{Qt::AlignmentFlag}). + \sa Qt::AlignmentFlag */ /*! @@ -905,26 +906,26 @@ QDataStream &operator>>(QDataStream &in, QListWidgetItem &item) */ /*! - \fn QSize QListWidgetItem::sizeHint() const - \since 4.1 + \fn QSize QListWidgetItem::sizeHint() const + \since 4.1 - Returns the size hint set for the list item. + Returns the size hint set for the list item. */ /*! - \fn void QListWidgetItem::setSizeHint(const QSize &size) - \since 4.1 + \fn void QListWidgetItem::setSizeHint(const QSize &size) + \since 4.1 - Sets the size hint for the list item to be \a size. - If no size hint is set, the item delegate will compute the - size hint based on the item data. + Sets the size hint for the list item to be \a size. If no size hint is set, + the item delegate will compute the size hint based on the item data. */ /*! - \fn void QListWidgetItem::setFlags(Qt::ItemFlags flags) + \fn void QListWidgetItem::setFlags(Qt::ItemFlags flags) + + Sets the item flags for the list item to \a flags. - Sets the item flags for the list item to \a flags (see - \l{Qt::ItemFlags}). + \sa Qt::ItemFlags */ void QListWidgetItem::setFlags(Qt::ItemFlags aflags) { itemFlags = aflags; @@ -953,10 +954,10 @@ void QListWidgetItem::setFlags(Qt::ItemFlags aflags) { \fn void QListWidgetItem::setStatusTip(const QString &statusTip) Sets the status tip for the list item to the text specified by - \a statusTip. QListWidget mouse tracking needs to be enabled for this + \a statusTip. QListWidget mouseTracking needs to be enabled for this feature to work. - \sa statusTip() setToolTip() setWhatsThis() + \sa statusTip(), setToolTip(), setWhatsThis(), QWidget::setMouseTracking() */ /*! @@ -964,29 +965,30 @@ void QListWidgetItem::setFlags(Qt::ItemFlags aflags) { Sets the tooltip for the list item to the text specified by \a toolTip. - \sa toolTip() setStatusTip() setWhatsThis() + \sa toolTip(), setStatusTip(), setWhatsThis() */ /*! \fn void QListWidgetItem::setWhatsThis(const QString &whatsThis) - Sets the "What's This?" help for the list item to the text specified - by \a whatsThis. + Sets the "What's This?" help for the list item to the text specified by + \a whatsThis. - \sa whatsThis() setStatusTip() setToolTip() + \sa whatsThis(), setStatusTip(), setToolTip() */ /*! - \fn void QListWidgetItem::setFont(const QFont &font) + \fn void QListWidgetItem::setFont(const QFont &font) - Sets the font used when painting the item to the given \a font. + Sets the font used when painting the item to the given \a font. */ /*! - \fn void QListWidgetItem::setTextAlignment(int alignment) + \fn void QListWidgetItem::setTextAlignment(int alignment) + + Sets the list item's text alignment to \a alignment. - Sets the list item's text alignment to \a alignment (see - \l{Qt::AlignmentFlag}). + \sa Qt::AlignmentFlag */ /*! @@ -1127,10 +1129,10 @@ void QListWidgetPrivate::_q_dataChanged(const QModelIndex &topLeft, \ingroup model-view \mainclass - QListWidget is a convenience class that provides a list view similar to - the one supplied by QListView, but with a classic item-based interface - for adding and removing items. QListWidget uses an internal model to - manage each QListWidgetItem in the list. + QListWidget is a convenience class that provides a list view similar to the + one supplied by QListView, but with a classic item-based interface for + adding and removing items. QListWidget uses an internal model to manage + each QListWidgetItem in the list. For a more flexible list view widget, use the QListView class with a standard model. @@ -1145,23 +1147,23 @@ void QListWidgetPrivate::_q_dataChanged(const QModelIndex &topLeft, function. There are two ways to add items to the list: they can be constructed with - the list widget as their parent widget, or they can be constructed with - no parent widget and added to the list later. If a list widget already - exists when the items are constructed, the first method is easier to use: + the list widget as their parent widget, or they can be constructed with no + parent widget and added to the list later. If a list widget already exists + when the items are constructed, the first method is easier to use: \snippet doc/src/snippets/qlistwidget-using/mainwindow.cpp 1 - If you need to insert a new item into the list at a particular position, - it is more required to construct the item without a parent widget and - use the insertItem() function to place it within the list. The list - widget will take ownership of the item. + If you need to insert a new item into the list at a particular position, it + is more required to construct the item without a parent widget and use the + insertItem() function to place it within the list. The list widget will + take ownership of the item. \snippet doc/src/snippets/qlistwidget-using/mainwindow.cpp 6 \snippet doc/src/snippets/qlistwidget-using/mainwindow.cpp 7 - For multiple items, insertItems() can be used instead. The number of - items in the list is found with the count() function. - To remove items from the list, use takeItem(). + For multiple items, insertItems() can be used instead. The number of items + in the list is found with the count() function. To remove items from the + list, use takeItem(). The current item in the list can be found with currentItem(), and changed with setCurrentItem(). The user can also change the current item by @@ -1187,9 +1189,9 @@ void QListWidgetPrivate::_q_dataChanged(const QModelIndex &topLeft, Inserts the \a item at the end of the list widget. - \warning A QListWidgetItem can only be added to a - QListWidget once. Adding the same QListWidgetItem multiple - times to a QListWidget will result in undefined behavior. + \warning A QListWidgetItem can only be added to a QListWidget once. Adding + the same QListWidgetItem multiple times to a QListWidget will result in + undefined behavior. \sa insertItem() */ @@ -1197,8 +1199,7 @@ void QListWidgetPrivate::_q_dataChanged(const QModelIndex &topLeft, /*! \fn void QListWidget::addItem(const QString &label) - Inserts an item with the text \a label at the end of the list - widget. + Inserts an item with the text \a label at the end of the list widget. */ /*! @@ -1212,8 +1213,8 @@ void QListWidgetPrivate::_q_dataChanged(const QModelIndex &topLeft, /*! \fn void QListWidget::itemPressed(QListWidgetItem *item) - This signal is emitted with the specified \a item when a mouse button is pressed - on an item in the widget. + This signal is emitted with the specified \a item when a mouse button is + pressed on an item in the widget. \sa itemClicked(), itemDoubleClicked() */ @@ -1221,8 +1222,8 @@ void QListWidgetPrivate::_q_dataChanged(const QModelIndex &topLeft, /*! \fn void QListWidget::itemClicked(QListWidgetItem *item) - This signal is emitted with the specified \a item when a mouse button is clicked - on an item in the widget. + This signal is emitted with the specified \a item when a mouse button is + clicked on an item in the widget. \sa itemPressed(), itemDoubleClicked() */ @@ -1230,8 +1231,8 @@ void QListWidgetPrivate::_q_dataChanged(const QModelIndex &topLeft, /*! \fn void QListWidget::itemDoubleClicked(QListWidgetItem *item) - This signal is emitted with the specified \a item when a mouse button is double - clicked on an item in the widget. + This signal is emitted with the specified \a item when a mouse button is + double clicked on an item in the widget. \sa itemClicked(), itemPressed() */ @@ -1239,20 +1240,21 @@ void QListWidgetPrivate::_q_dataChanged(const QModelIndex &topLeft, /*! \fn void QListWidget::itemActivated(QListWidgetItem *item) - This signal is emitted when the \a item is activated. The \a item - is activated when the user clicks or double clicks on it, - depending on the system configuration. It is also activated when - the user presses the activation key (on Windows and X11 this is - the \gui Return key, on Mac OS X it is \key{Ctrl+0}). + This signal is emitted when the \a item is activated. The \a item is + activated when the user clicks or double clicks on it, depending on the + system configuration. It is also activated when the user presses the + activation key (on Windows and X11 this is the \gui Return key, on Mac OS + X it is \key{Ctrl+0}). */ /*! \fn void QListWidget::itemEntered(QListWidgetItem *item) - This signal is emitted when the mouse cursor enters an item. The - \a item is the item entered. This signal is only emitted when - mouseTracking is turned on, or when a mouse button is pressed - while moving into an item. + This signal is emitted when the mouse cursor enters an item. The \a item is + the item entered. This signal is only emitted when mouseTracking is turned + on, or when a mouse button is pressed while moving into an item. + + \sa QWidget::setMouseTracking() */ /*! @@ -1264,24 +1266,28 @@ void QListWidgetPrivate::_q_dataChanged(const QModelIndex &topLeft, /*! \fn void QListWidget::currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous) - This signal is emitted whenever the current item changes. The \a - previous item is the item that previously had the focus, \a - current is the new current item. + This signal is emitted whenever the current item changes. + + \a previous is the item that previously had the focus; \a current is the + new current item. */ /*! - \fn void QListWidget::currentTextChanged(const QString ¤tText) + \fn void QListWidget::currentTextChanged(const QString ¤tText) - This signal is emitted whenever the current item changes. The \a currentText - is the text data in the current item. If there is no current item, the \a currentText - is invalid. + This signal is emitted whenever the current item changes. + + \a currentText is the text data in the current item. If there is no current + item, the \a currentText is invalid. */ /*! - \fn void QListWidget::currentRowChanged(int currentRow) + \fn void QListWidget::currentRowChanged(int currentRow) - This signal is emitted whenever the current item changes. The \a currentRow - is the row of the current item. If there is no current item, the \a currentRow is -1. + This signal is emitted whenever the current item changes. + + \a currentRow is the row of the current item. If there is no current item, + the \a currentRow is -1. */ /*! @@ -1289,15 +1295,15 @@ void QListWidgetPrivate::_q_dataChanged(const QModelIndex &topLeft, This signal is emitted whenever the selection changes. - \sa selectedItems() QListWidgetItem::isSelected() currentItemChanged() + \sa selectedItems(), QListWidgetItem::isSelected(), currentItemChanged() */ /*! - \since 4.3 + \since 4.3 - \fn void QListWidget::removeItemWidget(QListWidgetItem *item) + \fn void QListWidget::removeItemWidget(QListWidgetItem *item) - Removes the widget set on the given \a item. + Removes the widget set on the given \a item. */ /*! @@ -1361,8 +1367,8 @@ void QListWidget::insertItem(int row, QListWidgetItem *item) } /*! - Inserts an item with the text \a label in the list widget at the - position given by \a row. + Inserts an item with the text \a label in the list widget at the position + given by \a row. \sa addItem() */ @@ -1387,11 +1393,11 @@ void QListWidget::insertItems(int row, const QStringList &labels) } /*! - Removes and returns the item from the given \a row in the list widget; otherwise - returns 0. + Removes and returns the item from the given \a row in the list widget; + otherwise returns 0. - Items removed from a list widget will not be managed by Qt, and will need to be - deleted manually. + Items removed from a list widget will not be managed by Qt, and will need + to be deleted manually. \sa insertItem(), addItem() */ @@ -1405,8 +1411,8 @@ QListWidgetItem *QListWidget::takeItem(int row) } /*! - \property QListWidget::count - \brief the number of items in the list including any hidden items. + \property QListWidget::count + \brief the number of items in the list including any hidden items. */ int QListWidget::count() const @@ -1416,7 +1422,7 @@ int QListWidget::count() const } /*! - Returns the current item. + Returns the current item. */ QListWidgetItem *QListWidget::currentItem() const { @@ -1426,9 +1432,9 @@ QListWidgetItem *QListWidget::currentItem() const /*! - Sets the current item to \a item. + Sets the current item to \a item. - Depending on the current selection mode, the item may also be selected. + Depending on the current selection mode, the item may also be selected. */ void QListWidget::setCurrentItem(QListWidgetItem *item) { @@ -1436,8 +1442,8 @@ void QListWidget::setCurrentItem(QListWidgetItem *item) } /*! - \since 4.4 - Set the current item to \a item, using the given \a command. + \since 4.4 + Set the current item to \a item, using the given \a command. */ void QListWidget::setCurrentItem(QListWidgetItem *item, QItemSelectionModel::SelectionFlags command) { @@ -1445,10 +1451,10 @@ void QListWidget::setCurrentItem(QListWidgetItem *item, QItemSelectionModel::Sel } /*! - \property QListWidget::currentRow - \brief the row of the current item. + \property QListWidget::currentRow + \brief the row of the current item. - Depending on the current selection mode, the row may also be selected. + Depending on the current selection mode, the row may also be selected. */ int QListWidget::currentRow() const @@ -1469,9 +1475,9 @@ void QListWidget::setCurrentRow(int row) } /*! - \since 4.4 + \since 4.4 - Sets the current row to be the given \a row, using the given \a command, + Sets the current row to be the given \a row, using the given \a command, */ void QListWidget::setCurrentRow(int row, QItemSelectionModel::SelectionFlags command) { @@ -1498,7 +1504,7 @@ QListWidgetItem *QListWidget::itemAt(const QPoint &p) const /*! - Returns the rectangle on the viewport occupied by the item at \a item. + Returns the rectangle on the viewport occupied by the item at \a item. */ QRect QListWidget::visualItemRect(const QListWidgetItem *item) const { @@ -1508,7 +1514,7 @@ QRect QListWidget::visualItemRect(const QListWidgetItem *item) const } /*! - Sorts all the items in the list widget according to the specified \a order. + Sorts all the items in the list widget according to the specified \a order. */ void QListWidget::sortItems(Qt::SortOrder order) { @@ -1522,8 +1528,10 @@ void QListWidget::sortItems(Qt::SortOrder order) \property QListWidget::sortingEnabled \brief whether sorting is enabled - If this property is true, sorting is enabled for the list; if the - property is false, sorting is not enabled. The default value is false. + If this property is true, sorting is enabled for the list; if the property + is false, sorting is not enabled. + + The default value is false. */ void QListWidget::setSortingEnabled(bool enable) { @@ -1538,7 +1546,7 @@ bool QListWidget::isSortingEnabled() const } /*! - \internal + \internal */ Qt::SortOrder QListWidget::sortOrder() const { @@ -1547,7 +1555,7 @@ Qt::SortOrder QListWidget::sortOrder() const } /*! - Starts editing the \a item if it is editable. + Starts editing the \a item if it is editable. */ void QListWidget::editItem(QListWidgetItem *item) @@ -1557,9 +1565,10 @@ void QListWidget::editItem(QListWidgetItem *item) } /*! - Opens an editor for the given \a item. The editor remains open after editing. + Opens an editor for the given \a item. The editor remains open after + editing. - \sa closePersistentEditor() + \sa closePersistentEditor() */ void QListWidget::openPersistentEditor(QListWidgetItem *item) { @@ -1569,9 +1578,9 @@ void QListWidget::openPersistentEditor(QListWidgetItem *item) } /*! - Closes the persistent editor for the given \a item. + Closes the persistent editor for the given \a item. - \sa openPersistentEditor() + \sa openPersistentEditor() */ void QListWidget::closePersistentEditor(QListWidgetItem *item) { @@ -1597,9 +1606,10 @@ QWidget *QListWidget::itemWidget(QListWidgetItem *item) const Sets the \a widget to be displayed in the give \a item. - This function should only be used to display static content in the place of a list - widget item. If you want to display custom dynamic content or implement a custom - editor widget, use QListView and subclass QItemDelegate instead. + This function should only be used to display static content in the place of + a list widget item. If you want to display custom dynamic content or + implement a custom editor widget, use QListView and subclass QItemDelegate + instead. \sa {Delegate Classes} */ @@ -1611,11 +1621,11 @@ void QListWidget::setItemWidget(QListWidgetItem *item, QWidget *widget) } /*! - Returns true if \a item is selected; otherwise returns false. + Returns true if \a item is selected; otherwise returns false. - \obsolete + \obsolete - This function is deprecated. Use \l{QListWidgetItem::isSelected()} instead. + This function is deprecated. Use QListWidgetItem::isSelected() instead. */ bool QListWidget::isItemSelected(const QListWidgetItem *item) const { @@ -1625,12 +1635,12 @@ bool QListWidget::isItemSelected(const QListWidgetItem *item) const } /*! - Selects or deselects the given \a item depending on whether \a select is - true of false. + Selects or deselects the given \a item depending on whether \a select is + true of false. - \obsolete + \obsolete - This function is deprecated. Use \l{QListWidgetItem::setSelected()} instead. + This function is deprecated. Use QListWidgetItem::setSelected() instead. */ void QListWidget::setItemSelected(const QListWidgetItem *item, bool select) { @@ -1650,7 +1660,7 @@ void QListWidget::setItemSelected(const QListWidgetItem *item, bool select) } /*! - Returns a list of all selected items in the list widget. + Returns a list of all selected items in the list widget. */ QList QListWidget::selectedItems() const @@ -1664,7 +1674,8 @@ QList QListWidget::selectedItems() const } /*! - Finds items with the text that matches the string \a text using the given \a flags. + Finds items with the text that matches the string \a text using the given + \a flags. */ QList QListWidget::findItems(const QString &text, Qt::MatchFlags flags) const @@ -1679,11 +1690,11 @@ QList QListWidget::findItems(const QString &text, Qt::MatchFla } /*! - Returns true if the \a item is explicitly hidden; otherwise returns false. + Returns true if the \a item is explicitly hidden; otherwise returns false. - \obsolete + \obsolete - This function is deprecated. Use \l{QListWidgetItem::isHidden()} instead. + This function is deprecated. Use QListWidgetItem::isHidden() instead. */ bool QListWidget::isItemHidden(const QListWidgetItem *item) const { @@ -1691,11 +1702,11 @@ bool QListWidget::isItemHidden(const QListWidgetItem *item) const } /*! - If \a hide is true, the \a item will be hidden; otherwise it will be shown. + If \a hide is true, the \a item will be hidden; otherwise it will be shown. - \obsolete + \obsolete - This function is deprecated. Use \l{QListWidgetItem::setHidden()} instead. + This function is deprecated. Use QListWidgetItem::setHidden() instead. */ void QListWidget::setItemHidden(const QListWidgetItem *item, bool hide) { @@ -1703,9 +1714,9 @@ void QListWidget::setItemHidden(const QListWidgetItem *item, bool hide) } /*! - Scrolls the view if necessary to ensure that the \a item is - visible. The \a hint parameter specifies more precisely where the - \a item should be located after the operation. + Scrolls the view if necessary to ensure that the \a item is visible. + + \a hint specifies where the \a item should be located after the operation. */ void QListWidget::scrollToItem(const QListWidgetItem *item, QAbstractItemView::ScrollHint hint) @@ -1718,7 +1729,7 @@ void QListWidget::scrollToItem(const QListWidgetItem *item, QAbstractItemView::S /*! Removes all items and selections in the view. - \note All items will be permanently deleted. + \warning All items will be permanently deleted. */ void QListWidget::clear() { @@ -1743,8 +1754,8 @@ QStringList QListWidget::mimeTypes() const \a items. The format used to describe the items is obtained from the mimeTypes() function. - If the list of items is empty, 0 is returned rather than a serialized - empty list. + If the list of items is empty, 0 is returned instead of a serialized empty + list. */ QMimeData *QListWidget::mimeData(const QList) const { @@ -1753,10 +1764,9 @@ QMimeData *QListWidget::mimeData(const QList) const #ifndef QT_NO_DRAGANDDROP /*! - Handles the \a data supplied by an external drag and drop operation - that ended with the given \a action in the given \a index. - Returns true if the data and action can be handled by the model; - otherwise returns false. + Handles \a data supplied by an external drag and drop operation that ended + with the given \a action in the given \a index. Returns true if \a data and + \a action can be handled by the model; otherwise returns false. \sa supportedDropActions() */ @@ -1823,9 +1833,9 @@ void QListWidget::dropEvent(QDropEvent *event) { } /*! - Returns the drop actions supported by this view. + Returns the drop actions supported by this view. - \sa Qt::DropActions + \sa Qt::DropActions */ Qt::DropActions QListWidget::supportedDropActions() const { @@ -1835,9 +1845,9 @@ Qt::DropActions QListWidget::supportedDropActions() const #endif // QT_NO_DRAGANDDROP /*! - Returns a list of pointers to the items contained in the \a data object. - If the object was not created by a QListWidget in the same process, the list - is empty. + Returns a list of pointers to the items contained in the \a data object. If + the object was not created by a QListWidget in the same process, the list + is empty. */ QList QListWidget::items(const QMimeData *data) const { @@ -1848,7 +1858,7 @@ QList QListWidget::items(const QMimeData *data) const } /*! - Returns the QModelIndex assocated with the given \a item. + Returns the QModelIndex assocated with the given \a item. */ QModelIndex QListWidget::indexFromItem(QListWidgetItem *item) const @@ -1858,7 +1868,7 @@ QModelIndex QListWidget::indexFromItem(QListWidgetItem *item) const } /*! - Returns a pointer to the QListWidgetItem assocated with the given \a index. + Returns a pointer to the QListWidgetItem assocated with the given \a index. */ QListWidgetItem *QListWidget::itemFromIndex(const QModelIndex &index) const @@ -1870,7 +1880,7 @@ QListWidgetItem *QListWidget::itemFromIndex(const QModelIndex &index) const } /*! - \internal + \internal */ void QListWidget::setModel(QAbstractItemModel * /*model*/) { -- cgit v1.2.3 From 658c30c214070e8ff05ddaf1cb7b161c1b73f5ce Mon Sep 17 00:00:00 2001 From: Kavindra Devi Palaraja Date: Fri, 7 Aug 2009 15:09:30 +0200 Subject: Doc - Removing trailing whitespaces Reviewed-By: TrustMe --- src/gui/itemviews/qlistwidget.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/gui/itemviews/qlistwidget.cpp b/src/gui/itemviews/qlistwidget.cpp index 63514963e..b518ff297 100644 --- a/src/gui/itemviews/qlistwidget.cpp +++ b/src/gui/itemviews/qlistwidget.cpp @@ -561,7 +561,7 @@ Qt::DropActions QListModel::supportedDropActions() const Constructs an empty list widget item of the specified \a type with the given \a parent. If \a parent is not specified, the item will need to be inserted into a list widget with QListWidget::insertItem(). - + This constructor inserts the item into the model of the parent that is passed to the constructor. If the model is sorted then the behavior of the insert is undetermined since the model will call the \c '<' operator method @@ -588,7 +588,7 @@ QListWidgetItem::QListWidgetItem(QListWidget *view, int type) Constructs an empty list widget item of the specified \a type with the given \a text and \a parent. If the parent is not specified, the item will need to be inserted into a list widget with QListWidget::insertItem(). - + This constructor inserts the item into the model of the parent that is passed to the constructor. If the model is sorted then the behavior of the insert is undetermined since the model will call the \c '<' operator method @@ -618,14 +618,14 @@ QListWidgetItem::QListWidgetItem(const QString &text, QListWidget *view, int typ given \a icon, \a text and \a parent. If the parent is not specified, the item will need to be inserted into a list widget with QListWidget::insertItem(). - + This constructor inserts the item into the model of the parent that is passed to the constructor. If the model is sorted then the behavior of the insert is undetermined since the model will call the \c '<' operator method on the item which, at this point, is not yet constructed. To avoid the undetermined behavior, we recommend not to specify the parent and use QListWidget::insertItem() instead. - + \sa type() */ QListWidgetItem::QListWidgetItem(const QIcon &icon,const QString &text, @@ -1267,7 +1267,7 @@ void QListWidgetPrivate::_q_dataChanged(const QModelIndex &topLeft, \fn void QListWidget::currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous) This signal is emitted whenever the current item changes. - + \a previous is the item that previously had the focus; \a current is the new current item. */ @@ -1276,7 +1276,7 @@ void QListWidgetPrivate::_q_dataChanged(const QModelIndex &topLeft, \fn void QListWidget::currentTextChanged(const QString ¤tText) This signal is emitted whenever the current item changes. - + \a currentText is the text data in the current item. If there is no current item, the \a currentText is invalid. */ @@ -1285,7 +1285,7 @@ void QListWidgetPrivate::_q_dataChanged(const QModelIndex &topLeft, \fn void QListWidget::currentRowChanged(int currentRow) This signal is emitted whenever the current item changes. - + \a currentRow is the row of the current item. If there is no current item, the \a currentRow is -1. */ -- cgit v1.2.3 From dfa284220498a1e32ab3133f203bcb41cfa136b7 Mon Sep 17 00:00:00 2001 From: Harald Fernengel Date: Fri, 7 Aug 2009 15:08:09 +0200 Subject: Refactor QTestCharBuffer a bit Use a static buffer for small strings, and making it oom safe. We can now see messages up to 512 bytes even if we run out of memory (important for OOM tests). Also, testlogging (< 512 bytes per line) should again work without a single allocation. Reviewed-By: Rohan McGovern --- src/testlib/qabstracttestlogger.cpp | 47 ++++++++++++++++++++++ src/testlib/qabstracttestlogger_p.h | 52 +++++++++++++++++++----- src/testlib/qplaintestlogger.cpp | 10 ++--- src/testlib/qtest_global.h | 1 - src/testlib/qtestbasicstreamer.cpp | 40 +++++++++---------- src/testlib/qtestbasicstreamer.h | 11 ++--- src/testlib/qtestcase.cpp | 37 ----------------- src/testlib/qtestlightxmlstreamer.cpp | 70 ++++++++++++++++---------------- src/testlib/qtestlightxmlstreamer.h | 6 +-- src/testlib/qtestxmlstreamer.cpp | 61 ++++++++++++++-------------- src/testlib/qtestxmlstreamer.h | 6 +-- src/testlib/qtestxunitstreamer.cpp | 43 ++++++++++---------- src/testlib/qtestxunitstreamer.h | 8 ++-- src/testlib/qxmltestlogger.cpp | 75 ++++++++++++++++++----------------- src/testlib/qxmltestlogger_p.h | 8 ++-- 15 files changed, 257 insertions(+), 218 deletions(-) diff --git a/src/testlib/qabstracttestlogger.cpp b/src/testlib/qabstracttestlogger.cpp index 6482ec9b8..2fa535ed1 100644 --- a/src/testlib/qabstracttestlogger.cpp +++ b/src/testlib/qabstracttestlogger.cpp @@ -43,8 +43,11 @@ #include "QtTest/private/qtestlog_p.h" #include "QtTest/qtestassert.h" +#include "QtCore/qbytearray.h" + #include #include +#include #ifndef Q_OS_WIN #include @@ -106,4 +109,48 @@ void QAbstractTestLogger::stopLogging() QTest::stream = 0; } +namespace QTest +{ + +extern void filter_unprintable(char *str); + +/*! \internal + */ +int qt_asprintf(QTestCharBuffer *str, const char *format, ...) +{ + static const int MAXSIZE = 1024*1024*2; + + Q_ASSERT(str); + + int size = str->size(); + + va_list ap; + int res = 0; + + for (;;) { + va_start(ap, format); + res = qvsnprintf(str->data(), size, format, ap); + va_end(ap); + str->data()[size - 1] = '\0'; + if (res >= 0 && res < size) { + // We succeeded + break; + } + // buffer wasn't big enough, try again. + // Note, we're assuming that a result of -1 is always due to running out of space. + size *= 2; + if (size > MAXSIZE) { + break; + } + if (!str->reset(size)) + break; // out of memory - take what we have + } + + filter_unprintable(str->data()); + + return res; +} + +} + QT_END_NAMESPACE diff --git a/src/testlib/qabstracttestlogger_p.h b/src/testlib/qabstracttestlogger_p.h index 588184e45..183408669 100644 --- a/src/testlib/qabstracttestlogger_p.h +++ b/src/testlib/qabstracttestlogger_p.h @@ -101,27 +101,26 @@ public: struct QTestCharBuffer { - inline QTestCharBuffer() - : buf(0) - {} + enum { InitialSize = 512 }; - inline ~QTestCharBuffer() + inline QTestCharBuffer() + : _size(InitialSize), buf(staticBuf) { - delete[] buf; - buf = 0; + staticBuf[0] = '\0'; } - inline operator void*() + inline ~QTestCharBuffer() { - return buf; + if (buf != staticBuf) + qFree(buf); } - inline operator char*() + inline char *data() { return buf; } - inline operator char**() + inline char **buffer() { return &buf; } @@ -131,10 +130,43 @@ struct QTestCharBuffer return buf; } + inline int size() const + { + return _size; + } + + inline bool reset(int newSize) + { + char *newBuf = 0; + if (buf == staticBuf) { + // if we point to our internal buffer, we need to malloc first + newBuf = reinterpret_cast(qMalloc(newSize)); + } else { + // if we already malloc'ed, just realloc + newBuf = reinterpret_cast(qRealloc(buf, newSize)); + } + + // if the allocation went wrong (newBuf == 0), we leave the object as is + if (!newBuf) + return false; + + _size = newSize; + buf = newBuf; + return true; + } + private: + int _size; char* buf; + char staticBuf[InitialSize]; }; +namespace QTest +{ + int qt_asprintf(QTestCharBuffer *buf, const char *format, ...); +} + + QT_END_NAMESPACE #endif diff --git a/src/testlib/qplaintestlogger.cpp b/src/testlib/qplaintestlogger.cpp index e075b36da..2515c51ed 100644 --- a/src/testlib/qplaintestlogger.cpp +++ b/src/testlib/qplaintestlogger.cpp @@ -180,7 +180,7 @@ namespace QTest { : ""; const char *filler = (tag[0] && gtag[0]) ? ":" : ""; if (file) { - QTest::qt_asprintf(buf, "%s: %s::%s(%s%s%s)%s%s\n" + QTest::qt_asprintf(&buf, "%s: %s::%s(%s%s%s)%s%s\n" #ifdef Q_OS_WIN "%s(%d) : failure location\n" #else @@ -189,14 +189,14 @@ namespace QTest { , type, QTestResult::currentTestObjectName(), fn, gtag, filler, tag, msg[0] ? " " : "", msg, file, line); } else { - QTest::qt_asprintf(buf, "%s: %s::%s(%s%s%s)%s%s\n", + QTest::qt_asprintf(&buf, "%s: %s::%s(%s%s%s)%s%s\n", type, QTestResult::currentTestObjectName(), fn, gtag, filler, tag, msg[0] ? " " : "", msg); } // In colored mode, printf above stripped our nonprintable control characters. // Put them back. - memcpy(buf, type, strlen(type)); - outputMessage(buf); + memcpy(buf.data(), type, strlen(type)); + outputMessage(buf.data()); } template @@ -207,7 +207,7 @@ namespace QTest { int digits = 0; qreal divisor = 1; - + while (num / divisor >= 1) { divisor *= 10; ++digits; diff --git a/src/testlib/qtest_global.h b/src/testlib/qtest_global.h index c40f0adc3..b5b0fc054 100644 --- a/src/testlib/qtest_global.h +++ b/src/testlib/qtest_global.h @@ -82,7 +82,6 @@ namespace QTest enum TestFailMode { Abort = 1, Continue = 2 }; int Q_TESTLIB_EXPORT qt_snprintf(char *str, int size, const char *format, ...); - int qt_asprintf(char **str, const char *format, ...); } QT_END_NAMESPACE diff --git a/src/testlib/qtestbasicstreamer.cpp b/src/testlib/qtestbasicstreamer.cpp index aac57bad8..89de7d87b 100644 --- a/src/testlib/qtestbasicstreamer.cpp +++ b/src/testlib/qtestbasicstreamer.cpp @@ -68,39 +68,39 @@ QTestBasicStreamer::QTestBasicStreamer() QTestBasicStreamer::~QTestBasicStreamer() {} -void QTestBasicStreamer::formatStart(const QTestElement *element, char **formatted) const +void QTestBasicStreamer::formatStart(const QTestElement *element, QTestCharBuffer *formatted) const { if(!element || !formatted ) return; - QTest::qt_asprintf(formatted, ""); + formatted->data()[0] = '\0'; } -void QTestBasicStreamer::formatEnd(const QTestElement *element, char **formatted) const +void QTestBasicStreamer::formatEnd(const QTestElement *element, QTestCharBuffer *formatted) const { if(!element || !formatted ) return; - QTest::qt_asprintf(formatted, ""); + formatted->data()[0] = '\0'; } -void QTestBasicStreamer::formatBeforeAttributes(const QTestElement *element, char **formatted) const +void QTestBasicStreamer::formatBeforeAttributes(const QTestElement *element, QTestCharBuffer *formatted) const { if(!element || !formatted ) return; - QTest::qt_asprintf(formatted, ""); + formatted->data()[0] = '\0'; } -void QTestBasicStreamer::formatAfterAttributes(const QTestElement *element, char **formatted) const +void QTestBasicStreamer::formatAfterAttributes(const QTestElement *element, QTestCharBuffer *formatted) const { if(!element || !formatted ) return; - QTest::qt_asprintf(formatted, ""); + formatted->data()[0] = '\0'; } -void QTestBasicStreamer::formatAttributes(const QTestElement *, const QTestElementAttribute *attribute, char **formatted) const +void QTestBasicStreamer::formatAttributes(const QTestElement *, const QTestElementAttribute *attribute, QTestCharBuffer *formatted) const { if(!attribute || !formatted ) return; - QTest::qt_asprintf(formatted, ""); + formatted->data()[0] = '\0'; } void QTestBasicStreamer::output(QTestElement *element) const @@ -125,22 +125,22 @@ void QTestBasicStreamer::outputElements(QTestElement *element, bool) const while (element) { hasChildren = element->childElements(); - formatStart(element, buf); - outputString(buf); + formatStart(element, &buf); + outputString(buf.data()); - formatBeforeAttributes(element, buf); - outputString(buf); + formatBeforeAttributes(element, &buf); + outputString(buf.data()); outputElementAttributes(element, element->attributes()); - formatAfterAttributes(element, buf); - outputString(buf); + formatAfterAttributes(element, &buf); + outputString(buf.data()); if(hasChildren) outputElements(element->childElements(), true); - formatEnd(element, buf); - outputString(buf); + formatEnd(element, &buf); + outputString(buf.data()); element = element->previousElement(); } @@ -150,8 +150,8 @@ void QTestBasicStreamer::outputElementAttributes(const QTestElement* element, QT { QTestCharBuffer buf; while(attribute){ - formatAttributes(element, attribute, buf); - outputString(buf); + formatAttributes(element, attribute, &buf); + outputString(buf.data()); attribute = attribute->nextElement(); } } diff --git a/src/testlib/qtestbasicstreamer.h b/src/testlib/qtestbasicstreamer.h index 432dd223a..cabbf3498 100644 --- a/src/testlib/qtestbasicstreamer.h +++ b/src/testlib/qtestbasicstreamer.h @@ -53,6 +53,7 @@ QT_MODULE(Test) class QTestElement; class QTestElementAttribute; class QTestLogger; +class QTestCharBuffer; class QTestBasicStreamer { @@ -71,11 +72,11 @@ class QTestBasicStreamer const QTestLogger *logger() const; protected: - virtual void formatStart(const QTestElement *element, char **formatted) const; - virtual void formatEnd(const QTestElement *element, char **formatted) const; - virtual void formatBeforeAttributes(const QTestElement *element, char **formatted) const; - virtual void formatAfterAttributes(const QTestElement *element, char **formatted) const; - virtual void formatAttributes(const QTestElement *element, const QTestElementAttribute *attribute, char **formatted) const; + virtual void formatStart(const QTestElement *element, QTestCharBuffer *formatted) const; + virtual void formatEnd(const QTestElement *element, QTestCharBuffer *formatted) const; + virtual void formatBeforeAttributes(const QTestElement *element, QTestCharBuffer *formatted) const; + virtual void formatAfterAttributes(const QTestElement *element, QTestCharBuffer *formatted) const; + virtual void formatAttributes(const QTestElement *element, const QTestElementAttribute *attribute, QTestCharBuffer *formatted) const; virtual void outputElements(QTestElement *element, bool isChildElement = false) const; virtual void outputElementAttributes(const QTestElement *element, QTestElementAttribute *attribute) const; diff --git a/src/testlib/qtestcase.cpp b/src/testlib/qtestcase.cpp index ac4ca830c..1866197d7 100644 --- a/src/testlib/qtestcase.cpp +++ b/src/testlib/qtestcase.cpp @@ -818,43 +818,6 @@ void filter_unprintable(char *str) } } -/*! \internal - */ -int qt_asprintf(char **str, const char *format, ...) -{ - static const int MAXSIZE = 1024*1024*2; - - int size = 32; - delete[] *str; - *str = new char[size]; - - va_list ap; - int res = 0; - - for (;;) { - va_start(ap, format); - res = qvsnprintf(*str, size, format, ap); - va_end(ap); - (*str)[size - 1] = '\0'; - if (res >= 0 && res < size) { - // We succeeded - break; - } - // buffer wasn't big enough, try again. - // Note, we're assuming that a result of -1 is always due to running out of space. - size *= 2; - if (size > MAXSIZE) { - break; - } - delete[] *str; - *str = new char[size]; - } - - filter_unprintable(*str); - - return res; -} - /*! \internal */ int qt_snprintf(char *str, int size, const char *format, ...) diff --git a/src/testlib/qtestlightxmlstreamer.cpp b/src/testlib/qtestlightxmlstreamer.cpp index e17620124..b84f531ad 100644 --- a/src/testlib/qtestlightxmlstreamer.cpp +++ b/src/testlib/qtestlightxmlstreamer.cpp @@ -59,7 +59,7 @@ QTestLightXmlStreamer::QTestLightXmlStreamer() QTestLightXmlStreamer::~QTestLightXmlStreamer() {} -void QTestLightXmlStreamer::formatStart(const QTestElement *element, char **formatted) const +void QTestLightXmlStreamer::formatStart(const QTestElement *element, QTestCharBuffer *formatted) const { if(!element || !formatted) return; @@ -67,14 +67,14 @@ void QTestLightXmlStreamer::formatStart(const QTestElement *element, char **form switch(element->elementType()){ case QTest::LET_TestCase: { QTestCharBuffer quotedTf; - QXmlTestLogger::xmlQuote(quotedTf, element->attributeValue(QTest::AI_Name)); + QXmlTestLogger::xmlQuote("edTf, element->attributeValue(QTest::AI_Name)); QTest::qt_asprintf(formatted, "\n", quotedTf.constData()); break; } case QTest::LET_Failure: { QTestCharBuffer cdataDesc; - QXmlTestLogger::xmlCdata(cdataDesc, element->attributeValue(QTest::AI_Description)); + QXmlTestLogger::xmlCdata(&cdataDesc, element->attributeValue(QTest::AI_Description)); QTest::qt_asprintf(formatted, " \n", cdataDesc.constData()); @@ -84,8 +84,8 @@ void QTestLightXmlStreamer::formatStart(const QTestElement *element, char **form // assuming type and attribute names don't need quoting QTestCharBuffer quotedFile; QTestCharBuffer cdataDesc; - QXmlTestLogger::xmlQuote(quotedFile, element->attributeValue(QTest::AI_File)); - QXmlTestLogger::xmlCdata(cdataDesc, element->attributeValue(QTest::AI_Description)); + QXmlTestLogger::xmlQuote("edFile, element->attributeValue(QTest::AI_File)); + QXmlTestLogger::xmlCdata(&cdataDesc, element->attributeValue(QTest::AI_Description)); QTest::qt_asprintf(formatted, "\n \n\n", element->attributeValue(QTest::AI_Type), @@ -100,8 +100,8 @@ void QTestLightXmlStreamer::formatStart(const QTestElement *element, char **form // assuming value and iterations don't need quoting QTestCharBuffer quotedMetric; QTestCharBuffer quotedTag; - QXmlTestLogger::xmlQuote(quotedMetric, element->attributeValue(QTest::AI_Metric)); - QXmlTestLogger::xmlQuote(quotedTag, element->attributeValue(QTest::AI_Tag)); + QXmlTestLogger::xmlQuote("edMetric, element->attributeValue(QTest::AI_Metric)); + QXmlTestLogger::xmlQuote("edTag, element->attributeValue(QTest::AI_Tag)); QTest::qt_asprintf(formatted, "\n", element->attributeName(QTest::AI_Metric), @@ -115,11 +115,11 @@ void QTestLightXmlStreamer::formatStart(const QTestElement *element, char **form break; } default: - QTest::qt_asprintf(formatted, ""); + formatted->data()[0] = '\0'; } } -void QTestLightXmlStreamer::formatEnd(const QTestElement *element, char **formatted) const +void QTestLightXmlStreamer::formatEnd(const QTestElement *element, QTestCharBuffer *formatted) const { if(!element || !formatted) return; @@ -129,47 +129,47 @@ void QTestLightXmlStreamer::formatEnd(const QTestElement *element, char **format QTest::qt_asprintf(formatted, "\n\n"); else QTest::qt_asprintf(formatted, "\n"); + } else { + formatted->data()[0] = '\0'; } - else - QTest::qt_asprintf(formatted, ""); } -void QTestLightXmlStreamer::formatBeforeAttributes(const QTestElement *element, char **formatted) const +void QTestLightXmlStreamer::formatBeforeAttributes(const QTestElement *element, QTestCharBuffer *formatted) const { if(!element || !formatted) return; - if (element->elementType() == QTest::LET_TestCase && element->attribute(QTest::AI_Result)){ - QTestCharBuffer buf; - QTestCharBuffer quotedFile; - QXmlTestLogger::xmlQuote(quotedFile, element->attributeValue(QTest::AI_File)); - - QTest::qt_asprintf(buf, "%s=\"%s\" %s=\"%s\"", - element->attributeName(QTest::AI_File), - quotedFile.constData(), - element->attributeName(QTest::AI_Line), - element->attributeValue(QTest::AI_Line)); - - if( !element->childElements() ) - QTest::qt_asprintf(formatted, "\n", - element->attributeValue(QTest::AI_Result), buf.constData()); - else - QTest::qt_asprintf(formatted, "\n", - element->attributeValue(QTest::AI_Result), buf.constData()); - }else{ - QTest::qt_asprintf(formatted, ""); + if (element->elementType() == QTest::LET_TestCase && element->attribute(QTest::AI_Result)) { + QTestCharBuffer buf; + QTestCharBuffer quotedFile; + QXmlTestLogger::xmlQuote("edFile, element->attributeValue(QTest::AI_File)); + + QTest::qt_asprintf(&buf, "%s=\"%s\" %s=\"%s\"", + element->attributeName(QTest::AI_File), + quotedFile.constData(), + element->attributeName(QTest::AI_Line), + element->attributeValue(QTest::AI_Line)); + + if( !element->childElements() ) + QTest::qt_asprintf(formatted, "\n", + element->attributeValue(QTest::AI_Result), buf.constData()); + else + QTest::qt_asprintf(formatted, "\n", + element->attributeValue(QTest::AI_Result), buf.constData()); + } else { + formatted->data()[0] = '\0'; } } void QTestLightXmlStreamer::output(QTestElement *element) const { QTestCharBuffer buf; - QTest::qt_asprintf(buf, "\n %s\n %s\n", + QTest::qt_asprintf(&buf, "\n %s\n %s\n", qVersion(), QTEST_VERSION_STR ); - outputString(buf); + outputString(buf.constData()); - QTest::qt_asprintf(buf, "\n"); - outputString(buf); + QTest::qt_asprintf(&buf, "\n"); + outputString(buf.constData()); QTestBasicStreamer::output(element); } diff --git a/src/testlib/qtestlightxmlstreamer.h b/src/testlib/qtestlightxmlstreamer.h index 6dafdcc0f..e147e5cc0 100644 --- a/src/testlib/qtestlightxmlstreamer.h +++ b/src/testlib/qtestlightxmlstreamer.h @@ -59,9 +59,9 @@ class QTestLightXmlStreamer: public QTestBasicStreamer QTestLightXmlStreamer(); ~QTestLightXmlStreamer(); - void formatStart(const QTestElement *element, char **formatted) const; - void formatEnd(const QTestElement *element, char **formatted) const; - void formatBeforeAttributes(const QTestElement *element, char **formatted) const; + void formatStart(const QTestElement *element, QTestCharBuffer *formatted) const; + void formatEnd(const QTestElement *element, QTestCharBuffer *formatted) const; + void formatBeforeAttributes(const QTestElement *element, QTestCharBuffer *formatted) const; void output(QTestElement *element) const; }; diff --git a/src/testlib/qtestxmlstreamer.cpp b/src/testlib/qtestxmlstreamer.cpp index 1b6e674e8..c72d6480f 100644 --- a/src/testlib/qtestxmlstreamer.cpp +++ b/src/testlib/qtestxmlstreamer.cpp @@ -60,7 +60,7 @@ QTestXmlStreamer::QTestXmlStreamer() QTestXmlStreamer::~QTestXmlStreamer() {} -void QTestXmlStreamer::formatStart(const QTestElement *element, char **formatted) const +void QTestXmlStreamer::formatStart(const QTestElement *element, QTestCharBuffer *formatted) const { if(!element || !formatted) return; @@ -68,20 +68,20 @@ void QTestXmlStreamer::formatStart(const QTestElement *element, char **formatted switch(element->elementType()){ case QTest::LET_TestCase: { QTestCharBuffer quotedTf; - QXmlTestLogger::xmlQuote(quotedTf, element->attributeValue(QTest::AI_Name)); + QXmlTestLogger::xmlQuote("edTf, element->attributeValue(QTest::AI_Name)); QTest::qt_asprintf(formatted, "\n", quotedTf.constData()); break; } case QTest::LET_Failure: { QTestCharBuffer cdataDesc; - QXmlTestLogger::xmlCdata(cdataDesc, element->attributeValue(QTest::AI_Description)); + QXmlTestLogger::xmlCdata(&cdataDesc, element->attributeValue(QTest::AI_Description)); QTestCharBuffer location; QTestCharBuffer quotedFile; - QXmlTestLogger::xmlQuote(quotedFile, element->attributeValue(QTest::AI_File)); + QXmlTestLogger::xmlQuote("edFile, element->attributeValue(QTest::AI_File)); - QTest::qt_asprintf(location, "%s=\"%s\" %s=\"%s\"", + QTest::qt_asprintf(&location, "%s=\"%s\" %s=\"%s\"", element->attributeName(QTest::AI_File), quotedFile.constData(), element->attributeName(QTest::AI_Line), @@ -89,7 +89,7 @@ void QTestXmlStreamer::formatStart(const QTestElement *element, char **formatted if (element->attribute(QTest::AI_Tag)) { QTestCharBuffer cdataTag; - QXmlTestLogger::xmlCdata(cdataTag, element->attributeValue(QTest::AI_Tag)); + QXmlTestLogger::xmlCdata(&cdataTag, element->attributeValue(QTest::AI_Tag)); QTest::qt_asprintf(formatted, "\n" " \n" " \n" @@ -108,8 +108,8 @@ void QTestXmlStreamer::formatStart(const QTestElement *element, char **formatted // assuming type and attribute names don't need quoting QTestCharBuffer quotedFile; QTestCharBuffer cdataDesc; - QXmlTestLogger::xmlQuote(quotedFile, element->attributeValue(QTest::AI_File)); - QXmlTestLogger::xmlCdata(cdataDesc, element->attributeValue(QTest::AI_Description)); + QXmlTestLogger::xmlQuote("edFile, element->attributeValue(QTest::AI_File)); + QXmlTestLogger::xmlCdata(&cdataDesc, element->attributeValue(QTest::AI_Description)); QTest::qt_asprintf(formatted, "\n \n\n", element->attributeValue(QTest::AI_Type), @@ -124,8 +124,8 @@ void QTestXmlStreamer::formatStart(const QTestElement *element, char **formatted // assuming value and iterations don't need quoting QTestCharBuffer quotedMetric; QTestCharBuffer quotedTag; - QXmlTestLogger::xmlQuote(quotedMetric, element->attributeValue(QTest::AI_Metric)); - QXmlTestLogger::xmlQuote(quotedTag, element->attributeValue(QTest::AI_Tag)); + QXmlTestLogger::xmlQuote("edMetric, element->attributeValue(QTest::AI_Metric)); + QXmlTestLogger::xmlQuote("edTag, element->attributeValue(QTest::AI_Tag)); QTest::qt_asprintf(formatted, "\n", element->attributeName(QTest::AI_Metric), @@ -139,23 +139,23 @@ void QTestXmlStreamer::formatStart(const QTestElement *element, char **formatted break; } default: - QTest::qt_asprintf(formatted, ""); + formatted->data()[0] = '\0'; } } -void QTestXmlStreamer::formatEnd(const QTestElement *element, char **formatted) const +void QTestXmlStreamer::formatEnd(const QTestElement *element, QTestCharBuffer *formatted) const { if(!element || !formatted) return; if (element->elementType() == QTest::LET_TestCase) { QTest::qt_asprintf(formatted, "\n"); + } else { + formatted->data()[0] = '\0'; } - else - QTest::qt_asprintf(formatted, ""); } -void QTestXmlStreamer::formatBeforeAttributes(const QTestElement *element, char **formatted) const +void QTestXmlStreamer::formatBeforeAttributes(const QTestElement *element, QTestCharBuffer *formatted) const { if(!element || !formatted) return; @@ -163,9 +163,9 @@ void QTestXmlStreamer::formatBeforeAttributes(const QTestElement *element, char if (element->elementType() == QTest::LET_TestCase && element->attribute(QTest::AI_Result)){ QTestCharBuffer buf; QTestCharBuffer quotedFile; - QXmlTestLogger::xmlQuote(quotedFile, element->attributeValue(QTest::AI_File)); + QXmlTestLogger::xmlQuote("edFile, element->attributeValue(QTest::AI_File)); - QTest::qt_asprintf(buf, "%s=\"%s\" %s=\"%s\"", + QTest::qt_asprintf(&buf, "%s=\"%s\" %s=\"%s\"", element->attributeName(QTest::AI_File), quotedFile.constData(), element->attributeName(QTest::AI_Line), @@ -174,12 +174,11 @@ void QTestXmlStreamer::formatBeforeAttributes(const QTestElement *element, char if( !element->childElements() ) { QTest::qt_asprintf(formatted, "\n", element->attributeValue(QTest::AI_Result), buf.constData()); + } else { + formatted->data()[0] = '\0'; } - else { - QTest::qt_asprintf(formatted, ""); - } - }else{ - QTest::qt_asprintf(formatted, ""); + } else { + formatted->data()[0] = '\0'; } } @@ -187,23 +186,23 @@ void QTestXmlStreamer::output(QTestElement *element) const { QTestCharBuffer buf; QTestCharBuffer quotedTc; - QXmlTestLogger::xmlQuote(quotedTc, QTestResult::currentTestObjectName()); + QXmlTestLogger::xmlQuote("edTc, QTestResult::currentTestObjectName()); - QTest::qt_asprintf(buf, "\n\n", + QTest::qt_asprintf(&buf, "\n\n", quotedTc.constData()); - outputString(buf); + outputString(buf.constData()); - QTest::qt_asprintf(buf, "\n %s\n %s\n", + QTest::qt_asprintf(&buf, "\n %s\n %s\n", qVersion(), QTEST_VERSION_STR ); - outputString(buf); + outputString(buf.constData()); - QTest::qt_asprintf(buf, "\n"); - outputString(buf); + QTest::qt_asprintf(&buf, "\n"); + outputString(buf.constData()); QTestBasicStreamer::output(element); - QTest::qt_asprintf(buf, "\n"); - outputString(buf); + QTest::qt_asprintf(&buf, "\n"); + outputString(buf.constData()); } QT_END_NAMESPACE diff --git a/src/testlib/qtestxmlstreamer.h b/src/testlib/qtestxmlstreamer.h index a601f6034..6e1ae84cb 100644 --- a/src/testlib/qtestxmlstreamer.h +++ b/src/testlib/qtestxmlstreamer.h @@ -59,9 +59,9 @@ class QTestXmlStreamer: public QTestBasicStreamer QTestXmlStreamer(); ~QTestXmlStreamer(); - void formatStart(const QTestElement *element, char **formatted) const; - void formatEnd(const QTestElement *element, char **formatted) const; - void formatBeforeAttributes(const QTestElement *element, char **formatted) const; + void formatStart(const QTestElement *element, QTestCharBuffer *formatted) const; + void formatEnd(const QTestElement *element, QTestCharBuffer *formatted) const; + void formatBeforeAttributes(const QTestElement *element, QTestCharBuffer *formatted) const; void output(QTestElement *element) const; }; diff --git a/src/testlib/qtestxunitstreamer.cpp b/src/testlib/qtestxunitstreamer.cpp index d5d2631bf..932b70b13 100644 --- a/src/testlib/qtestxunitstreamer.cpp +++ b/src/testlib/qtestxunitstreamer.cpp @@ -73,7 +73,7 @@ void QTestXunitStreamer::indentForElement(const QTestElement* element, char* buf } } -void QTestXunitStreamer::formatStart(const QTestElement *element, char **formatted) const +void QTestXunitStreamer::formatStart(const QTestElement *element, QTestCharBuffer *formatted) const { if(!element || !formatted ) return; @@ -85,8 +85,7 @@ void QTestXunitStreamer::formatStart(const QTestElement *element, char **formatt if (element->elementType() == QTest::LET_Error) { if (element->parentElement()->elementType() == QTest::LET_SystemError) { QTest::qt_asprintf(formatted, "elementName()); } -void QTestXunitStreamer::formatEnd(const QTestElement *element, char **formatted) const +void QTestXunitStreamer::formatEnd(const QTestElement *element, QTestCharBuffer *formatted) const { - if(!element || !formatted ) + if (!element || !formatted ) return; - if(!element->childElements()){ - QTest::qt_asprintf(formatted, ""); + if (!element->childElements()){ + formatted->data()[0] = '\0'; return; } @@ -111,7 +110,7 @@ void QTestXunitStreamer::formatEnd(const QTestElement *element, char **formatted QTest::qt_asprintf(formatted, "%s\n", indent, element->elementName()); } -void QTestXunitStreamer::formatAttributes(const QTestElement* element, const QTestElementAttribute *attribute, char **formatted) const +void QTestXunitStreamer::formatAttributes(const QTestElement* element, const QTestElementAttribute *attribute, QTestCharBuffer *formatted) const { if(!attribute || !formatted ) return; @@ -136,15 +135,14 @@ void QTestXunitStreamer::formatAttributes(const QTestElement* element, const QTe if (key) { QTestCharBuffer quotedValue; - QXmlTestLogger::xmlQuote(quotedValue, attribute->value()); + QXmlTestLogger::xmlQuote("edValue, attribute->value()); QTest::qt_asprintf(formatted, " %s=\"%s\"", key, quotedValue.constData()); - } - else { - QTest::qt_asprintf(formatted, ""); + } else { + formatted->data()[0] = '\0'; } } -void QTestXunitStreamer::formatAfterAttributes(const QTestElement *element, char **formatted) const +void QTestXunitStreamer::formatAfterAttributes(const QTestElement *element, QTestCharBuffer *formatted) const { if(!element || !formatted ) return; @@ -153,8 +151,7 @@ void QTestXunitStreamer::formatAfterAttributes(const QTestElement *element, char if (element->elementType() == QTest::LET_Error) { if (element->parentElement()->elementType() == QTest::LET_SystemError) { QTest::qt_asprintf(formatted, "]]>\n"); - } - else { + } else { QTest::qt_asprintf(formatted, " -->\n"); } return; @@ -187,22 +184,22 @@ void QTestXunitStreamer::outputElements(QTestElement *element, bool) const hasChildren = element->childElements(); if(element->elementType() != QTest::LET_Benchmark){ - formatStart(element, buf); - outputString(buf); + formatStart(element, &buf); + outputString(buf.data()); - formatBeforeAttributes(element, buf); - outputString(buf); + formatBeforeAttributes(element, &buf); + outputString(buf.data()); outputElementAttributes(element, element->attributes()); - formatAfterAttributes(element, buf); - outputString(buf); + formatAfterAttributes(element, &buf); + outputString(buf.data()); if(hasChildren) outputElements(element->childElements(), true); - formatEnd(element, buf); - outputString(buf); + formatEnd(element, &buf); + outputString(buf.data()); } element = element->previousElement(); } diff --git a/src/testlib/qtestxunitstreamer.h b/src/testlib/qtestxunitstreamer.h index 044307f9e..43ff03d81 100644 --- a/src/testlib/qtestxunitstreamer.h +++ b/src/testlib/qtestxunitstreamer.h @@ -58,10 +58,10 @@ class QTestXunitStreamer: public QTestBasicStreamer QTestXunitStreamer(); ~QTestXunitStreamer(); - void formatStart(const QTestElement *element, char **formatted) const; - void formatEnd(const QTestElement *element, char **formatted) const; - void formatAfterAttributes(const QTestElement *element, char **formatted) const; - void formatAttributes(const QTestElement *element, const QTestElementAttribute *attribute, char **formatted) const; + void formatStart(const QTestElement *element, QTestCharBuffer *formatted) const; + void formatEnd(const QTestElement *element, QTestCharBuffer *formatted) const; + void formatAfterAttributes(const QTestElement *element, QTestCharBuffer *formatted) const; + void formatAttributes(const QTestElement *element, const QTestElementAttribute *attribute, QTestCharBuffer *formatted) const; void output(QTestElement *element) const; void outputElements(QTestElement *element, bool isChildElement = false) const; diff --git a/src/testlib/qxmltestlogger.cpp b/src/testlib/qxmltestlogger.cpp index fca7bfc1e..494acb46f 100644 --- a/src/testlib/qxmltestlogger.cpp +++ b/src/testlib/qxmltestlogger.cpp @@ -108,19 +108,19 @@ void QXmlTestLogger::startLogging() if (xmlmode == QXmlTestLogger::Complete) { QTestCharBuffer quotedTc; - xmlQuote(quotedTc, QTestResult::currentTestObjectName()); - QTest::qt_asprintf(buf, + xmlQuote("edTc, QTestResult::currentTestObjectName()); + QTest::qt_asprintf(&buf, "\n" "\n", quotedTc.constData()); - outputString(buf); + outputString(buf.constData()); } - QTest::qt_asprintf(buf, + QTest::qt_asprintf(&buf, "\n" " %s\n" " "QTEST_VERSION_STR"\n" "\n", qVersion()); - outputString(buf); + outputString(buf.constData()); } void QXmlTestLogger::stopLogging() @@ -136,9 +136,9 @@ void QXmlTestLogger::enterTestFunction(const char *function) { QTestCharBuffer buf; QTestCharBuffer quotedFunction; - xmlQuote(quotedFunction, function); - QTest::qt_asprintf(buf, "\n", quotedFunction.constData()); - outputString(buf); + xmlQuote("edFunction, function); + QTest::qt_asprintf(&buf, "\n", quotedFunction.constData()); + outputString(buf.constData()); } void QXmlTestLogger::leaveTestFunction() @@ -219,12 +219,12 @@ void QXmlTestLogger::addIncident(IncidentTypes type, const char *description, QTestCharBuffer cdataTag; QTestCharBuffer cdataDescription; - xmlQuote(quotedFile, file); - xmlCdata(cdataGtag, gtag); - xmlCdata(cdataTag, tag); - xmlCdata(cdataDescription, description); + xmlQuote("edFile, file); + xmlCdata(&cdataGtag, gtag); + xmlCdata(&cdataTag, tag); + xmlCdata(&cdataDescription, description); - QTest::qt_asprintf(buf, + QTest::qt_asprintf(&buf, QTest::incidentFormatString(QTest::isEmpty(description), notag), QTest::xmlIncidentType2String(type), quotedFile.constData(), line, @@ -233,7 +233,7 @@ void QXmlTestLogger::addIncident(IncidentTypes type, const char *description, cdataTag.constData(), cdataDescription.constData()); - outputString(buf); + outputString(buf.constData()); } void QXmlTestLogger::addBenchmarkResult(const QBenchmarkResult &result) @@ -242,18 +242,18 @@ void QXmlTestLogger::addBenchmarkResult(const QBenchmarkResult &result) QTestCharBuffer quotedMetric; QTestCharBuffer quotedTag; - xmlQuote(quotedMetric, + xmlQuote("edMetric, QBenchmarkGlobalData::current->measurer->metricText().toAscii().constData()); - xmlQuote(quotedTag, result.context.tag.toAscii().constData()); + xmlQuote("edTag, result.context.tag.toAscii().constData()); QTest::qt_asprintf( - buf, + &buf, QTest::benchmarkResultFormatString(), quotedMetric.constData(), quotedTag.constData(), QByteArray::number(result.value).constData(), //no 64-bit qt_snprintf support result.iterations); - outputString(buf); + outputString(buf.constData()); } void QXmlTestLogger::addMessage(MessageTypes type, const char *message, @@ -270,12 +270,12 @@ void QXmlTestLogger::addMessage(MessageTypes type, const char *message, QTestCharBuffer cdataTag; QTestCharBuffer cdataDescription; - xmlQuote(quotedFile, file); - xmlCdata(cdataGtag, gtag); - xmlCdata(cdataTag, tag); - xmlCdata(cdataDescription, message); + xmlQuote("edFile, file); + xmlCdata(&cdataGtag, gtag); + xmlCdata(&cdataTag, tag); + xmlCdata(&cdataDescription, message); - QTest::qt_asprintf(buf, + QTest::qt_asprintf(&buf, QTest::messageFormatString(QTest::isEmpty(message), notag), QTest::xmlMessageType2String(type), quotedFile.constData(), line, @@ -284,7 +284,7 @@ void QXmlTestLogger::addMessage(MessageTypes type, const char *message, cdataTag.constData(), cdataDescription.constData()); - outputString(buf); + outputString(buf.constData()); } /* @@ -292,10 +292,11 @@ void QXmlTestLogger::addMessage(MessageTypes type, const char *message, XML characters as necessary so that dest is suitable for use in an XML quoted attribute string. */ -int QXmlTestLogger::xmlQuote(char* dest, char const* src, size_t n) +int QXmlTestLogger::xmlQuote(QTestCharBuffer* destBuf, char const* src, size_t n) { if (n == 0) return 0; + char *dest = destBuf->data(); *dest = 0; if (!src) return 0; @@ -351,10 +352,12 @@ int QXmlTestLogger::xmlQuote(char* dest, char const* src, size_t n) Copy up to n characters from the src string into dest, escaping any special strings such that dest is suitable for use in an XML CDATA section. */ -int QXmlTestLogger::xmlCdata(char* dest, char const* src, size_t n) +int QXmlTestLogger::xmlCdata(QTestCharBuffer *destBuf, char const* src, size_t n) { if (!n) return 0; + char *dest = destBuf->data(); + if (!src || n == 1) { *dest = 0; return 0; @@ -394,25 +397,23 @@ int QXmlTestLogger::xmlCdata(char* dest, char const* src, size_t n) return (dest-begin); } -typedef int (*StringFormatFunction)(char*,char const*,size_t); +typedef int (*StringFormatFunction)(QTestCharBuffer*,char const*,size_t); /* A wrapper for string functions written to work with a fixed size buffer so they can be called with a dynamically allocated buffer. */ -int allocateStringFn(char** str, char const* src, StringFormatFunction func) +int allocateStringFn(QTestCharBuffer* str, char const* src, StringFormatFunction func) { static const int MAXSIZE = 1024*1024*2; - int size = 32; - delete[] *str; - *str = new char[size]; + int size = str->size(); int res = 0; for (;;) { - res = func(*str, src, size); - (*str)[size - 1] = '\0'; + res = func(str, src, size); + str->data()[size - 1] = '\0'; if (res < size) { // We succeeded or fatally failed break; @@ -422,19 +423,19 @@ int allocateStringFn(char** str, char const* src, StringFormatFunction func) if (size > MAXSIZE) { break; } - delete[] *str; - *str = new char[size]; + if (!str->reset(size)) + break; // ran out of memory - bye } return res; } -int QXmlTestLogger::xmlQuote(char** str, char const* src) +int QXmlTestLogger::xmlQuote(QTestCharBuffer* str, char const* src) { return allocateStringFn(str, src, QXmlTestLogger::xmlQuote); } -int QXmlTestLogger::xmlCdata(char** str, char const* src) +int QXmlTestLogger::xmlCdata(QTestCharBuffer* str, char const* src) { return allocateStringFn(str, src, QXmlTestLogger::xmlCdata); } diff --git a/src/testlib/qxmltestlogger_p.h b/src/testlib/qxmltestlogger_p.h index a7cc00a34..e14504ce4 100644 --- a/src/testlib/qxmltestlogger_p.h +++ b/src/testlib/qxmltestlogger_p.h @@ -79,10 +79,10 @@ public: void addMessage(MessageTypes type, const char *message, const char *file = 0, int line = 0); - static int xmlCdata(char** dest, char const* src); - static int xmlQuote(char** dest, char const* src); - static int xmlCdata(char* dest, char const* src, size_t n); - static int xmlQuote(char* dest, char const* src, size_t n); + static int xmlCdata(QTestCharBuffer *dest, char const* src); + static int xmlQuote(QTestCharBuffer *dest, char const* src); + static int xmlCdata(QTestCharBuffer *dest, char const* src, size_t n); + static int xmlQuote(QTestCharBuffer *dest, char const* src, size_t n); private: XmlMode xmlmode; -- cgit v1.2.3 From 56d84a7dcbbaee6402d1d43bba879b135839ad61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan-Arve=20S=C3=A6ther?= Date: Fri, 7 Aug 2009 15:34:31 +0200 Subject: Don't crash if we are drawing an empty image. Reviewed-by: gunnar --- src/gui/painting/qpaintengine_raster.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index 74456dde4..b260f4129 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -2542,6 +2542,9 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe qDebug() << " - QRasterPaintEngine::drawImage(), r=" << r << " sr=" << sr << " image=" << img.size() << "depth=" << img.depth(); #endif + if (r.isEmpty()) + return; + Q_D(QRasterPaintEngine); QRasterPaintEngineState *s = state(); const bool aa = s->flags.antialiased || s->flags.bilinear; -- cgit v1.2.3 From f99e01bccb5e2b686c0d98ea3743e9fcf48ce8d2 Mon Sep 17 00:00:00 2001 From: Harald Fernengel Date: Fri, 7 Aug 2009 16:09:45 +0200 Subject: Fix build warning gcc was complaining about format string not being a string literal. Also fixes the small chance that error messages would be bogus if they contain printf control characters. Reviewed-by: Bradley T. Hughes --- src/tools/uic/uic.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/uic/uic.cpp b/src/tools/uic/uic.cpp index f789980ca..14576e285 100644 --- a/src/tools/uic/uic.cpp +++ b/src/tools/uic/uic.cpp @@ -184,7 +184,7 @@ DomUI *Uic::parseUiFile(QXmlStreamReader &reader) if (reader.hasError()) { delete ui; ui = 0; - fprintf(stderr, qPrintable(QString::fromLatin1("uic: Error in line %1, column %2 : %3\n") + fprintf(stderr, "%s\n", qPrintable(QString::fromLatin1("uic: Error in line %1, column %2 : %3") .arg(reader.lineNumber()).arg(reader.columnNumber()) .arg(reader.errorString()))); } -- cgit v1.2.3 From 132a319dc782ef1feebe6582fb6f05dc91df74bb Mon Sep 17 00:00:00 2001 From: Anders Bakken Date: Fri, 7 Aug 2009 07:28:27 -0700 Subject: Fix compiler error on GCC 4.2.0 mips/sh3 Before this patch gcc would fail with this message: internal compiler error: in add_virtual_operand, at tree-ssa-operands.c:1317 Reviewed-by: Volker Hilsheimer --- src/gui/graphicsview/qgraphicsview.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp index ca55f2e96..92f8816a8 100644 --- a/src/gui/graphicsview/qgraphicsview.cpp +++ b/src/gui/graphicsview/qgraphicsview.cpp @@ -2209,8 +2209,7 @@ QPolygonF QGraphicsView::mapToScene(const QRect &rect) const QPointF br = scrollOffset + r.bottomRight(); QPointF bl = scrollOffset + r.bottomLeft(); - QPolygonF poly; - poly.resize(4); + QPolygonF poly(4); if (!d->identityMatrix) { QTransform x = d->matrix.inverted(); poly[0] = x.map(tl); @@ -2313,8 +2312,7 @@ QPolygon QGraphicsView::mapFromScene(const QRectF &rect) const br -= scrollOffset; bl -= scrollOffset; - QPolygon poly; - poly.resize(4); + QPolygon poly(4); poly[0] = tl.toPoint(); poly[1] = tr.toPoint(); poly[2] = br.toPoint(); @@ -3647,8 +3645,7 @@ QRectF QGraphicsViewPrivate::mapToScene(const QRectF &rect) const QPointF br = scrollOffset + rect.bottomRight(); QPointF bl = scrollOffset + rect.bottomLeft(); - QPolygonF poly; - poly.resize(4); + QPolygonF poly(4); if (!identityMatrix) { QTransform x = matrix.inverted(); poly[0] = x.map(tl); -- cgit v1.2.3 From d13418effc5f00474541ae513a30c9a42c2a1cb3 Mon Sep 17 00:00:00 2001 From: Gabriel de Dietrich Date: Fri, 7 Aug 2009 17:14:31 +0200 Subject: QItemSelectionModel did not send selectionChanged signal when deleting an item in a tree-like model with one of its grand-children being selected. Added recursive deselection for the model. Task-number: 232634 Reviewed-by: thierry --- src/gui/itemviews/qitemselectionmodel.cpp | 22 +++++++++++++++++++- src/gui/itemviews/qitemselectionmodel_p.h | 2 ++ .../tst_qitemselectionmodel.cpp | 24 ++++++++++++++++++++++ 3 files changed, 47 insertions(+), 1 deletion(-) diff --git a/src/gui/itemviews/qitemselectionmodel.cpp b/src/gui/itemviews/qitemselectionmodel.cpp index 9dad95f86..0f35ac1df 100644 --- a/src/gui/itemviews/qitemselectionmodel.cpp +++ b/src/gui/itemviews/qitemselectionmodel.cpp @@ -593,10 +593,30 @@ void QItemSelectionModelPrivate::_q_rowsAboutToBeRemoved(const QModelIndex &pare // update selectionsx QModelIndex tl = model->index(start, 0, parent); QModelIndex br = model->index(end, model->columnCount(parent) - 1, parent); - q->select(QItemSelection(tl, br), QItemSelectionModel::Deselect); + recursiveDeselect(QItemSelectionRange(tl, br)); finalize(); } +void QItemSelectionModelPrivate::recursiveDeselect(const QItemSelectionRange &range) +{ + Q_Q(QItemSelectionModel); + + QItemSelection sel(range.topLeft(), range.bottomRight()); + q->select(sel, QItemSelectionModel::Deselect); + + QModelIndexList idxList = range.indexes(); + QModelIndexList::const_iterator it = idxList.begin(); + for (; it != idxList.end(); ++it) + { + if (!model->hasChildren(*it)) + continue; + + const QModelIndex &firstChild = it->child(0,0); + const QModelIndex &lastChild = it->child(model->rowCount(*it) - 1, model->columnCount(*it) - 1); + recursiveDeselect(QItemSelectionRange(firstChild, lastChild)); + } +} + /*! \internal */ diff --git a/src/gui/itemviews/qitemselectionmodel_p.h b/src/gui/itemviews/qitemselectionmodel_p.h index 18ad506dc..8176d4c0e 100644 --- a/src/gui/itemviews/qitemselectionmodel_p.h +++ b/src/gui/itemviews/qitemselectionmodel_p.h @@ -77,6 +77,8 @@ public: void _q_layoutAboutToBeChanged(); void _q_layoutChanged(); + void recursiveDeselect(const QItemSelectionRange &range); + inline void remove(QList &r) { QList::const_iterator it = r.constBegin(); diff --git a/tests/auto/qitemselectionmodel/tst_qitemselectionmodel.cpp b/tests/auto/qitemselectionmodel/tst_qitemselectionmodel.cpp index 0541b461f..05e23f196 100644 --- a/tests/auto/qitemselectionmodel/tst_qitemselectionmodel.cpp +++ b/tests/auto/qitemselectionmodel/tst_qitemselectionmodel.cpp @@ -90,6 +90,7 @@ private slots: void merge(); void task119433_isRowSelected(); void task252069_rowIntersectsSelection(); + void task232634_childrenDeselectionSignal(); private: QAbstractItemModel *model; @@ -2187,5 +2188,28 @@ void tst_QItemSelectionModel::task252069_rowIntersectsSelection() QVERIFY(!selected.columnIntersectsSelection(5, QModelIndex())); } +void tst_QItemSelectionModel::task232634_childrenDeselectionSignal() +{ + QStandardItemModel model; + + QStandardItem *parentItem = model.invisibleRootItem(); + for (int i = 0; i < 4; ++i) { + QStandardItem *item = new QStandardItem(QString("item %0").arg(i)); + parentItem->appendRow(item); + parentItem = item; + } + + QModelIndex root = model.index(0,0); + QModelIndex par = root.child(0,0); + QModelIndex sel = par.child(0,0); + + QItemSelectionModel selectionModel(&model); + selectionModel.select(sel, QItemSelectionModel::SelectCurrent); + + QSignalSpy deselectSpy(&selectionModel, SIGNAL(selectionChanged(const QItemSelection& , const QItemSelection&))); + model.removeRows(0, 1, root); + QVERIFY(deselectSpy.count() == 1); +} + QTEST_MAIN(tst_QItemSelectionModel) #include "tst_qitemselectionmodel.moc" -- cgit v1.2.3 From e54e4f19ec2fd06f9d383b2cd83a565479e3cced Mon Sep 17 00:00:00 2001 From: Rhys Weatherley Date: Mon, 10 Aug 2009 10:36:01 +1000 Subject: Add a private function for conversion a QPixmap into a VGImage Custom OpenVG pixmap filters written by users will need to access the VGImage form of a QPixmap. The qPixmapToVGImage() function is provided for this purpose, as a private API. Reviewed-by: Sarah Smith --- src/openvg/qpixmapdata_vg.cpp | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/openvg/qpixmapdata_vg.cpp b/src/openvg/qpixmapdata_vg.cpp index 90fd9a588..6f2024fa1 100644 --- a/src/openvg/qpixmapdata_vg.cpp +++ b/src/openvg/qpixmapdata_vg.cpp @@ -341,4 +341,29 @@ QImage::Format QVGPixmapData::sourceFormat() const return QImage::Format_ARGB32_Premultiplied; } +/* + \internal + + Returns the VGImage that is storing the contents of \a pixmap. + Returns VG_INVALID_HANDLE if \a pixmap is not owned by the OpenVG + graphics system or \a pixmap is invalid. + + This function is typically used to access the backing store + for a pixmap when executing raw OpenVG calls. It must only + be used when a QPainter is active and the OpenVG paint engine + is in use by the QPainter. + + \sa {QtOpenVG Module} +*/ +Q_OPENVG_EXPORT VGImage qPixmapToVGImage(const QPixmap& pixmap) +{ + QPixmapData *pd = pixmap.pixmapData(); + if (pd->classId() == QPixmapData::OpenVGClass) { + QVGPixmapData *vgpd = static_cast(pd); + if (vgpd->isValid()) + return vgpd->toVGImage(); + } + return VG_INVALID_HANDLE; +} + QT_END_NAMESPACE -- cgit v1.2.3 From 341ba562a81c4be1264020c207a940d5c7fd5de7 Mon Sep 17 00:00:00 2001 From: Rohan McGovern Date: Mon, 10 Aug 2009 14:27:49 +1000 Subject: Make checksdk give a nonzero exit code when it's asked for an SDK which isn't available. Reviewed-by: Michael Goddard --- tools/checksdk/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/checksdk/main.cpp b/tools/checksdk/main.cpp index 6322eb7bf..b36aa3286 100644 --- a/tools/checksdk/main.cpp +++ b/tools/checksdk/main.cpp @@ -161,5 +161,5 @@ int main(int argc, char **argv) } } qWarning("Could not find specified SDK: %s" , qPrintable(sdkName)); - return 0; -} \ No newline at end of file + return -1; +} -- cgit v1.2.3 From bb97f90ef340d668f3dc04026aa034b33a997453 Mon Sep 17 00:00:00 2001 From: Rhys Weatherley Date: Mon, 10 Aug 2009 14:47:13 +1000 Subject: Set default QGraphicsTransform3D axis to (0, 0, 1) The docs said that the default axis was (0, 0, 1), but the code and unit tests were using (0, 0, 0). Modify the code to match the docs because (0, 0, 0) is not very useful. Also optimize the calculation of sin/cos values for 90, 180, and 270 degrees. Reviewed-by: Aaron Kennedy --- src/gui/graphicsview/qgraphicstransform.cpp | 37 +++++++++++++++------- .../qgraphicstransform/tst_qgraphicstransform.cpp | 22 ++++++++++++- 2 files changed, 47 insertions(+), 12 deletions(-) diff --git a/src/gui/graphicsview/qgraphicstransform.cpp b/src/gui/graphicsview/qgraphicstransform.cpp index 778cd9451..ae88641a4 100644 --- a/src/gui/graphicsview/qgraphicstransform.cpp +++ b/src/gui/graphicsview/qgraphicstransform.cpp @@ -80,11 +80,7 @@ #include "qgraphicsitem_p.h" #include "qgraphicstransform_p.h" #include - -#include -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif +#include QT_BEGIN_NAMESPACE @@ -355,7 +351,6 @@ public: QGraphicsRotationPrivate() : angle(0) {} QPointF origin; - qreal originY; qreal angle; }; @@ -475,13 +470,18 @@ void QGraphicsRotation::applyTo(QTransform *t) const By default the axis is (0, 0, 1), giving QGraphicsRotation3D the same default behavior as QGraphicsRotation (i.e., rotation around the Z axis). + Note: the final rotation is the combined effect of a rotation in + 3D space followed by a projection back to 2D. If several rotations + are performed in succession, they will not behave as expected unless + they were all around the Z axis. + \sa QGraphicsTransform, QGraphicsItem::setRotation(), QTransform::rotate() */ class QGraphicsRotation3DPrivate : public QGraphicsRotationPrivate { public: - QGraphicsRotation3DPrivate() {} + QGraphicsRotation3DPrivate() : axis(0, 0, 1) {} QVector3D axis; }; @@ -526,6 +526,7 @@ void QGraphicsRotation3D::setAxis(const QVector3D &axis) update(); } +const qreal deg2rad = qreal(0.017453292519943295769); // pi/180 static const qreal inv_dist_to_plane = 1. / 1024.; /*! @@ -535,13 +536,27 @@ void QGraphicsRotation3D::applyTo(QTransform *t) const { Q_D(const QGraphicsRotation3D); - if (d->angle == 0. || + qreal a = d->angle; + + if (a == 0. || (d->axis.z() == 0. && d->axis.y() == 0 && d->axis.x() == 0)) return; - qreal rad = d->angle * 2. * M_PI / 360.; - qreal c = ::cos(rad); - qreal s = ::sin(rad); + qreal c, s; + if (a == 90. || a == -270.) { + s = 1.; + c = 0.; + } else if (a == 270. || a == -90.) { + s = -1.; + c = 0.; + } else if (a == 180.) { + s = 0.; + c = -1.; + } else { + qreal b = deg2rad*a; + s = qSin(b); + c = qCos(b); + } qreal x = d->axis.x(); qreal y = d->axis.y(); diff --git a/tests/auto/qgraphicstransform/tst_qgraphicstransform.cpp b/tests/auto/qgraphicstransform/tst_qgraphicstransform.cpp index 672b1f15a..c9481da3b 100644 --- a/tests/auto/qgraphicstransform/tst_qgraphicstransform.cpp +++ b/tests/auto/qgraphicstransform/tst_qgraphicstransform.cpp @@ -137,7 +137,10 @@ void tst_QGraphicsTransform::rotation() void tst_QGraphicsTransform::rotation3d() { QGraphicsRotation3D rotation; - rotation.setOrigin(QPointF(10, 10)); + QCOMPARE(rotation.axis().x(), (qreal)0); + QCOMPARE(rotation.axis().y(), (qreal)0); + QCOMPARE(rotation.axis().z(), (qreal)1); + QCOMPARE(rotation.angle(), (qreal)0); QTransform t; rotation.applyTo(&t); @@ -147,6 +150,23 @@ void tst_QGraphicsTransform::rotation3d() rotation.setAngle(180); + QTransform t180; + t180.rotate(180.0f); + + QCOMPARE(t, QTransform()); + QVERIFY(qFuzzyCompare(rotation.transform(), t180)); + + rotation.setAxis(QVector3D(0, 0, 0)); + rotation.setOrigin(QPointF(10, 10)); + + t = QTransform(); + rotation.applyTo(&t); + + QCOMPARE(t, QTransform()); + QCOMPARE(rotation.transform(), QTransform()); + + rotation.setAngle(180); + QCOMPARE(t, QTransform()); QCOMPARE(rotation.transform(), QTransform()); -- cgit v1.2.3 From 5d01d0cde28f2ac1ff9b5d8ca731edcf38725051 Mon Sep 17 00:00:00 2001 From: Rhys Weatherley Date: Mon, 10 Aug 2009 15:31:00 +1000 Subject: Emit axisChanged() when the QGraphicsRotation3D axis changes. Reviewed-by: Aaron Kennedy --- src/gui/graphicsview/qgraphicstransform.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/gui/graphicsview/qgraphicstransform.cpp b/src/gui/graphicsview/qgraphicstransform.cpp index ae88641a4..775a0d581 100644 --- a/src/gui/graphicsview/qgraphicstransform.cpp +++ b/src/gui/graphicsview/qgraphicstransform.cpp @@ -522,8 +522,11 @@ QVector3D QGraphicsRotation3D::axis() void QGraphicsRotation3D::setAxis(const QVector3D &axis) { Q_D(QGraphicsRotation3D); + if (d->axis == axis) + return; d->axis = axis; update(); + emit axisChanged(); } const qreal deg2rad = qreal(0.017453292519943295769); // pi/180 -- cgit v1.2.3 From 6cc14b9bd84de30471db40f73b119ba33356a6ba Mon Sep 17 00:00:00 2001 From: Keith Isdale Date: Mon, 10 Aug 2009 17:19:20 +1000 Subject: In a .pro file the include() function does not warn if specified file can not be found change that behavior to warn by default. Currently the default behavior of include() in a .pro file is not to warn if the supplied file argument can not be found which can lead to hard to find build errors. The include() will now,by default, warn if the specified file can not be found. If a warning is not required because the included file is optional then example use in the .pro file: include(SomePriFile.pri", "", true) Task-number:259398 Reviewed-by:Marius Storm-Olsen --- mkspecs/features/qt_config.prf | 2 +- qmake/project.cpp | 13 +++++++++---- src/3rdparty/webkit/WebCore/WebCore.pro | 2 +- src/corelib/arch/arch.pri | 2 +- src/qbase.pri | 2 +- src/xmlpatterns/query.pri | 2 +- src/xmlpatterns/xmlpatterns.pro | 2 +- tests/auto/qaccessibility_mac/qaccessibility_mac.pro | 2 +- tests/auto/qmake/testdata/functions/functions.pro | 2 +- tools/assistant/compat/lib/lib.pro | 2 +- tools/designer/src/components/lib/lib.pro | 2 +- tools/designer/src/lib/lib.pro | 2 +- tools/designer/src/uitools/uitools.pro | 2 +- 13 files changed, 21 insertions(+), 16 deletions(-) diff --git a/mkspecs/features/qt_config.prf b/mkspecs/features/qt_config.prf index 779c2e5ac..0a2d985de 100644 --- a/mkspecs/features/qt_config.prf +++ b/mkspecs/features/qt_config.prf @@ -4,7 +4,7 @@ isEmpty(QMAKE_QT_CONFIG)|!exists($$QMAKE_QT_CONFIG) { else:exists($$_QMAKE_CACHE_):infile($$_QMAKE_CACHE_, QT_BUILD_TREE):QMAKE_QT_CONFIG = $$fromfile($$_QMAKE_CACHE_, QT_BUILD_TREE)/mkspecs/qconfig.pri else:exists($$[QT_INSTALL_DATA]/mkspecs/qconfig.pri):QMAKE_QT_CONFIG = $$[QT_INSTALL_DATA]/mkspecs/qconfig.pri } -!exists($$QMAKE_QT_CONFIG)|!include($$QMAKE_QT_CONFIG) { +!exists($$QMAKE_QT_CONFIG)|!include($$QMAKE_QT_CONFIG, "", true) { debug(1, "Cannot load qconfig.pri!") } else { debug(1, "Loaded .qconfig.pri from ($$QMAKE_QT_CONFIG)") diff --git a/qmake/project.cpp b/qmake/project.cpp index 4fefbabc7..6687e9a62 100644 --- a/qmake/project.cpp +++ b/qmake/project.cpp @@ -2693,10 +2693,15 @@ QMakeProject::doProjectTest(QString func, QList args_list, QMap= 2) { if(func_t == T_INCLUDE) { parseInto = args[1]; + if (args.count() == 3){ + QString sarg = args[2]; + if (sarg.toLower() == "true" || sarg.toInt()) + ignore_error = true; + } } else { QString sarg = args[1]; ignore_error = (sarg.toLower() == "true" || sarg.toInt()); @@ -2738,8 +2743,8 @@ QMakeProject::doProjectTest(QString func, QList args_list, QMap= IncludeFailure) { diff --git a/src/3rdparty/webkit/WebCore/WebCore.pro b/src/3rdparty/webkit/WebCore/WebCore.pro index e49ab1344..2eb7c08f9 100644 --- a/src/3rdparty/webkit/WebCore/WebCore.pro +++ b/src/3rdparty/webkit/WebCore/WebCore.pro @@ -3159,7 +3159,7 @@ xpathbison.dependency_type = TYPE_C xpathbison.variable_out = GENERATED_SOURCES addExtraCompilerWithHeader(xpathbison) -include($$PWD/../WebKit/qt/Api/headers.pri) +include($$PWD/../WebKit/qt/Api/headers.pri, "", true) HEADERS += $$WEBKIT_API_HEADERS !CONFIG(QTDIR_build) { target.path = $$[QT_INSTALL_LIBS] diff --git a/src/corelib/arch/arch.pri b/src/corelib/arch/arch.pri index dd3141a3c..18f54ee5b 100644 --- a/src/corelib/arch/arch.pri +++ b/src/corelib/arch/arch.pri @@ -25,4 +25,4 @@ vxworks:HEADERS += arch/qatomic_vxworks.h QT_ARCH_CPP = $$QT_SOURCE_TREE/src/corelib/arch/$$QT_ARCH DEPENDPATH += $$QT_ARCH_CPP -include($$QT_ARCH_CPP/arch.pri) +include($$QT_ARCH_CPP/arch.pri, "", true) diff --git a/src/qbase.pri b/src/qbase.pri index 0ab04e61f..9e2d26ffa 100644 --- a/src/qbase.pri +++ b/src/qbase.pri @@ -13,7 +13,7 @@ mac:!contains(QMAKE_EXT_C, .mm):QMAKE_EXT_C += .mm #load up the headers info CONFIG += qt_install_headers HEADERS_PRI = $$QT_BUILD_TREE/include/$$TARGET/headers.pri -include($$HEADERS_PRI)|clear(HEADERS_PRI) +include($$HEADERS_PRI, "", true)|clear(HEADERS_PRI) #version overriding win32 { diff --git a/src/xmlpatterns/query.pri b/src/xmlpatterns/query.pri index e09a61854..fab194031 100644 --- a/src/xmlpatterns/query.pri +++ b/src/xmlpatterns/query.pri @@ -11,4 +11,4 @@ include($$PWD/parser/parser.pri) include($$PWD/projection/projection.pri) include($$PWD/type/type.pri) include($$PWD/utils/utils.pri) -include($$PWD/qobjectmodel/qobjectmodel.pri) +include($$PWD/qobjectmodel/qobjectmodel.pri, "", true) diff --git a/src/xmlpatterns/xmlpatterns.pro b/src/xmlpatterns/xmlpatterns.pro index fb6aa1af5..0e6270ea7 100644 --- a/src/xmlpatterns/xmlpatterns.pro +++ b/src/xmlpatterns/xmlpatterns.pro @@ -25,7 +25,7 @@ include($$PWD/schema/schema.pri) include($$PWD/schematron/schematron.pri) include($$PWD/type/type.pri) include($$PWD/utils/utils.pri) -include($$PWD/qobjectmodel/qobjectmodel.pri) +include($$PWD/qobjectmodel/qobjectmodel.pri, "", true) wince*: { # The Microsoft MIPS compiler crashes if /Og is specified diff --git a/tests/auto/qaccessibility_mac/qaccessibility_mac.pro b/tests/auto/qaccessibility_mac/qaccessibility_mac.pro index b32a7e53e..47f72d1cd 100644 --- a/tests/auto/qaccessibility_mac/qaccessibility_mac.pro +++ b/tests/auto/qaccessibility_mac/qaccessibility_mac.pro @@ -11,7 +11,7 @@ requires(mac) # builds (where QTDIR points to the build directory). # autotest + shadow build is not supported :) exists($$(QTDIR)/tools/designer/src/lib/uilib/uilib.pri) { - include($$(QTDIR)/tools/designer/src/lib/uilib/uilib.pri) + include($$(QTDIR)/tools/designer/src/lib/uilib/uilib.pri, "", true) INCLUDEPATH += $$(QTDIR)/tools/designer/src/uitools SOURCES += $$(QTDIR)/tools/designer/src/uitools/quiloader.cpp HEADERS += $$(QTDIR)/tools/designer/src/uitools/quiloader.h diff --git a/tests/auto/qmake/testdata/functions/functions.pro b/tests/auto/qmake/testdata/functions/functions.pro index 9ed92f960..5e089e403 100644 --- a/tests/auto/qmake/testdata/functions/functions.pro +++ b/tests/auto/qmake/testdata/functions/functions.pro @@ -46,7 +46,7 @@ isEmpty( CONFIG ) { } #include -include( infiletest.pro ) +include( infiletest.pro, "", true ) !contains( DEFINES, QT_DLL ) { message( "FAILED: include function: $$DEFINES" ) } diff --git a/tools/assistant/compat/lib/lib.pro b/tools/assistant/compat/lib/lib.pro index d4b5a47b2..e50d4702c 100644 --- a/tools/assistant/compat/lib/lib.pro +++ b/tools/assistant/compat/lib/lib.pro @@ -32,7 +32,7 @@ contains(CONFIG, static) { #load up the headers info CONFIG += qt_install_headers HEADERS_PRI = $$QT_BUILD_TREE/include/QtAssistant/headers.pri -include($$HEADERS_PRI)|clear(HEADERS_PRI) +include($$HEADERS_PRI, "", true)|clear(HEADERS_PRI) #mac frameworks mac:!static:contains(QT_CONFIG, qt_framework) { diff --git a/tools/designer/src/components/lib/lib.pro b/tools/designer/src/components/lib/lib.pro index 4515b6635..92cf387cf 100644 --- a/tools/designer/src/components/lib/lib.pro +++ b/tools/designer/src/components/lib/lib.pro @@ -24,7 +24,7 @@ QMAKE_TARGET_DESCRIPTION = Graphical user interface designer. #load up the headers info CONFIG += qt_install_headers HEADERS_PRI = $$QT_BUILD_TREE/include/QtDesigner/headers.pri -include($$HEADERS_PRI)|clear(HEADERS_PRI) +include($$HEADERS_PRI, "", true)|clear(HEADERS_PRI) #mac frameworks mac:!static:contains(QT_CONFIG, qt_framework) { diff --git a/tools/designer/src/lib/lib.pro b/tools/designer/src/lib/lib.pro index e0f2f2357..495976d21 100644 --- a/tools/designer/src/lib/lib.pro +++ b/tools/designer/src/lib/lib.pro @@ -34,7 +34,7 @@ QMAKE_TARGET_DESCRIPTION = Graphical user interface designer. #load up the headers info CONFIG += qt_install_headers HEADERS_PRI = $$QT_BUILD_TREE/include/QtDesigner/headers.pri -include($$HEADERS_PRI)|clear(HEADERS_PRI) +include($$HEADERS_PRI, "", true)|clear(HEADERS_PRI) #mac frameworks mac:CONFIG += explicitlib diff --git a/tools/designer/src/uitools/uitools.pro b/tools/designer/src/uitools/uitools.pro index a20abf0b2..34e487758 100644 --- a/tools/designer/src/uitools/uitools.pro +++ b/tools/designer/src/uitools/uitools.pro @@ -22,7 +22,7 @@ include(../lib/uilib/uilib.pri) HEADERS += quiloader.h SOURCES += quiloader.cpp -include($$QT_BUILD_TREE/include/QtUiTools/headers.pri) +include($$QT_BUILD_TREE/include/QtUiTools/headers.pri, "", true) quitools_headers.files = $$SYNCQT.HEADER_FILES $$SYNCQT.HEADER_CLASSES quitools_headers.path = $$[QT_INSTALL_HEADERS]/QtUiTools INSTALLS += quitools_headers -- cgit v1.2.3 From 2be387f3e94f84cf0167cdc3871de0d0af85c62d Mon Sep 17 00:00:00 2001 From: David Faure Date: Mon, 10 Aug 2009 09:37:18 +0200 Subject: Make QTimeLine::start() restart from the beginning as the documentation says. The documentation implies that start restarts. Which it did, but only if the timeline was finished _and_ the duration hadn't been changed meanwhile. So after a setDuration(), start() would do nothing, which was unexpected. Merge-request: 1145 Reviewed-by: Olivier Goffart --- src/corelib/tools/qtimeline.cpp | 9 ++++---- tests/auto/qtimeline/tst_qtimeline.cpp | 41 +++++++++++++++++++++++++++++++++- 2 files changed, 44 insertions(+), 6 deletions(-) diff --git a/src/corelib/tools/qtimeline.cpp b/src/corelib/tools/qtimeline.cpp index e32fc0358..7402ba6ba 100644 --- a/src/corelib/tools/qtimeline.cpp +++ b/src/corelib/tools/qtimeline.cpp @@ -663,6 +663,7 @@ qreal QTimeLine::valueForTime(int msec) const second). You can change the update interval by calling setUpdateInterval(). + The timeline will start from position 0, or the end if going backward. If you want to resume a stopped timeline without restarting, you can call resume() instead. @@ -675,10 +676,8 @@ void QTimeLine::start() qWarning("QTimeLine::start: already running"); return; } - int curTime = d->currentTime; - if (curTime == d->duration && d->direction == Forward) - curTime = 0; - else if (curTime == 0 && d->direction == Backward) + int curTime = 0; + if (d->direction == Backward) curTime = d->duration; d->timerId = startTimer(d->updateInterval); d->startTime = curTime; @@ -694,7 +693,7 @@ void QTimeLine::start() frame and value at regular intervals. In contrast to start(), this function does not restart the timeline before - is resumes. + it resumes. \sa start(), updateInterval(), frameChanged(), valueChanged() */ diff --git a/tests/auto/qtimeline/tst_qtimeline.cpp b/tests/auto/qtimeline/tst_qtimeline.cpp index e6e75ff01..4ce1f4b81 100644 --- a/tests/auto/qtimeline/tst_qtimeline.cpp +++ b/tests/auto/qtimeline/tst_qtimeline.cpp @@ -81,6 +81,7 @@ private slots: void outOfRange(); void stateInFinishedSignal(); void resume(); + void restart(); protected slots: void finishedSlot(); @@ -177,7 +178,7 @@ void tst_QTimeLine::currentTime() QCOMPARE(spy.count(), 1); spy.clear(); QCOMPARE(timeLine.currentTime(), timeLine.duration()/2); - timeLine.start(); + timeLine.resume(); // Let it update on its own QTest::qWait(timeLine.duration()/4); QCOMPARE(timeLine.state(), QTimeLine::Running); @@ -699,5 +700,43 @@ void tst_QTimeLine::resume() } } +void tst_QTimeLine::restart() +{ + QTimeLine timeLine(100); + timeLine.setFrameRange(0,9); + + timeLine.start(); + QTest::qWait(timeLine.duration()*2); + QCOMPARE(timeLine.currentFrame(), timeLine.endFrame()); + QCOMPARE(timeLine.state(), QTimeLine::NotRunning); + + // A restart with the same duration + timeLine.start(); + QCOMPARE(timeLine.state(), QTimeLine::Running); + QCOMPARE(timeLine.currentFrame(), timeLine.startFrame()); + QCOMPARE(timeLine.currentTime(), 0); + QTest::qWait(250); + QCOMPARE(timeLine.currentFrame(), timeLine.endFrame()); + QCOMPARE(timeLine.state(), QTimeLine::NotRunning); + + // Set a smaller duration and restart + timeLine.setDuration(50); + timeLine.start(); + QCOMPARE(timeLine.state(), QTimeLine::Running); + QCOMPARE(timeLine.currentFrame(), timeLine.startFrame()); + QCOMPARE(timeLine.currentTime(), 0); + QTest::qWait(250); + QCOMPARE(timeLine.currentFrame(), timeLine.endFrame()); + QCOMPARE(timeLine.state(), QTimeLine::NotRunning); + + // Set a longer duration and restart + timeLine.setDuration(150); + timeLine.start(); + QCOMPARE(timeLine.state(), QTimeLine::Running); + QCOMPARE(timeLine.currentFrame(), timeLine.startFrame()); + QCOMPARE(timeLine.currentTime(), 0); +} + QTEST_MAIN(tst_QTimeLine) + #include "tst_qtimeline.moc" -- cgit v1.2.3 From 7aa2d76dfc4a107f38c5cb0aac00a0b31d0fbbb6 Mon Sep 17 00:00:00 2001 From: Morten Sorvig Date: Mon, 10 Aug 2009 10:14:12 +0200 Subject: Add QBENCMARK_ONCE to QTestLib. The code block associated with QBENCHMARK_ONCE macro will only be executed once, whether the backend returns a valid result or not. The "-iterations" command line argument is also ignored. This is useful for benchmarking code that has side effects. Revby: jasplin --- src/testlib/qbenchmark.cpp | 13 +++++++++++-- src/testlib/qbenchmark.h | 10 ++++++++-- src/testlib/qbenchmark_p.h | 1 + src/testlib/qtestcase.cpp | 19 +++++++++++++++++++ .../benchlibwalltime/tst_benchlibwalltime.cpp | 11 +++++++++++ tests/auto/selftests/expected_benchlibwalltime.txt | 5 ++++- 6 files changed, 54 insertions(+), 5 deletions(-) diff --git a/src/testlib/qbenchmark.cpp b/src/testlib/qbenchmark.cpp index 9cdf23237..bad3379db 100644 --- a/src/testlib/qbenchmark.cpp +++ b/src/testlib/qbenchmark.cpp @@ -116,7 +116,7 @@ int QBenchmarkGlobalData::adjustMedianIterationCount() QBenchmarkTestMethodData *QBenchmarkTestMethodData::current; QBenchmarkTestMethodData::QBenchmarkTestMethodData() -:resultAccepted(false), iterationCount(-1) +:resultAccepted(false), runOnce(false), iterationCount(-1) { } @@ -157,6 +157,11 @@ void QBenchmarkTestMethodData::setResult(qint64 value) if (QBenchmarkGlobalData::current->iterationCount != -1) accepted = true; + if (QBenchmarkTestMethodData::current->runOnce) { + iterationCount = 1; + accepted = true; + } + // Test the result directly without calling the measurer if the minimum time // has been specifed on the command line with -minimumvalue. else if (QBenchmarkGlobalData::current->walltimeMinimum != -1) @@ -179,10 +184,12 @@ void QBenchmarkTestMethodData::setResult(qint64 value) drive the benchmarking loop. It is repsonsible for starting and stopping the timing measurements as well as calling the result reporting functions. */ -QTest::QBenchmarkIterationController::QBenchmarkIterationController() +QTest::QBenchmarkIterationController::QBenchmarkIterationController(RunMode runMode) { QTest::beginBenchmarkMeasurement(); i = 0; + if (runMode == RunOnce) + QBenchmarkTestMethodData::current->runOnce = true; } /*! \internal */ @@ -195,6 +202,8 @@ QTest::QBenchmarkIterationController::~QBenchmarkIterationController() */ bool QTest::QBenchmarkIterationController::isDone() { + if (QBenchmarkTestMethodData::current->runOnce) + return i > 0; return i >= QTest::iterationCount(); } diff --git a/src/testlib/qbenchmark.h b/src/testlib/qbenchmark.h index c06bfc082..87d34e7b6 100644 --- a/src/testlib/qbenchmark.h +++ b/src/testlib/qbenchmark.h @@ -64,7 +64,8 @@ namespace QTest class Q_TESTLIB_EXPORT QBenchmarkIterationController { public: - QBenchmarkIterationController(); + enum RunMode { RepeatUntilValidMeasurement, RunOnce }; + QBenchmarkIterationController(RunMode runMode); ~QBenchmarkIterationController(); bool isDone(); void next(); @@ -74,7 +75,12 @@ public: } #define QBENCHMARK \ - for (QTest::QBenchmarkIterationController __iteration_controller; __iteration_controller.isDone() == false; __iteration_controller.next()) + for (QTest::QBenchmarkIterationController __iteration_controller(QTest::QBenchmarkIterationController::RepeatUntilValidMeasurement); \ + __iteration_controller.isDone() == false; __iteration_controller.next()) + +#define QBENCHMARK_ONCE \ + for (QTest::QBenchmarkIterationController __iteration_controller(QTest::QBenchmarkIterationController::RunOnce); \ + __iteration_controller.isDone() == false; __iteration_controller.next()) QT_END_NAMESPACE diff --git a/src/testlib/qbenchmark_p.h b/src/testlib/qbenchmark_p.h index 25f9cdc1e..185d65693 100644 --- a/src/testlib/qbenchmark_p.h +++ b/src/testlib/qbenchmark_p.h @@ -171,6 +171,7 @@ public: QBenchmarkResult result; bool resultAccepted; + bool runOnce; int iterationCount; }; diff --git a/src/testlib/qtestcase.cpp b/src/testlib/qtestcase.cpp index 1866197d7..21a686e4a 100644 --- a/src/testlib/qtestcase.cpp +++ b/src/testlib/qtestcase.cpp @@ -351,6 +351,25 @@ QT_BEGIN_NAMESPACE {Chapter 5: Writing a Benchmark}{Writing a Benchmark} */ +/*! + \macro QBENCHMARK_ONCE + + \relates QTest + + This macro is used to measure the performance of code within a test. + The code to be benchmarked is contained within a code block following + this macro. + + Unlike QBENCHMARK, the contents of the contained code block is only run + once. The elapsed time will be reported as "0" if it's to short to + be measured by the selected backend. (Use) + + \sa {QTestLib Manual#Creating a Benchmark}{Creating a Benchmark}, + {Chapter 5: Writing a Benchmark}{Writing a Benchmark} +*/ + + + /*! \enum QTest::SkipMode This enum describes the modes for skipping tests during execution diff --git a/tests/auto/selftests/benchlibwalltime/tst_benchlibwalltime.cpp b/tests/auto/selftests/benchlibwalltime/tst_benchlibwalltime.cpp index de655995e..8474144f3 100644 --- a/tests/auto/selftests/benchlibwalltime/tst_benchlibwalltime.cpp +++ b/tests/auto/selftests/benchlibwalltime/tst_benchlibwalltime.cpp @@ -50,6 +50,7 @@ class tst_BenchlibWalltime: public QObject private slots: void waitForOneThousand(); void waitForFourThousand(); + void qbenchmark_once(); }; void tst_BenchlibWalltime::waitForOneThousand() @@ -66,6 +67,16 @@ void tst_BenchlibWalltime::waitForFourThousand() } } +void tst_BenchlibWalltime::qbenchmark_once() +{ + int iterations = 0; + QBENCHMARK_ONCE { + ++iterations; + } + QCOMPARE(iterations, 1); +} + + QTEST_MAIN(tst_BenchlibWalltime) #include "tst_benchlibwalltime.moc" diff --git a/tests/auto/selftests/expected_benchlibwalltime.txt b/tests/auto/selftests/expected_benchlibwalltime.txt index 03f246512..ec2d02040 100644 --- a/tests/auto/selftests/expected_benchlibwalltime.txt +++ b/tests/auto/selftests/expected_benchlibwalltime.txt @@ -7,6 +7,9 @@ PASS : tst_BenchlibWalltime::waitForOneThousand() RESULT : tst_BenchlibWalltime::waitForFourThousand(): 4,000 msec per iteration (total: 4000, iterations: 1) PASS : tst_BenchlibWalltime::waitForFourThousand() +RESULT : tst_BenchlibWalltime::qbenchmark_once(): + 0 msec per iteration (total: 0, iterations: 1) +PASS : tst_BenchlibWalltime::qbenchmark_once() PASS : tst_BenchlibWalltime::cleanupTestCase() -Totals: 4 passed, 0 failed, 0 skipped +Totals: 5 passed, 0 failed, 0 skipped ********* Finished testing of tst_BenchlibWalltime ********* -- cgit v1.2.3 From 76b8707e813c4b139a9ebd38b5ae0585d4afc425 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 24 Jul 2009 11:59:07 +0200 Subject: Remove spurious paranthesis in container docs --- doc/src/containers.qdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/src/containers.qdoc b/doc/src/containers.qdoc index 11a4b0b54..2a3471649 100644 --- a/doc/src/containers.qdoc +++ b/doc/src/containers.qdoc @@ -682,7 +682,7 @@ \header \o{1,2} \o{2,1} Key lookup \o{2,1} Insertion \header \o Average \o Worst case \o Average \o Worst case \row \o QMap \o O(log \e n) \o O(log \e n) \o O(log \e n) \o O(log \e n) - \row \o QMultiMap \o O((log \e n) \o O(log \e n) \o O(log \e n) \o O(log \e n) + \row \o QMultiMap \o O(log \e n) \o O(log \e n) \o O(log \e n) \o O(log \e n) \row \o QHash \o Amort. O(1) \o O(\e n) \o Amort. O(1) \o O(\e n) \row \o QSet \o Amort. O(1) \o O(\e n) \o Amort. O(1) \o O(\e n) \endtable -- cgit v1.2.3 From f0495e760e1e942481b8e0371b2700fd78519bb8 Mon Sep 17 00:00:00 2001 From: Peter Hartmann Date: Mon, 10 Aug 2009 10:57:45 +0200 Subject: Xml patterns: remove line in .pro file that added the schematron dir this line was dragged in from the Xml schema branch, but there is no schematron in Qt. Reviewed-by: TrustMe --- src/xmlpatterns/xmlpatterns.pro | 1 - 1 file changed, 1 deletion(-) diff --git a/src/xmlpatterns/xmlpatterns.pro b/src/xmlpatterns/xmlpatterns.pro index 0e6270ea7..bb8e45215 100644 --- a/src/xmlpatterns/xmlpatterns.pro +++ b/src/xmlpatterns/xmlpatterns.pro @@ -22,7 +22,6 @@ include($$PWD/janitors/janitors.pri) include($$PWD/parser/parser.pri) include($$PWD/projection/projection.pri) include($$PWD/schema/schema.pri) -include($$PWD/schematron/schematron.pri) include($$PWD/type/type.pri) include($$PWD/utils/utils.pri) include($$PWD/qobjectmodel/qobjectmodel.pri, "", true) -- cgit v1.2.3 From 89f0156b21b4cff8fec0cee283d75f413cf36c61 Mon Sep 17 00:00:00 2001 From: Harald Fernengel Date: Mon, 10 Aug 2009 11:10:03 +0200 Subject: Link with winscw again compiler mangles "struct" and "class" differently, so make sure that QTestCharBuffer is always forward declared as "struct". --- src/testlib/qtestbasicstreamer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/testlib/qtestbasicstreamer.h b/src/testlib/qtestbasicstreamer.h index cabbf3498..932f5c3ec 100644 --- a/src/testlib/qtestbasicstreamer.h +++ b/src/testlib/qtestbasicstreamer.h @@ -53,7 +53,7 @@ QT_MODULE(Test) class QTestElement; class QTestElementAttribute; class QTestLogger; -class QTestCharBuffer; +struct QTestCharBuffer; class QTestBasicStreamer { -- cgit v1.2.3 From 167b333e2c428947264f283f6eec275b27f8f0db Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Mon, 10 Aug 2009 11:21:48 +0200 Subject: Fix default QWidget size on X servers with Xinerama The default widget size is normally calculated from the root window size, but when running on an X server with Xinerama enabled, the root window spans all screens, making the widget far to large. Use the default screen's size instead to give the widget a size that should fit on a single screen. --- src/gui/kernel/qwidget_x11.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/gui/kernel/qwidget_x11.cpp b/src/gui/kernel/qwidget_x11.cpp index 2a3d2f34e..cf65af3d4 100644 --- a/src/gui/kernel/qwidget_x11.cpp +++ b/src/gui/kernel/qwidget_x11.cpp @@ -512,6 +512,13 @@ void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyO dialog = popup = false; // force these flags off data.crect.setRect(0, 0, sw, sh); } else if (topLevel && !q->testAttribute(Qt::WA_Resized)) { + QDesktopWidget *desktopWidget = qApp->desktop(); + if (desktopWidget->isVirtualDesktop()) { + QRect r = desktopWidget->screenGeometry(); + sw = r.width(); + sh = r.height(); + } + int width = sw / 2; int height = 4 * sh / 10; if (extra) { -- cgit v1.2.3 From 468b157ab5496cdab6ff751312dba5376901d533 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan-Arve=20S=C3=A6ther?= Date: Mon, 10 Aug 2009 12:47:31 +0200 Subject: Whitespace cleanup --- src/corelib/tools/qtimeline.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/corelib/tools/qtimeline.cpp b/src/corelib/tools/qtimeline.cpp index 7402ba6ba..b6511d5c6 100644 --- a/src/corelib/tools/qtimeline.cpp +++ b/src/corelib/tools/qtimeline.cpp @@ -212,7 +212,7 @@ void QTimeLinePrivate::setCurrentTime(int msecs) applies an interpolation algorithm to generate these value. You can choose from a set of predefined timeline algorithms by calling setCurveShape(). - + Note that by default, QTimeLine uses the EaseInOut curve shape, which provides a value that grows slowly, then grows steadily, and finally grows slowly. For a custom timeline, you can reimplement @@ -549,7 +549,7 @@ void QTimeLine::setCurveShape(CurveShape shape) case CosineCurve: setEasingCurve(QEasingCurve(QEasingCurve::CosineCurve)); break; - } + } } /*! @@ -559,7 +559,7 @@ void QTimeLine::setCurveShape(CurveShape shape) Specifies the easing curve that the timeline will use. If both easing curve and curveShape are set, the last set property will - override the previous one. (If valueForTime() is reimplemented it will + override the previous one. (If valueForTime() is reimplemented it will override both) */ -- cgit v1.2.3 From ec1a146dd7f8582d3053ed54420d26141e98155c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan-Arve=20S=C3=A6ther?= Date: Mon, 10 Aug 2009 12:48:13 +0200 Subject: Remove unused member. --- src/corelib/tools/qtimeline.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/corelib/tools/qtimeline.cpp b/src/corelib/tools/qtimeline.cpp index b6511d5c6..6dbad3424 100644 --- a/src/corelib/tools/qtimeline.cpp +++ b/src/corelib/tools/qtimeline.cpp @@ -69,7 +69,6 @@ public: int currentLoopCount; int currentTime; - int elapsedTime; int timerId; QTime timer; -- cgit v1.2.3 From 17bffacda99055831bb4c8c6e7da39ec15415519 Mon Sep 17 00:00:00 2001 From: Leonardo Sobral Cunha Date: Mon, 10 Aug 2009 13:01:34 +0200 Subject: Moved tests/auto/runQtXmlPatternsTests.sh to devtools/shell --- tests/auto/runQtXmlPatternsTests.sh | 61 ------------------------------------- 1 file changed, 61 deletions(-) delete mode 100755 tests/auto/runQtXmlPatternsTests.sh diff --git a/tests/auto/runQtXmlPatternsTests.sh b/tests/auto/runQtXmlPatternsTests.sh deleted file mode 100755 index 41d6c83ef..000000000 --- a/tests/auto/runQtXmlPatternsTests.sh +++ /dev/null @@ -1,61 +0,0 @@ -#!/bin/sh -# Runs all the tests specific to QtXmlPatterns in one go. - -# If you add a test, remember to update ./auto.pro too. -# checkxmlfiles is not part of Patternist, but since it shares test code -# and use Patternist, we include it as well. -# -# Sorted alphabetically, with the difference that xmlpatternsxqts appears -# before xmlpattersview, xmlpatternsdiagnosticsts, and xmlpatternsxslts, since -# they have the former as dependency. -tests=" \ -checkxmlfiles \ -patternistexamplefiletree \ -patternistexamples \ -patternistheaders \ -qabstractmessagehandler \ -qabstracturiresolver \ -qabstractxmlforwarditerator \ -qabstractxmlnodemodel \ -qabstractxmlreceiver \ -qapplicationargumentparser \ -qautoptr \ -qsimplexmlnodemodel \ -qsourcelocation \ -qtokenautomaton \ -qxmlformatter \ -qxmlitem \ -qxmlname \ -qxmlnamepool \ -qxmlnodemodelindex \ -qxmlquery \ -qxmlresultitems \ -qxmlserializer \ -xmlpatterns \ -xmlpatternsxqts \ -xmlpatternsdiagnosticsts \ -xmlpatternsschema \ -xmlpatternsschemats \ -xmlpatternsview \ -xmlpatternsxslts" - -os=`uname` - -for test in $tests; do - cd $test - make distclean - qmake - make - - if [ $os = "Darwin" ]; then - ./tst_"$test".app/Contents/MacOS/tst_"$test" - else - ./tst_$test - fi - - if [ $? -ne 0 ]; then - exit $? - else - cd .. - fi -done -- cgit v1.2.3 From 47f58dfad1eb7fe61a523597023df33f3d320377 Mon Sep 17 00:00:00 2001 From: Denis Dzyubenko Date: Sat, 8 Aug 2009 23:58:46 +0200 Subject: Made the QGesture::reset function protected. By default the QGesture::reset function is protected, and it can be made public in the derived class if necessary. Reviewed-by: trustme --- src/gui/kernel/qgesture.h | 3 +-- src/gui/kernel/qstandardgestures.h | 4 +++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/gui/kernel/qgesture.h b/src/gui/kernel/qgesture.h index 7da37c403..839fdcad1 100644 --- a/src/gui/kernel/qgesture.h +++ b/src/gui/kernel/qgesture.h @@ -73,14 +73,13 @@ public: void setGraphicsItem(QGraphicsItem *); QGraphicsItem *graphicsItem() const; - virtual void reset(); - Qt::GestureState state() const; protected: QGesture(QGesturePrivate &dd, QObject *parent); bool eventFilter(QObject*, QEvent*); + virtual void reset(); void updateState(Qt::GestureState state); Q_SIGNALS: diff --git a/src/gui/kernel/qstandardgestures.h b/src/gui/kernel/qstandardgestures.h index c734fbafe..03a1374c7 100644 --- a/src/gui/kernel/qstandardgestures.h +++ b/src/gui/kernel/qstandardgestures.h @@ -66,11 +66,13 @@ public: QPanGesture(QWidget *parent); bool filterEvent(QEvent *event); - void reset(); QSize totalOffset() const; QSize lastOffset() const; +protected: + void reset(); + private: bool event(QEvent *event); bool eventFilter(QObject *receiver, QEvent *event); -- cgit v1.2.3 From 6826490774d66e0470fc1e5848ab89b3a0d0bb86 Mon Sep 17 00:00:00 2001 From: Denis Dzyubenko Date: Wed, 5 Aug 2009 18:57:25 +0200 Subject: Implemented QPinchGesture. Added a new standard gesture, which is implemented using a native zoom and rotate gestures on Windows and with a direct touch event handling on other platforms. Improved pan support - we subscribe to native pan gesture only when it's really needed, and we pass proper flags for single finger horizontal/vertical panning. Reviewed-by: Richard Moe Gustavsen --- src/gui/kernel/qapplication_p.h | 3 + src/gui/kernel/qapplication_win.cpp | 21 ++-- src/gui/kernel/qevent_p.h | 5 +- src/gui/kernel/qstandardgestures.cpp | 210 ++++++++++++++++++++++++++++++++++- src/gui/kernel/qstandardgestures.h | 39 +++++++ src/gui/kernel/qstandardgestures_p.h | 25 +++++ src/gui/kernel/qwidget_win.cpp | 40 ++++--- 7 files changed, 316 insertions(+), 27 deletions(-) diff --git a/src/gui/kernel/qapplication_p.h b/src/gui/kernel/qapplication_p.h index c4ce2ea4d..995390710 100644 --- a/src/gui/kernel/qapplication_p.h +++ b/src/gui/kernel/qapplication_p.h @@ -235,6 +235,7 @@ typedef struct tagGESTUREINFO # define GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY 0x00000004 # define GC_ZOOM 0x00000001 +# define GC_ROTATE 0x00000001 typedef struct tagGESTURECONFIG { @@ -243,6 +244,8 @@ typedef struct tagGESTURECONFIG DWORD dwBlock; } GESTURECONFIG; +# define GID_ROTATE_ANGLE_FROM_ARGUMENT(arg) ((((double)(arg) / 65535.0) * 4.0 * 3.14159265) - 2.0*3.14159265) + #endif // WM_GESTURE #endif // Q_WS_WIN diff --git a/src/gui/kernel/qapplication_win.cpp b/src/gui/kernel/qapplication_win.cpp index bdee6ecd0..cb6740975 100644 --- a/src/gui/kernel/qapplication_win.cpp +++ b/src/gui/kernel/qapplication_win.cpp @@ -3721,17 +3721,18 @@ bool QETWidget::translateGestureEvent(const MSG &msg) QApplicationPrivate *qAppPriv = getQApplicationPrivateInternal(); BOOL bResult = qAppPriv->GetGestureInfo((HANDLE)msg.lParam, &gi); + if (bResult) { + const QPoint widgetPos = QPoint(gi.ptsLocation.x, gi.ptsLocation.y); + QWidget *alienWidget = !internalWinId() ? this : childAt(widgetPos); + if (alienWidget && alienWidget->internalWinId()) + alienWidget = 0; + QWidget *widget = alienWidget ? alienWidget : this; - const QPoint widgetPos = QPoint(gi.ptsLocation.x, gi.ptsLocation.y); - QWidget *alienWidget = !internalWinId() ? this : childAt(widgetPos); - if (alienWidget && alienWidget->internalWinId()) - alienWidget = 0; - QWidget *widget = alienWidget ? alienWidget : this; + QNativeGestureEvent event; + event.sequenceId = gi.dwSequenceID; + event.position = QPoint(gi.ptsLocation.x, gi.ptsLocation.y); + event.argument = gi.ullArguments; - QNativeGestureEvent event; - event.sequenceId = gi.dwSequenceID; - event.position = QPoint(gi.ptsLocation.x, gi.ptsLocation.y); - if (bResult) { switch (gi.dwID) { case GID_BEGIN: event.gestureType = QNativeGestureEvent::GestureBegin; @@ -3746,6 +3747,8 @@ bool QETWidget::translateGestureEvent(const MSG &msg) event.gestureType = QNativeGestureEvent::Pan; break; case GID_ROTATE: + event.gestureType = QNativeGestureEvent::Rotate; + break; case GID_TWOFINGERTAP: case GID_ROLLOVER: default: diff --git a/src/gui/kernel/qevent_p.h b/src/gui/kernel/qevent_p.h index b21b35c36..2ff672bb1 100644 --- a/src/gui/kernel/qevent_p.h +++ b/src/gui/kernel/qevent_p.h @@ -133,9 +133,9 @@ public: }; QNativeGestureEvent() - : QEvent(QEvent::NativeGesture), gestureType(None), percentage(0), direction(0, 0) + : QEvent(QEvent::NativeGesture), gestureType(None), percentage(0) #ifdef Q_WS_WIN - , sequenceId(0) + , sequenceId(0), argument(0) #endif { } @@ -146,6 +146,7 @@ public: QSize direction; #ifdef Q_WS_WIN ulong sequenceId; + quint64 argument; #endif }; diff --git a/src/gui/kernel/qstandardgestures.cpp b/src/gui/kernel/qstandardgestures.cpp index 7078dbf0f..ac03cd247 100644 --- a/src/gui/kernel/qstandardgestures.cpp +++ b/src/gui/kernel/qstandardgestures.cpp @@ -132,8 +132,7 @@ bool QPanGesture::eventFilter(QObject *receiver, QEvent *event) it = qAppPriv->widgetGestures.find(static_cast(receiver)); if (it == qAppPriv->widgetGestures.end()) return false; - QPanGesture *gesture = it.value().pan; - if (this != gesture) + if (this != it.value().pan) return false; Qt::GestureState nextState = Qt::NoGesture; switch(ev->gestureType) { @@ -162,7 +161,7 @@ bool QPanGesture::eventFilter(QObject *receiver, QEvent *event) d->totalOffset += d->lastOffset; } d->lastPosition = ev->position; - gesture->updateState(nextState); + updateState(nextState); return true; } #endif @@ -248,6 +247,7 @@ void QPanGesture::reset() d->panFinishedTimer = 0; } #endif + QGesture::reset(); } /*! @@ -273,6 +273,210 @@ QSize QPanGesture::lastOffset() const return d->lastOffset; } + +/*! + \class QPinchGesture + \since 4.6 + + \brief The QPinchGesture class represents a Pinch gesture, + providing additional information related to zooming and/or rotation. +*/ + +/*! + Creates a new Pinch gesture handler object and marks it as a child of \a + parent. + + On some platform like Windows it's necessary to provide a non-null widget + as \a parent to get native gesture support. +*/ +QPinchGesture::QPinchGesture(QWidget *parent) + : QGesture(*new QPinchGesturePrivate, parent) +{ + if (parent) { + QApplicationPrivate *qAppPriv = getQApplicationPrivateInternal(); + qAppPriv->widgetGestures[parent].pinch = this; +#ifdef Q_WS_WIN + qt_widget_private(parent)->winSetupGestures(); +#endif + } +} + +/*! \internal */ +bool QPinchGesture::event(QEvent *event) +{ + switch (event->type()) { + case QEvent::ParentAboutToChange: + if (QWidget *w = qobject_cast(parent())) { + getQApplicationPrivateInternal()->widgetGestures[w].pinch = 0; +#ifdef Q_WS_WIN + qt_widget_private(w)->winSetupGestures(); +#endif + } + break; + case QEvent::ParentChange: + if (QWidget *w = qobject_cast(parent())) { + getQApplicationPrivateInternal()->widgetGestures[w].pinch = this; +#ifdef Q_WS_WIN + qt_widget_private(w)->winSetupGestures(); +#endif + } + break; + default: + break; + } + return QObject::event(event); +} + +bool QPinchGesture::eventFilter(QObject *receiver, QEvent *event) +{ +#ifdef Q_WS_WIN + Q_D(QPinchGesture); + if (receiver->isWidgetType() && event->type() == QEvent::NativeGesture) { + QNativeGestureEvent *ev = static_cast(event); + QApplicationPrivate *qAppPriv = getQApplicationPrivateInternal(); + QApplicationPrivate::WidgetStandardGesturesMap::iterator it; + it = qAppPriv->widgetGestures.find(static_cast(receiver)); + if (it == qAppPriv->widgetGestures.end()) + return false; + if (this != it.value().pinch) + return false; + Qt::GestureState nextState = Qt::NoGesture; + switch(ev->gestureType) { + case QNativeGestureEvent::GestureBegin: + // next we might receive the first gesture update event, so we + // prepare for it. + d->state = Qt::NoGesture; + d->scaleFactor = d->lastScaleFactor = 1; + d->rotationAngle = d->lastRotationAngle = 0; + d->startCenterPoint = d->centerPoint = d->lastCenterPoint = QPoint(); + d->initialDistance = 0; + return false; + case QNativeGestureEvent::Rotate: + d->lastRotationAngle = d->rotationAngle; + d->rotationAngle = -1 * GID_ROTATE_ANGLE_FROM_ARGUMENT(ev->argument); + nextState = Qt::GestureUpdated; + event->accept(); + break; + case QNativeGestureEvent::Zoom: + if (d->initialDistance != 0) { + d->lastScaleFactor = d->scaleFactor; + int distance = int(qint64(ev->argument)); + d->scaleFactor = (qreal) distance / d->initialDistance; + } else { + d->initialDistance = int(qint64(ev->argument)); + } + nextState = Qt::GestureUpdated; + event->accept(); + break; + case QNativeGestureEvent::GestureEnd: + if (state() == Qt::NoGesture) + return false; // some other gesture has ended + nextState = Qt::GestureFinished; + break; + default: + return false; + } + if (d->startCenterPoint.isNull()) + d->startCenterPoint = d->centerPoint; + d->lastCenterPoint = d->centerPoint; + d->centerPoint = static_cast(receiver)->mapFromGlobal(ev->position); + updateState(nextState); + return true; + } +#endif + return QGesture::eventFilter(receiver, event); +} + +/*! \internal */ +bool QPinchGesture::filterEvent(QEvent *event) +{ + Q_UNUSED(event); + return false; +} + +/*! \internal */ +void QPinchGesture::reset() +{ + Q_D(QPinchGesture); + d->scaleFactor = d->lastScaleFactor = 0; + d->rotationAngle = d->lastRotationAngle = 0; + d->startCenterPoint = d->centerPoint = d->lastCenterPoint = QPoint(); + QGesture::reset(); +} + +/*! + \property QPinchGesture::scaleFactor + + Specifies a scale factor of the pinch gesture. +*/ +qreal QPinchGesture::scaleFactor() const +{ + return d_func()->scaleFactor; +} + +/*! + \property QPinchGesture::lastScaleFactor + + Specifies a previous scale factor of the pinch gesture. +*/ +qreal QPinchGesture::lastScaleFactor() const +{ + return d_func()->lastScaleFactor; +} + +/*! + \property QPinchGesture::rotationAngle + + Specifies a rotation angle of the gesture. +*/ +qreal QPinchGesture::rotationAngle() const +{ + return d_func()->rotationAngle; +} + +/*! + \property QPinchGesture::lastRotationAngle + + Specifies a previous rotation angle of the gesture. +*/ +qreal QPinchGesture::lastRotationAngle() const +{ + return d_func()->lastRotationAngle; +} + +/*! + \property QPinchGesture::centerPoint + + Specifies a center point of the gesture. The point can be used as a center + point that the object is rotated around. +*/ +QPoint QPinchGesture::centerPoint() const +{ + return d_func()->centerPoint; +} + +/*! + \property QPinchGesture::lastCenterPoint + + Specifies a previous center point of the gesture. +*/ +QPoint QPinchGesture::lastCenterPoint() const +{ + return d_func()->lastCenterPoint; +} + +/*! + \property QPinchGesture::startCenterPoint + + Specifies an initial center point of the gesture. Difference between the + startCenterPoint and the centerPoint is the distance at which pinching + fingers has shifted. +*/ +QPoint QPinchGesture::startCenterPoint() const +{ + return d_func()->startCenterPoint; +} + QT_END_NAMESPACE #include "moc_qstandardgestures.cpp" diff --git a/src/gui/kernel/qstandardgestures.h b/src/gui/kernel/qstandardgestures.h index 03a1374c7..adee74074 100644 --- a/src/gui/kernel/qstandardgestures.h +++ b/src/gui/kernel/qstandardgestures.h @@ -80,6 +80,45 @@ private: friend class QWidget; }; +class QPinchGesturePrivate; +class Q_GUI_EXPORT QPinchGesture : public QGesture +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QPinchGesture) + + Q_PROPERTY(qreal scaleFactor READ scaleFactor) + Q_PROPERTY(qreal lastScaleFactor READ lastScaleFactor) + + Q_PROPERTY(qreal rotationAngle READ rotationAngle) + Q_PROPERTY(qreal lastRotationAngle READ lastRotationAngle) + + Q_PROPERTY(QPoint startCenterPoint READ startCenterPoint) + Q_PROPERTY(QPoint lastCenterPoint READ lastCenterPoint) + Q_PROPERTY(QPoint centerPoint READ centerPoint) + +public: + QPinchGesture(QWidget *parent); + + bool filterEvent(QEvent *event); + void reset(); + + QPoint startCenterPoint() const; + QPoint lastCenterPoint() const; + QPoint centerPoint() const; + + qreal scaleFactor() const; + qreal lastScaleFactor() const; + + qreal rotationAngle() const; + qreal lastRotationAngle() const; + +private: + bool event(QEvent *event); + bool eventFilter(QObject *receiver, QEvent *event); + + friend class QWidget; +}; + QT_END_NAMESPACE QT_END_HEADER diff --git a/src/gui/kernel/qstandardgestures_p.h b/src/gui/kernel/qstandardgestures_p.h index 0fe24ee89..43636d09c 100644 --- a/src/gui/kernel/qstandardgestures_p.h +++ b/src/gui/kernel/qstandardgestures_p.h @@ -85,6 +85,31 @@ public: #endif }; +class QPinchGesturePrivate : public QGesturePrivate +{ + Q_DECLARE_PUBLIC(QPinchGesture) + +public: + QPinchGesturePrivate() + : scaleFactor(0), lastScaleFactor(0), + rotationAngle(0), lastRotationAngle(0) +#ifdef Q_WS_WIN + ,initialDistance(0) +#endif + { + } + qreal scaleFactor; + qreal lastScaleFactor; + qreal rotationAngle; + qreal lastRotationAngle; + QPoint startCenterPoint; + QPoint lastCenterPoint; + QPoint centerPoint; +#ifdef Q_WS_WIN + int initialDistance; +#endif +}; + QT_END_NAMESPACE #endif // QSTANDARDGESTURES_P_H diff --git a/src/gui/kernel/qwidget_win.cpp b/src/gui/kernel/qwidget_win.cpp index 7cfa111ad..510df7feb 100644 --- a/src/gui/kernel/qwidget_win.cpp +++ b/src/gui/kernel/qwidget_win.cpp @@ -1160,6 +1160,8 @@ void QWidgetPrivate::show_sys() data.window_state |= Qt::WindowMaximized; } + winSetupGestures(); + invalidateBuffer(q->rect()); } #endif //Q_WS_WINCE @@ -2058,8 +2060,11 @@ void QWidgetPrivate::winSetupGestures() Q_Q(QWidget); if (!q) return; - extern QApplicationPrivate* getQApplicationPrivateInternal(); - QApplicationPrivate *qAppPriv = getQApplicationPrivateInternal(); + q->setAttribute(Qt::WA_DontCreateNativeAncestors); + q->setAttribute(Qt::WA_NativeWindow); + if (!q->isVisible()) + return; + QApplicationPrivate *qAppPriv = QApplicationPrivate::instance(); bool needh = false; bool needv = false; bool singleFingerPanEnabled = false; @@ -2072,34 +2077,43 @@ void QWidgetPrivate::winSetupGestures() QScrollBar *vbar = asa->verticalScrollBar(); Qt::ScrollBarPolicy hbarpolicy = asa->horizontalScrollBarPolicy(); Qt::ScrollBarPolicy vbarpolicy = asa->verticalScrollBarPolicy(); - needh = (hbarpolicy == Qt::ScrollBarAlwaysOn - || (hbarpolicy == Qt::ScrollBarAsNeeded && hbar->minimum() < hbar->maximum())); - needv = (vbarpolicy == Qt::ScrollBarAlwaysOn - || (vbarpolicy == Qt::ScrollBarAsNeeded && vbar->minimum() < vbar->maximum())); + needh = (hbarpolicy == Qt::ScrollBarAlwaysOn || + (hbarpolicy == Qt::ScrollBarAsNeeded && hbar->minimum() < hbar->maximum())); + needv = (vbarpolicy == Qt::ScrollBarAlwaysOn || + (vbarpolicy == Qt::ScrollBarAsNeeded && vbar->minimum() < vbar->maximum())); singleFingerPanEnabled = asa->d_func()->singleFingerPanEnabled; } else { winid = q->winId(); } if (qAppPriv->SetGestureConfig) { - GESTURECONFIG gc[2]; + GESTURECONFIG gc[3]; + memset(gc, 0, sizeof(gc)); gc[0].dwID = GID_PAN; - if (gestures.pan || needh || needv) { + if (gestures.pan) { gc[0].dwWant = GC_PAN; - gc[0].dwBlock = 0; if (needv && singleFingerPanEnabled) gc[0].dwWant |= GC_PAN_WITH_SINGLE_FINGER_VERTICALLY; + else + gc[0].dwBlock |= GC_PAN_WITH_SINGLE_FINGER_VERTICALLY; if (needh && singleFingerPanEnabled) gc[0].dwWant |= GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY; + else + gc[0].dwBlock |= GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY; } else { - gc[0].dwWant = 0; gc[0].dwBlock = GC_PAN; } gc[1].dwID = GID_ZOOM; - if (gestures.pinch) { + if (gestures.pinch) gc[1].dwWant = GC_ZOOM; - gc[1].dwBlock = 0; - } + else + gc[1].dwBlock = GC_ZOOM; + gc[2].dwID = GID_ROTATE; + if (gestures.pinch) + gc[2].dwWant = GC_ROTATE; + else + gc[2].dwBlock = GC_ROTATE; + Q_ASSERT(winid); qAppPriv->SetGestureConfig(winid, 0, sizeof(gc)/sizeof(gc[0]), gc, sizeof(gc[0])); } -- cgit v1.2.3 From 65ba2c18a9a3ec82331c0ccab47edc8e252192df Mon Sep 17 00:00:00 2001 From: Thierry Bastian Date: Mon, 10 Aug 2009 13:45:24 +0200 Subject: Fixed an assert that could happen when the mediaSource is deleted When using streaming, it could happen that the last reference to the MediaSource is in another thread. So the objects are destroyed from another thread. In which case we would delete QObject (ioDevice) in another thread. That is fixed by calling deleteLater which will ensure that they are deleted in their own thread. Note: there was a nother assert that could happen due to a race condition in the worker thread. That is also fixed with this patch. Reviewed-by: jbache --- src/3rdparty/phonon/ds9/mediaobject.cpp | 55 ++++++++++-------------------- src/3rdparty/phonon/ds9/mediaobject.h | 1 - src/3rdparty/phonon/phonon/mediasource.cpp | 8 +++-- 3 files changed, 24 insertions(+), 40 deletions(-) diff --git a/src/3rdparty/phonon/ds9/mediaobject.cpp b/src/3rdparty/phonon/ds9/mediaobject.cpp index 10782c251..b163ad4dd 100644 --- a/src/3rdparty/phonon/ds9/mediaobject.cpp +++ b/src/3rdparty/phonon/ds9/mediaobject.cpp @@ -57,24 +57,6 @@ namespace Phonon { } - WorkerThread::Work WorkerThread::dequeueWork() - { - QMutexLocker locker(&m_mutex); - if (m_finished) { - return Work(); - } - Work ret = m_queue.dequeue(); - - //we ensure to have the wait condition in the right state - if (m_queue.isEmpty()) { - m_waitCondition.reset(); - } else { - m_waitCondition.set(); - } - - return ret; - } - void WorkerThread::run() { while (m_finished == false) { @@ -88,11 +70,6 @@ namespace Phonon } DWORD result = ::WaitForMultipleObjects(count, handles, FALSE, INFINITE); if (result == WAIT_OBJECT_0) { - if (m_finished) { - //that's the end of the thread execution - return; - } - handleTask(); } else { //this is the event management @@ -199,22 +176,25 @@ namespace Phonon void WorkerThread::handleTask() { - const Work w = dequeueWork(); - - if (m_finished) { + QMutexLocker locker(&m_mutex); + if (m_finished || m_queue.isEmpty()) { return; } - HRESULT hr = S_OK; + const Work w = m_queue.dequeue(); - { - QMutexLocker locker(&m_mutex); - m_currentRender = w.graph; - m_currentRenderId = w.id; + //we ensure to have the wait condition in the right state + if (m_queue.isEmpty()) { + m_waitCondition.reset(); + } else { + m_waitCondition.set(); } + HRESULT hr = S_OK; + + m_currentRender = w.graph; + m_currentRenderId = w.id; if (w.task == ReplaceGraph) { - QMutexLocker locker(&m_mutex); int index = -1; for(int i = 0; i < FILTER_COUNT; ++i) { if (m_graphHandle[i].graph == w.oldGraph) { @@ -237,6 +217,9 @@ namespace Phonon m_graphHandle[index].handle = h; } } else if (w.task == Render) { + //we need to unlock here because the use might trigger a call to abort + //which uses the same mutex + locker.unlock(); if (w.filter) { //let's render pins w.graph->AddFilter(w.filter, 0); @@ -255,6 +238,7 @@ namespace Phonon if (hr != E_ABORT) { emit asyncRenderFinished(w.id, hr, w.graph); } + locker.relock(); } else if (w.task == Seek) { //that's a seekrequest ComPointer mediaSeeking(w.graph, IID_IMediaSeeking); @@ -327,11 +311,8 @@ namespace Phonon } } - { - QMutexLocker locker(&m_mutex); - m_currentRender = Graph(); - m_currentRenderId = 0; - } + m_currentRender = Graph(); + m_currentRenderId = 0; } void WorkerThread::abortCurrentRender(qint16 renderId) diff --git a/src/3rdparty/phonon/ds9/mediaobject.h b/src/3rdparty/phonon/ds9/mediaobject.h index 2c34ffc35..fe52604ae 100644 --- a/src/3rdparty/phonon/ds9/mediaobject.h +++ b/src/3rdparty/phonon/ds9/mediaobject.h @@ -135,7 +135,6 @@ namespace Phonon }; QList decoders; //for the state change requests }; - Work dequeueWork(); void handleTask(); Graph m_currentRender; diff --git a/src/3rdparty/phonon/phonon/mediasource.cpp b/src/3rdparty/phonon/phonon/mediasource.cpp index 0a21c8766..c003af988 100644 --- a/src/3rdparty/phonon/phonon/mediasource.cpp +++ b/src/3rdparty/phonon/phonon/mediasource.cpp @@ -140,8 +140,12 @@ MediaSourcePrivate::~MediaSourcePrivate() { #ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM if (autoDelete) { - delete stream; - delete ioDevice; + //here we use deleteLater because this object + //might be destroyed from another thread + if (stream) + stream->deleteLater(); + if (ioDevice) + ioDevice->deleteLater(); } #endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM } -- cgit v1.2.3 From 2a1dcf7a47d81ad8b492c312dfd5e422ba2e3cd0 Mon Sep 17 00:00:00 2001 From: Martin Smith Date: Mon, 10 Aug 2009 14:57:30 +0200 Subject: qdoc: List the NOTIFY signal function in the property doc. --- tools/qdoc3/cppcodeparser.cpp | 3 +++ tools/qdoc3/generator.cpp | 2 +- tools/qdoc3/htmlgenerator.cpp | 8 ++++++++ tools/qdoc3/node.h | 5 +++-- tools/qdoc3/tree.cpp | 3 +++ 5 files changed, 18 insertions(+), 3 deletions(-) diff --git a/tools/qdoc3/cppcodeparser.cpp b/tools/qdoc3/cppcodeparser.cpp index 562684b4d..12ec7f3a9 100644 --- a/tools/qdoc3/cppcodeparser.cpp +++ b/tools/qdoc3/cppcodeparser.cpp @@ -1737,6 +1737,9 @@ bool CppCodeParser::matchProperty(InnerNode *parent) property->setDesignable(value.toLower() == "true"); else if (key == "RESET") tre->addPropertyFunction(property, value, PropertyNode::Resetter); + else if (key == "NOTIFY") { + tre->addPropertyFunction(property, value, PropertyNode::Notifier); + } } match(Tok_RightParen); return true; diff --git a/tools/qdoc3/generator.cpp b/tools/qdoc3/generator.cpp index e92f53b45..9538dfe75 100644 --- a/tools/qdoc3/generator.cpp +++ b/tools/qdoc3/generator.cpp @@ -283,7 +283,7 @@ bool Generator::generateText(const Text& text, bool Generator::generateQmlText(const Text& text, const Node *relative, CodeMarker *marker, - const QString& qmlName) + const QString& /* qmlName */ ) { const Atom* atom = text.firstAtom(); if (atom == 0) diff --git a/tools/qdoc3/htmlgenerator.cpp b/tools/qdoc3/htmlgenerator.cpp index 26874e16c..c203c6258 100644 --- a/tools/qdoc3/htmlgenerator.cpp +++ b/tools/qdoc3/htmlgenerator.cpp @@ -3420,6 +3420,14 @@ void HtmlGenerator::generateDetailedMember(const Node *node, out() << "

Access functions:

\n"; generateSectionList(section, node, marker, CodeMarker::Accessors); } + + Section notifiers; + notifiers.members += property->notifiers(); + + if (!notifiers.members.isEmpty()) { + out() << "

Notifier signal:

\n"; + generateSectionList(notifiers, node, marker, CodeMarker::Accessors); + } } else if (node->type() == Node::Enum) { const EnumNode *enume = static_cast(node); diff --git a/tools/qdoc3/node.h b/tools/qdoc3/node.h index 17ec4479c..61f2a76d8 100644 --- a/tools/qdoc3/node.h +++ b/tools/qdoc3/node.h @@ -590,8 +590,8 @@ class FunctionNode : public LeafNode class PropertyNode : public LeafNode { public: - enum FunctionRole { Getter, Setter, Resetter }; - enum { NumFunctionRoles = Resetter + 1 }; + enum FunctionRole { Getter, Setter, Resetter, Notifier }; + enum { NumFunctionRoles = Notifier + 1 }; PropertyNode(InnerNode *parent, const QString& name); virtual ~PropertyNode() { } @@ -609,6 +609,7 @@ class PropertyNode : public LeafNode NodeList getters() const { return functions(Getter); } NodeList setters() const { return functions(Setter); } NodeList resetters() const { return functions(Resetter); } + NodeList notifiers() const { return functions(Notifier); } bool isStored() const { return fromTrool(sto, storedDefault()); } bool isDesignable() const { return fromTrool(des, designableDefault()); } const PropertyNode *overriddenFrom() const { return overrides; } diff --git a/tools/qdoc3/tree.cpp b/tools/qdoc3/tree.cpp index f8320621e..a5e22f1c0 100644 --- a/tools/qdoc3/tree.cpp +++ b/tools/qdoc3/tree.cpp @@ -485,6 +485,7 @@ void Tree::resolveProperties() QString getterName = (*propEntry)[PropertyNode::Getter]; QString setterName = (*propEntry)[PropertyNode::Setter]; QString resetterName = (*propEntry)[PropertyNode::Resetter]; + QString notifierName = (*propEntry)[PropertyNode::Notifier]; NodeList::ConstIterator c = parent->childNodes().begin(); while (c != parent->childNodes().end()) { @@ -499,6 +500,8 @@ void Tree::resolveProperties() property->addFunction(function, PropertyNode::Setter); } else if (function->name() == resetterName) { property->addFunction(function, PropertyNode::Resetter); + } else if (function->name() == notifierName) { + property->addFunction(function, PropertyNode::Notifier); } } } -- cgit v1.2.3 From 4fe7c464be95fbbcb663a21f9519024486123248 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 10 Aug 2009 11:26:01 +0200 Subject: Compile fix with namespaces --- examples/statemachine/rogue/window.h | 2 ++ src/corelib/kernel/qeventdispatcher_unix.cpp | 2 +- src/corelib/tools/qsharedpointer.cpp | 10 ++++++++++ src/gui/graphicsview/qgraphicstransform_p.h | 4 ++++ src/gui/image/qimagepixmapcleanuphooks.cpp | 3 +++ src/network/access/qnetworkcookie.h | 6 +++--- 6 files changed, 23 insertions(+), 4 deletions(-) diff --git a/examples/statemachine/rogue/window.h b/examples/statemachine/rogue/window.h index bcd86bd8a..1df566d8d 100644 --- a/examples/statemachine/rogue/window.h +++ b/examples/statemachine/rogue/window.h @@ -44,9 +44,11 @@ #include +QT_BEGIN_NAMESPACE class QState; class QStateMachine; class QTransition; +QT_END_NAMESPACE #define WIDTH 35 #define HEIGHT 20 diff --git a/src/corelib/kernel/qeventdispatcher_unix.cpp b/src/corelib/kernel/qeventdispatcher_unix.cpp index 7982d4cb7..da151481b 100644 --- a/src/corelib/kernel/qeventdispatcher_unix.cpp +++ b/src/corelib/kernel/qeventdispatcher_unix.cpp @@ -627,7 +627,7 @@ QEventDispatcherUNIX::~QEventDispatcherUNIX() int QEventDispatcherUNIX::select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, timeval *timeout) { - return ::qt_safe_select(nfds, readfds, writefds, exceptfds, timeout); + return qt_safe_select(nfds, readfds, writefds, exceptfds, timeout); } /*! diff --git a/src/corelib/tools/qsharedpointer.cpp b/src/corelib/tools/qsharedpointer.cpp index f18dee80b..cdb7d1d08 100644 --- a/src/corelib/tools/qsharedpointer.cpp +++ b/src/corelib/tools/qsharedpointer.cpp @@ -867,6 +867,8 @@ #if !defined(QT_NO_QOBJECT) #include "../kernel/qobject_p.h" +QT_BEGIN_NAMESPACE + /*! \internal This function is called for a just-created QObject \a obj, to enable @@ -910,6 +912,9 @@ QtSharedPointer::ExternalRefCountData *QtSharedPointer::ExternalRefCountData::ge } return d->sharedRefcount; } + +QT_END_NAMESPACE + #endif @@ -932,6 +937,8 @@ QtSharedPointer::ExternalRefCountData *QtSharedPointer::ExternalRefCountData::ge # include # include +QT_BEGIN_NAMESPACE + static inline QByteArray saveBacktrace() __attribute__((always_inline)); static inline QByteArray saveBacktrace() { @@ -992,6 +999,9 @@ static void printBacktrace(QByteArray stacktrace) waitpid(child, 0, 0); } } + +QT_END_NAMESPACE + # endif // BACKTRACE_SUPPORTED namespace { diff --git a/src/gui/graphicsview/qgraphicstransform_p.h b/src/gui/graphicsview/qgraphicstransform_p.h index 2d36edae2..467021fef 100644 --- a/src/gui/graphicsview/qgraphicstransform_p.h +++ b/src/gui/graphicsview/qgraphicstransform_p.h @@ -55,6 +55,8 @@ #include "private/qobject_p.h" +QT_BEGIN_NAMESPACE + class QGraphicsItem; class QGraphicsTransformPrivate : public QObjectPrivate { @@ -70,4 +72,6 @@ public: static void updateItem(QGraphicsItem *item); }; +QT_END_NAMESPACE + #endif // QGRAPHICSTRANSFORM_P_H diff --git a/src/gui/image/qimagepixmapcleanuphooks.cpp b/src/gui/image/qimagepixmapcleanuphooks.cpp index 7d1c5fbe2..789700a0c 100644 --- a/src/gui/image/qimagepixmapcleanuphooks.cpp +++ b/src/gui/image/qimagepixmapcleanuphooks.cpp @@ -43,6 +43,8 @@ #include "qpixmapdata_p.h" +QT_BEGIN_NAMESPACE + // Legacy, single instance hooks: ### Qt 5: remove typedef void (*_qt_pixmap_cleanup_hook)(int); typedef void (*_qt_pixmap_cleanup_hook_64)(qint64); @@ -108,3 +110,4 @@ void QImagePixmapCleanupHooks::executeImageHooks(qint64 key) qt_image_cleanup_hook_64(key); } +QT_END_NAMESPACE diff --git a/src/network/access/qnetworkcookie.h b/src/network/access/qnetworkcookie.h index ef309a8d6..4bc3f3fac 100644 --- a/src/network/access/qnetworkcookie.h +++ b/src/network/access/qnetworkcookie.h @@ -106,9 +106,6 @@ private: }; Q_DECLARE_TYPEINFO(QNetworkCookie, Q_MOVABLE_TYPE); -// ### Qt5 remove this include -#include "qnetworkcookiejar.h" - #ifndef QT_NO_DEBUG_STREAM class QDebug; Q_NETWORK_EXPORT QDebug operator<<(QDebug, const QNetworkCookie &); @@ -116,6 +113,9 @@ Q_NETWORK_EXPORT QDebug operator<<(QDebug, const QNetworkCookie &); QT_END_NAMESPACE +// ### Qt5 remove this include +#include "qnetworkcookiejar.h" + Q_DECLARE_METATYPE(QNetworkCookie) Q_DECLARE_METATYPE(QList) -- cgit v1.2.3 From cbf60a676402eebae558568a2da4574a20f7a27e Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 10 Aug 2009 15:10:22 +0200 Subject: Compile fix for QStringBuilder auto test --- tests/auto/qstringbuilder/scenario1.pro | 1 + tests/auto/qstringbuilder/scenario2.pro | 1 + tests/auto/qstringbuilder/scenario3.pro | 1 + tests/auto/qstringbuilder/scenario4.pro | 1 + tests/auto/qstringbuilder/tst_qstringbuilder.cpp | 11 +---- tests/auto/qstringbuilder/tst_qstringbuilder.h | 55 ++++++++++++++++++++++++ 6 files changed, 60 insertions(+), 10 deletions(-) create mode 100644 tests/auto/qstringbuilder/tst_qstringbuilder.h diff --git a/tests/auto/qstringbuilder/scenario1.pro b/tests/auto/qstringbuilder/scenario1.pro index 4ce715610..d72451c2e 100644 --- a/tests/auto/qstringbuilder/scenario1.pro +++ b/tests/auto/qstringbuilder/scenario1.pro @@ -3,6 +3,7 @@ load(qttest_p4) QT = core SOURCES += scenario1.cpp +HEADERS += tst_qstringbuilder.h DEFINES += SCENARIO=1 diff --git a/tests/auto/qstringbuilder/scenario2.pro b/tests/auto/qstringbuilder/scenario2.pro index 64c46e2a5..78e0c68de 100644 --- a/tests/auto/qstringbuilder/scenario2.pro +++ b/tests/auto/qstringbuilder/scenario2.pro @@ -3,5 +3,6 @@ load(qttest_p4) QT = core SOURCES += scenario2.cpp +HEADERS += tst_qstringbuilder.h DEFINES += SCENARIO=2 diff --git a/tests/auto/qstringbuilder/scenario3.pro b/tests/auto/qstringbuilder/scenario3.pro index beedffd87..7b9e5af18 100644 --- a/tests/auto/qstringbuilder/scenario3.pro +++ b/tests/auto/qstringbuilder/scenario3.pro @@ -3,5 +3,6 @@ load(qttest_p4) QT = core SOURCES += scenario3.cpp +HEADERS += tst_qstringbuilder.h DEFINES += SCENARIO=3 diff --git a/tests/auto/qstringbuilder/scenario4.pro b/tests/auto/qstringbuilder/scenario4.pro index 1c45a7034..1b62b25e3 100644 --- a/tests/auto/qstringbuilder/scenario4.pro +++ b/tests/auto/qstringbuilder/scenario4.pro @@ -3,5 +3,6 @@ load(qttest_p4) QT = core SOURCES += scenario4.cpp +HEADERS += tst_qstringbuilder.h DEFINES += SCENARIO=4 diff --git a/tests/auto/qstringbuilder/tst_qstringbuilder.cpp b/tests/auto/qstringbuilder/tst_qstringbuilder.cpp index 72889bc13..86f6ada42 100644 --- a/tests/auto/qstringbuilder/tst_qstringbuilder.cpp +++ b/tests/auto/qstringbuilder/tst_qstringbuilder.cpp @@ -86,20 +86,13 @@ #endif #include +#include "tst_qstringbuilder.h" //TESTED_CLASS=QStringBuilder //TESTED_FILES=qstringbuilder.cpp #define LITERAL "some literal" -class tst_QStringBuilder : public QObject -{ - Q_OBJECT - -private slots: - void scenario(); -}; - void tst_QStringBuilder::scenario() { QLatin1Literal l1literal(LITERAL); @@ -138,5 +131,3 @@ void tst_QStringBuilder::scenario() } QTEST_APPLESS_MAIN(tst_QStringBuilder) - -#include "tst_qstringbuilder.moc" diff --git a/tests/auto/qstringbuilder/tst_qstringbuilder.h b/tests/auto/qstringbuilder/tst_qstringbuilder.h new file mode 100644 index 000000000..92c66d8c3 --- /dev/null +++ b/tests/auto/qstringbuilder/tst_qstringbuilder.h @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TST_QSTRINGBUILDER_H +#define TST_QSTRINGBUILDER_H + +#include + +class tst_QStringBuilder : public QObject +{ + Q_OBJECT + +private slots: + void scenario(); +}; + +#endif -- cgit v1.2.3 From 56f58a397ace5985571995ddfce98a99c490ebf8 Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Mon, 10 Aug 2009 15:45:02 +0200 Subject: Removed unused member in QApplicationPrivate The appAllTouchPoints variable isn't used on Windows, remove it. --- src/gui/kernel/qapplication_p.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/gui/kernel/qapplication_p.h b/src/gui/kernel/qapplication_p.h index 995390710..f8096729c 100644 --- a/src/gui/kernel/qapplication_p.h +++ b/src/gui/kernel/qapplication_p.h @@ -527,7 +527,6 @@ public: static PtrCloseTouchInputHandle CloseTouchInputHandle; QHash touchInputIDToTouchPointID; - QList appAllTouchPoints; bool translateTouchEvent(const MSG &msg); PtrGetGestureInfo GetGestureInfo; -- cgit v1.2.3 From 24aa36349b9fc0be9d9bf80b0db607588e0a54f6 Mon Sep 17 00:00:00 2001 From: Volker Hilsheimer Date: Mon, 10 Aug 2009 15:50:43 +0200 Subject: Doc: Fix qdoc warnings --- src/gui/kernel/qgesture.cpp | 2 +- src/testlib/qabstracttestlogger.cpp | 4 +++- src/testlib/qbenchmark.cpp | 8 +++++++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/gui/kernel/qgesture.cpp b/src/gui/kernel/qgesture.cpp index 38e8851dc..672fc1c99 100644 --- a/src/gui/kernel/qgesture.cpp +++ b/src/gui/kernel/qgesture.cpp @@ -204,7 +204,7 @@ Qt::GestureState QGesture::state() const \a state, and it should be called after all the internal properties have been initialized. - \sa started, triggered, finished, cancelled + \sa started(), triggered(), finished(), cancelled() */ void QGesture::updateState(Qt::GestureState state) { diff --git a/src/testlib/qabstracttestlogger.cpp b/src/testlib/qabstracttestlogger.cpp index 2fa535ed1..6b4b375ec 100644 --- a/src/testlib/qabstracttestlogger.cpp +++ b/src/testlib/qabstracttestlogger.cpp @@ -114,7 +114,9 @@ namespace QTest extern void filter_unprintable(char *str); -/*! \internal +/*! + \fn int QTest::qt_asprintf(QTestCharBuffer *buf, const char *format, ...); + \internal */ int qt_asprintf(QTestCharBuffer *str, const char *format, ...) { diff --git a/src/testlib/qbenchmark.cpp b/src/testlib/qbenchmark.cpp index bad3379db..eaec02fda 100644 --- a/src/testlib/qbenchmark.cpp +++ b/src/testlib/qbenchmark.cpp @@ -179,11 +179,17 @@ void QBenchmarkTestMethodData::setResult(qint64 value) QBenchmarkResult(QBenchmarkGlobalData::current->context, value, iterationCount); } -/*! \internal +/*! + \class QTest::QBenchmarkIterationController + \internal + The QBenchmarkIterationController class is used by the QBENCHMARK macro to drive the benchmarking loop. It is repsonsible for starting and stopping the timing measurements as well as calling the result reporting functions. */ + +/*! \internal +*/ QTest::QBenchmarkIterationController::QBenchmarkIterationController(RunMode runMode) { QTest::beginBenchmarkMeasurement(); -- cgit v1.2.3 From 0c98e05dfeccdca99bc180ccccd04b38305ad025 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 10 Aug 2009 16:07:33 +0200 Subject: Compile fix on Linux. Reviewed-by: brad The declaration of getQApplicationPrivateInternal was only available as 'friend' on Q_WS_WIN. --- src/gui/kernel/qapplication.h | 4 ---- src/gui/kernel/qapplication_win.cpp | 11 +++-------- src/gui/kernel/qstandardgestures.cpp | 8 ++++---- 3 files changed, 7 insertions(+), 16 deletions(-) diff --git a/src/gui/kernel/qapplication.h b/src/gui/kernel/qapplication.h index 19ae085a0..58e0cc367 100644 --- a/src/gui/kernel/qapplication.h +++ b/src/gui/kernel/qapplication.h @@ -375,10 +375,6 @@ private: friend class QDirectPainterPrivate; #endif -#if defined(Q_WS_WIN) - friend QApplicationPrivate* getQApplicationPrivateInternal(); -#endif - #if defined(Q_WS_MAC) || defined(Q_WS_X11) Q_PRIVATE_SLOT(d_func(), void _q_alertTimeOut()) #endif diff --git a/src/gui/kernel/qapplication_win.cpp b/src/gui/kernel/qapplication_win.cpp index cb6740975..d5448db63 100644 --- a/src/gui/kernel/qapplication_win.cpp +++ b/src/gui/kernel/qapplication_win.cpp @@ -428,11 +428,6 @@ extern QCursor *qt_grab_cursor(); #define __export #endif -QApplicationPrivate* getQApplicationPrivateInternal() -{ - return qApp->d_func(); -} - extern "C" LRESULT CALLBACK QtWndProc(HWND, UINT, WPARAM, LPARAM); class QETWidget : public QWidget // event translator widget @@ -1461,7 +1456,7 @@ LRESULT CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam // we receive the message for each toplevel window included internal hidden ones, // but the aboutToQuit signal should be emitted only once. - QApplicationPrivate *qAppPriv = getQApplicationPrivateInternal(); + QApplicationPrivate *qAppPriv = QApplicationPrivate::instance(); if (endsession && !qAppPriv->aboutToQuitEmitted) { qAppPriv->aboutToQuitEmitted = true; int index = QApplication::staticMetaObject.indexOfSignal("aboutToQuit()"); @@ -1648,7 +1643,7 @@ LRESULT CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam } else { switch (message) { case WM_TOUCH: - result = getQApplicationPrivateInternal()->translateTouchEvent(msg); + result = QApplicationPrivate::instance()->translateTouchEvent(msg); break; case WM_KEYDOWN: // keyboard event case WM_SYSKEYDOWN: @@ -3719,7 +3714,7 @@ bool QETWidget::translateGestureEvent(const MSG &msg) memset(&gi, 0, sizeof(GESTUREINFO)); gi.cbSize = sizeof(GESTUREINFO); - QApplicationPrivate *qAppPriv = getQApplicationPrivateInternal(); + QApplicationPrivate *qAppPriv = QApplicationPrivate::instance(); BOOL bResult = qAppPriv->GetGestureInfo((HANDLE)msg.lParam, &gi); if (bResult) { const QPoint widgetPos = QPoint(gi.ptsLocation.x, gi.ptsLocation.y); diff --git a/src/gui/kernel/qstandardgestures.cpp b/src/gui/kernel/qstandardgestures.cpp index ac03cd247..b4c37876d 100644 --- a/src/gui/kernel/qstandardgestures.cpp +++ b/src/gui/kernel/qstandardgestures.cpp @@ -293,7 +293,7 @@ QPinchGesture::QPinchGesture(QWidget *parent) : QGesture(*new QPinchGesturePrivate, parent) { if (parent) { - QApplicationPrivate *qAppPriv = getQApplicationPrivateInternal(); + QApplicationPrivate *qAppPriv = QApplicationPrivate::instance(); qAppPriv->widgetGestures[parent].pinch = this; #ifdef Q_WS_WIN qt_widget_private(parent)->winSetupGestures(); @@ -307,7 +307,7 @@ bool QPinchGesture::event(QEvent *event) switch (event->type()) { case QEvent::ParentAboutToChange: if (QWidget *w = qobject_cast(parent())) { - getQApplicationPrivateInternal()->widgetGestures[w].pinch = 0; + QApplicationPrivate::instance()->widgetGestures[w].pinch = 0; #ifdef Q_WS_WIN qt_widget_private(w)->winSetupGestures(); #endif @@ -315,7 +315,7 @@ bool QPinchGesture::event(QEvent *event) break; case QEvent::ParentChange: if (QWidget *w = qobject_cast(parent())) { - getQApplicationPrivateInternal()->widgetGestures[w].pinch = this; + QApplicationPrivate::instance()->widgetGestures[w].pinch = this; #ifdef Q_WS_WIN qt_widget_private(w)->winSetupGestures(); #endif @@ -333,7 +333,7 @@ bool QPinchGesture::eventFilter(QObject *receiver, QEvent *event) Q_D(QPinchGesture); if (receiver->isWidgetType() && event->type() == QEvent::NativeGesture) { QNativeGestureEvent *ev = static_cast(event); - QApplicationPrivate *qAppPriv = getQApplicationPrivateInternal(); + QApplicationPrivate *qAppPriv = QApplicationPrivate::instance(); QApplicationPrivate::WidgetStandardGesturesMap::iterator it; it = qAppPriv->widgetGestures.find(static_cast(receiver)); if (it == qAppPriv->widgetGestures.end()) -- cgit v1.2.3 From eeb206d41d386d4d3dee1ff2813d132d15f670d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Trond=20Kjern=C3=A5sen?= Date: Mon, 10 Aug 2009 16:16:16 +0200 Subject: Compile and work on Linux. Reviewed-by: Kim --- tests/arthur/lance/main.cpp | 2 +- tests/arthur/lance/widgets.h | 39 +++++++++++++++++++++------------------ 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/tests/arthur/lance/main.cpp b/tests/arthur/lance/main.cpp index f95b42623..0c9f3d854 100644 --- a/tests/arthur/lance/main.cpp +++ b/tests/arthur/lance/main.cpp @@ -271,7 +271,7 @@ int main(int argc, char **argv) QString format = QString(argv[++i]).toLower(); imageFormat = QImage::Format_Invalid; - static const unsigned int formatCount = + static const int formatCount = sizeof(imageFormats) / sizeof(imageFormats[0]); for (int ff = 0; ff < formatCount; ++ff) { if (QLatin1String(imageFormats[ff].name) == format) { diff --git a/tests/arthur/lance/widgets.h b/tests/arthur/lance/widgets.h index 72476084f..61691dc11 100644 --- a/tests/arthur/lance/widgets.h +++ b/tests/arthur/lance/widgets.h @@ -56,6 +56,9 @@ #include #include #include +#include +#include + #include @@ -96,8 +99,8 @@ public: OnScreenWidget(const QString &file, QWidget *parent = 0) : T(parent), - m_view_mode(RenderView), - m_filename(file) + m_filename(file), + m_view_mode(RenderView) { QSettings settings("Trolltech", "lance"); for (int i=0; i<10; ++i) { @@ -117,36 +120,36 @@ public: } if (m_baseline.isNull()) { - setWindowTitle("Rendering: '" + file + "'. No baseline available"); + T::setWindowTitle("Rendering: '" + file + "'. No baseline available"); } else { - setWindowTitle("Rendering: '" + file + "'. Shortcuts: 1=render, 2=baseline, 3=difference"); + T::setWindowTitle("Rendering: '" + file + "'. Shortcuts: 1=render, 2=baseline, 3=difference"); StupidWorkaround *workaround = new StupidWorkaround(this, &m_view_mode); QSignalMapper *mapper = new QSignalMapper(this); - connect(mapper, SIGNAL(mapped(int)), workaround, SLOT(setViewMode(int))); - connect(mapper, SIGNAL(mapped(QString)), this, SLOT(setWindowTitle(QString))); + T::connect(mapper, SIGNAL(mapped(int)), workaround, SLOT(setViewMode(int))); + T::connect(mapper, SIGNAL(mapped(QString)), this, SLOT(setWindowTitle(QString))); QAction *renderViewAction = new QAction("Render View", this); renderViewAction->setShortcut(Qt::Key_1); - connect(renderViewAction, SIGNAL(triggered()), mapper, SLOT(map())); + T::connect(renderViewAction, SIGNAL(triggered()), mapper, SLOT(map())); mapper->setMapping(renderViewAction, RenderView); mapper->setMapping(renderViewAction, "Render View: " + file); - addAction(renderViewAction); + T::addAction(renderViewAction); QAction *baselineAction = new QAction("Baseline", this); baselineAction->setShortcut(Qt::Key_2); - connect(baselineAction, SIGNAL(triggered()), mapper, SLOT(map())); + T::connect(baselineAction, SIGNAL(triggered()), mapper, SLOT(map())); mapper->setMapping(baselineAction, BaselineView); mapper->setMapping(baselineAction, "Baseline View: " + file); - addAction(baselineAction); + T::addAction(baselineAction); QAction *differenceAction = new QAction("Differenfe View", this); differenceAction->setShortcut(Qt::Key_3); - connect(differenceAction, SIGNAL(triggered()), mapper, SLOT(map())); + T::connect(differenceAction, SIGNAL(triggered()), mapper, SLOT(map())); mapper->setMapping(differenceAction, DifferenceView); mapper->setMapping(differenceAction, "Difference View" + file); - addAction(differenceAction); + T::addAction(differenceAction); } @@ -178,7 +181,7 @@ public: } } - void OnScreenWidget::paintRenderView() + void paintRenderView() { QPainter pt; QPaintDevice *dev = this; @@ -233,7 +236,7 @@ public: } if (m_render_view.isNull()) { - m_render_view = window()->windowSurface()->grabWidget(this); + m_render_view = T::window()->windowSurface()->grabWidget(this); m_render_view.save("renderView.png"); } } @@ -242,7 +245,7 @@ public: QPainter p(this); if (m_baseline.isNull()) { - p.drawText(rect(), Qt::AlignCenter, + p.drawText(T::rect(), Qt::AlignCenter, "No baseline found\n" "file '" + m_baseline_name + "' does not exist..."); return; @@ -258,7 +261,7 @@ public: QPixmap generateDifference() { - QImage img(size(), QImage::Format_RGB32); + QImage img(T::size(), QImage::Format_RGB32); img.fill(0); QPainter p(&img); @@ -275,13 +278,13 @@ public: void paintDifferenceView() { QPainter p(this); if (m_baseline.isNull()) { - p.drawText(rect(), Qt::AlignCenter, + p.drawText(T::rect(), Qt::AlignCenter, "No baseline found\n" "file '" + m_baseline_name + "' does not exist..."); return; } - p.fillRect(rect(), Qt::black); + p.fillRect(T::rect(), Qt::black); p.drawPixmap(0, 0, generateDifference()); } -- cgit v1.2.3 From 9c4ed99ede2de8dae005cef9a6c519e2b561a54f Mon Sep 17 00:00:00 2001 From: Thierry Bastian Date: Mon, 10 Aug 2009 16:15:03 +0200 Subject: Fixed a possible problem when unplugging a QToolBar The 'break' statement was misplaced... This was found thanks to coverity --- src/gui/widgets/qtoolbararealayout.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/widgets/qtoolbararealayout.cpp b/src/gui/widgets/qtoolbararealayout.cpp index b4a0ef022..afd526af3 100644 --- a/src/gui/widgets/qtoolbararealayout.cpp +++ b/src/gui/widgets/qtoolbararealayout.cpp @@ -1156,8 +1156,8 @@ QLayoutItem *QToolBarAreaLayout::unplug(const QList &path, QToolBarAreaLayo if (!next.skip()) { newExtraSpace = next.pos - previous.pos - pick(line.o, previous.sizeHint()); previous.resize(line.o, next.pos - previous.pos); + break; } - break; } break; } -- cgit v1.2.3 From f4dba5394f6772a61af56fd25052e29a44de89ed Mon Sep 17 00:00:00 2001 From: David Boddie Date: Mon, 10 Aug 2009 16:27:51 +0200 Subject: Doc: Clarified the behavior of QDir::exists(). Task-number: 259091 Reviewed-by: Trust Me --- src/corelib/io/qdir.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/corelib/io/qdir.cpp b/src/corelib/io/qdir.cpp index 072eb2736..cb0fdeb17 100644 --- a/src/corelib/io/qdir.cpp +++ b/src/corelib/io/qdir.cpp @@ -1541,9 +1541,11 @@ bool QDir::isReadable() const /*! \overload - Returns true if the \e directory exists; otherwise returns false. - (If a file with the same name is found this function will return - false). + Returns true if the directory exists; otherwise returns false. + (If a file with the same name is found this function will return false). + + The overload of this function that accepts an argument is used to test + for the presence of files and directories within a directory. \sa QFileInfo::exists(), QFile::exists() */ @@ -1773,8 +1775,11 @@ bool QDir::rename(const QString &oldName, const QString &newName) /*! Returns true if the file called \a name exists; otherwise returns - false. Unless \a name contains an absolute file path, the file - name is assumed to be relative to the current directory. + false. + + Unless \a name contains an absolute file path, the file name is assumed + to be relative to the directory itself, so this function is typically used + to check for the presence of files within a directory. \sa QFileInfo::exists(), QFile::exists() */ -- cgit v1.2.3 From a4b6a5ccf5146dc5fbe2b8363b4c6fb73a8d975e Mon Sep 17 00:00:00 2001 From: Volker Hilsheimer Date: Mon, 10 Aug 2009 16:33:25 +0200 Subject: Doc: add \since 4.6 for new functions --- src/corelib/kernel/qmetaobject.cpp | 2 ++ src/testlib/qtestcase.cpp | 1 + 2 files changed, 3 insertions(+) diff --git a/src/corelib/kernel/qmetaobject.cpp b/src/corelib/kernel/qmetaobject.cpp index d43c5dd8d..f153c7ecc 100644 --- a/src/corelib/kernel/qmetaobject.cpp +++ b/src/corelib/kernel/qmetaobject.cpp @@ -2488,6 +2488,7 @@ bool QMetaProperty::isUser(const QObject *object) const } /*! + \since 4.6 Returns true if the property is constant; otherwise returns false. A property is constant if the \c{Q_PROPERTY()}'s \c CONSTANT attribute @@ -2502,6 +2503,7 @@ bool QMetaProperty::isConstant() const } /*! + \since 4.6 Returns true if the property is final; otherwise returns false. A property is final if the \c{Q_PROPERTY()}'s \c FINAL attribute diff --git a/src/testlib/qtestcase.cpp b/src/testlib/qtestcase.cpp index 21a686e4a..51e767c40 100644 --- a/src/testlib/qtestcase.cpp +++ b/src/testlib/qtestcase.cpp @@ -353,6 +353,7 @@ QT_BEGIN_NAMESPACE /*! \macro QBENCHMARK_ONCE + \since 4.6 \relates QTest -- cgit v1.2.3 From 724d7721331b444a6dd817cd4e12909a2cae709a Mon Sep 17 00:00:00 2001 From: David Boddie Date: Mon, 10 Aug 2009 16:34:12 +0200 Subject: Doc: Fixed spelling mistake and some acronyms. Task-number: 259268 Reviewed-by: Trust Me --- src/network/access/qhttp.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/network/access/qhttp.cpp b/src/network/access/qhttp.cpp index faa239870..4c0684818 100644 --- a/src/network/access/qhttp.cpp +++ b/src/network/access/qhttp.cpp @@ -1597,11 +1597,11 @@ QHttp::~QHttp() This enum is used to specify the mode of connection to use: - \value ConnectionModeHttp The connection is a regular Http connection to the server - \value ConnectionModeHttps The Https protocol is used and the connection is encrypted using SSL. + \value ConnectionModeHttp The connection is a regular HTTP connection to the server + \value ConnectionModeHttps The HTTPS protocol is used and the connection is encrypted using SSL. - When using the Https mode, care should be taken to connect to the sslErrors signal, and - handle possible Ssl errors. + When using the HTTPS mode, care should be taken to connect to the sslErrors signal, and + handle possible SSL errors. \sa QSslSocket */ @@ -2039,7 +2039,7 @@ int QHttp::setHost(const QString &hostName, quint16 port) port \a port using the connection mode \a mode. If port is 0, it will use the default port for the \a mode used - (80 for Http and 443 fopr Https). + (80 for HTTP and 443 for HTTPS). The function does not block; instead, it returns immediately. The request is scheduled, and its execution is performed asynchronously. The -- cgit v1.2.3 From 41537bb8ea6f6174690d244a1cc07678f4bf4229 Mon Sep 17 00:00:00 2001 From: Kent Hansen Date: Mon, 10 Aug 2009 16:47:41 +0200 Subject: fix issues reported by Coverity --- src/corelib/statemachine/qhistorystate.cpp | 4 +--- src/corelib/statemachine/qstate_p.h | 2 +- src/corelib/statemachine/qstatemachine.cpp | 1 + 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/corelib/statemachine/qhistorystate.cpp b/src/corelib/statemachine/qhistorystate.cpp index e5ca83769..d21eee985 100644 --- a/src/corelib/statemachine/qhistorystate.cpp +++ b/src/corelib/statemachine/qhistorystate.cpp @@ -120,7 +120,7 @@ QT_BEGIN_NAMESPACE */ QHistoryStatePrivate::QHistoryStatePrivate() - : defaultState(0) + : defaultState(0), historyType(QHistoryState::ShallowHistory) { } @@ -135,8 +135,6 @@ QHistoryStatePrivate *QHistoryStatePrivate::get(QHistoryState *q) QHistoryState::QHistoryState(QState *parent) : QAbstractState(*new QHistoryStatePrivate, parent) { - Q_D(QHistoryState); - d->historyType = ShallowHistory; } /*! Constructs a new history state of the given \a type, with the given \a diff --git a/src/corelib/statemachine/qstate_p.h b/src/corelib/statemachine/qstate_p.h index 20eb5eadb..c43a26c95 100644 --- a/src/corelib/statemachine/qstate_p.h +++ b/src/corelib/statemachine/qstate_p.h @@ -64,7 +64,7 @@ QT_BEGIN_NAMESPACE struct QPropertyAssignment { QPropertyAssignment() - : object(0) {} + : object(0), explicitlySet(true) {} QPropertyAssignment(QObject *o, const QByteArray &n, const QVariant &v, bool es = true) : object(o), propertyName(n), value(v), explicitlySet(es) diff --git a/src/corelib/statemachine/qstatemachine.cpp b/src/corelib/statemachine/qstatemachine.cpp index 9cb1d4dba..59261766d 100644 --- a/src/corelib/statemachine/qstatemachine.cpp +++ b/src/corelib/statemachine/qstatemachine.cpp @@ -209,6 +209,7 @@ QStateMachinePrivate::QStateMachinePrivate() processing = false; processingScheduled = false; stop = false; + stopProcessingReason = EventQueueEmpty; error = QStateMachine::NoError; globalRestorePolicy = QStateMachine::DoNotRestoreProperties; signalEventGenerator = 0; -- cgit v1.2.3 From 66f26230a463fef12e8c95ea7819e476e038d4f8 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 10 Aug 2009 16:53:28 +0200 Subject: Linguist: Fixed spehling error. --- tools/linguist/linguist/mainwindow.cpp | 10 +++++----- tools/linguist/linguist/mainwindow.ui | 6 +++--- tools/linguist/linguist/messageeditor.cpp | 2 +- tools/linguist/linguist/messageeditor.h | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/tools/linguist/linguist/mainwindow.cpp b/tools/linguist/linguist/mainwindow.cpp index bb79b1916..22ff46a6e 100644 --- a/tools/linguist/linguist/mainwindow.cpp +++ b/tools/linguist/linguist/mainwindow.cpp @@ -482,9 +482,9 @@ MainWindow::MainWindow() readConfig(); m_statistics = 0; - connect(m_ui.actionLenghtVariants, SIGNAL(toggled(bool)), - m_messageEditor, SLOT(setLenghtVariants(bool))); - m_messageEditor->setLenghtVariants(m_ui.actionLenghtVariants->isChecked()); + connect(m_ui.actionLengthVariants, SIGNAL(toggled(bool)), + m_messageEditor, SLOT(setLengthVariants(bool))); + m_messageEditor->setLengthVariants(m_ui.actionLengthVariants->isChecked()); m_focusWatcher = new FocusWatcher(m_messageEditor, this); m_contextView->installEventFilter(m_focusWatcher); @@ -2521,7 +2521,7 @@ void MainWindow::readConfig() config.value(settingPath("Validators/PhraseMatch"), true).toBool()); m_ui.actionPlaceMarkerMatches->setChecked( config.value(settingPath("Validators/PlaceMarkers"), true).toBool()); - m_ui.actionLenghtVariants->setChecked( + m_ui.actionLengthVariants->setChecked( config.value(settingPath("Options/LengthVariants"), false).toBool()); recentFiles().readConfig(); @@ -2548,7 +2548,7 @@ void MainWindow::writeConfig() config.setValue(settingPath("Validators/PlaceMarkers"), m_ui.actionPlaceMarkerMatches->isChecked()); config.setValue(settingPath("Options/LengthVariants"), - m_ui.actionLenghtVariants->isChecked()); + m_ui.actionLengthVariants->isChecked()); config.setValue(settingPath("MainWindowState"), saveState()); recentFiles().writeConfig(); diff --git a/tools/linguist/linguist/mainwindow.ui b/tools/linguist/linguist/mainwindow.ui index 613241bb0..9dfb1fff1 100644 --- a/tools/linguist/linguist/mainwindow.ui +++ b/tools/linguist/linguist/mainwindow.ui @@ -116,7 +116,7 @@ - + @@ -878,12 +878,12 @@ Ctrl+W - + true - Lenght Variants + Length Variants diff --git a/tools/linguist/linguist/messageeditor.cpp b/tools/linguist/linguist/messageeditor.cpp index 9e598a804..e9113897e 100644 --- a/tools/linguist/linguist/messageeditor.cpp +++ b/tools/linguist/linguist/messageeditor.cpp @@ -710,7 +710,7 @@ void MessageEditor::setEditingEnabled(int model, bool enabled) updateCanPaste(); } -void MessageEditor::setLenghtVariants(bool on) +void MessageEditor::setLengthVariants(bool on) { m_lengthVariants = on; foreach (const MessageEditorData &ed, m_editors) diff --git a/tools/linguist/linguist/messageeditor.h b/tools/linguist/linguist/messageeditor.h index 410603694..b195a04db 100644 --- a/tools/linguist/linguist/messageeditor.h +++ b/tools/linguist/linguist/messageeditor.h @@ -110,7 +110,7 @@ public slots: void beginFromSource(); void setEditorFocus(); void setTranslation(int latestModel, const QString &translation); - void setLenghtVariants(bool on); + void setLengthVariants(bool on); private slots: void editorCreated(QTextEdit *); -- cgit v1.2.3 From cbd8a54f8c55e1982430fc929e9d74f977699428 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 10 Aug 2009 16:54:24 +0200 Subject: Translations: Purged and updated German of Assistant/Linguist/Help. --- translations/assistant_de.ts | 304 +++-------- translations/linguist_de.ts | 1180 +++++++----------------------------------- translations/qt_help_de.ts | 40 +- 3 files changed, 310 insertions(+), 1214 deletions(-) diff --git a/translations/assistant_de.ts b/translations/assistant_de.ts index f7024654f..ce3206243 100644 --- a/translations/assistant_de.ts +++ b/translations/assistant_de.ts @@ -52,11 +52,11 @@ Neuer Ordner - + - - - + + + Bookmarks Lesezeichen @@ -66,7 +66,7 @@ + - + Delete Folder Ordner löschen @@ -79,12 +79,12 @@ BookmarkManager - + Bookmarks Lesezeichen - + Remove Entfernen @@ -94,7 +94,7 @@ Wenn Sie diesen Ordner löschen, wird auch<br>dessen kompletter Inhalt gelöscht. Möchten Sie wirklich fortfahren? - + New Folder Neuer Ordner @@ -103,25 +103,17 @@ BookmarkWidget - + Filter: Filter: - Bookmarks - Lesezeichen - - - + Remove Entfernen - You are going to delete a Folder, this will also<br>remove it's content. Are you sure to continue? - Wenn Sie dieses Verzeichnis löschen, wird auch<br>dessen kompletter Inhalt gelöscht! Fortfahren? - - - + Delete Folder Ordner löschen @@ -151,11 +143,7 @@ Lesezeichen umbenennen - Search for: - Suchen: - - - + Add Hinzufügen @@ -163,7 +151,7 @@ CentralWidget - + Add new page Neue Seite hinzufügen @@ -173,7 +161,7 @@ Aktuelle Seite schließen - + Print Document Drucken @@ -184,7 +172,7 @@ unbekannt - + Add New Page Neue Seite hinzufügen @@ -204,7 +192,7 @@ Lesezeichen für diese Seite hinzufügen ... - + Search Suchen @@ -212,7 +200,7 @@ ContentWindow - + Open Link Link öffnen @@ -224,10 +212,6 @@ FilterNameDialogClass - - FilterNameDialog - FilterNameDialog - Add Filter Name @@ -242,7 +226,7 @@ FindWidget - + Previous Zurück @@ -302,12 +286,6 @@ Help Hilfe - - Unable to launch web browser. - - Der Webbrowser konnte nicht gestarted werden. - - OK @@ -362,13 +340,13 @@ InstallDialog - + Install Documentation Dokumentation installieren - + Downloading documentation info... Dokumentationsinformation herunterladen ... @@ -462,20 +440,20 @@ MainWindow - - + + Index Index - - + + Contents Inhalt - - + + Bookmarks Lesezeichen @@ -485,24 +463,20 @@ Suchen - - - + + + Qt Assistant Qt Assistant - + Unfiltered Ohne Filter - File - Datei - - - + Page Set&up... S&eite einrichten ... @@ -517,111 +491,62 @@ &Drucken ... - CTRL+P - CTRL+P - - - + New &Tab Neuer &Tab - - CTRL+T - CTRL+T - &Close Tab Tab &schließen - - CTRL+W - CTRL+W - &Quit &Beenden - - CTRL+Q - CTRL+Q - - - Edit - Bearbeiten - - - + &Copy selected Text Ausgewählten Text &kopieren - Ctrl+C - Ctrl+C - - - + &Find in Text... &Textsuche ... - Ctrl+F - Ctrl+F - - - + Find &Next &Weitersuchen - - F3 - F3 - Find &Previous &Vorheriges suchen - - Shift+F3 - Shift+F3 - Preferences... Einstellungen ... - - View - Ansicht - Zoom &in &Vergrößern - Ctrl++ - Ctrl++ - - - + Zoom &out Ver&kleinern - Ctrl+- - Ctrl+- - - - + Normal &Size Standard&größe - + Ctrl+0 Ctrl+0 @@ -635,31 +560,18 @@ ALT+I ALT+I - - ALT+B - ALT+B - ALT+S ALT+S - - Go - Gehe - &Home &Startseite - - Ctrl+Home - Ctrl+Home - - - + &Back &Rückwärts @@ -669,12 +581,12 @@ &Vorwärts - + Sync with Table of Contents Seite mit Inhalt-Tab abgleichen - + Next Page Nächste Seite @@ -699,15 +611,7 @@ Lesezeichen hinzufügen ... - CTRL+B - CTRL+B - - - Help - Hilfe - - - + About... Über ... @@ -747,38 +651,22 @@ Der zugehörige Inhaltseintrag konnte nicht gefunden werden. - Open Source Edition - Open Source Edition - - - This version of Qt Assistant is part of the Qt Open Source Edition, for use in the development of Open Source applications. Qt is a comprehensive C++ framework for cross-platform application development. - This version of Qt Assistant is part of the Qt Open Source Edition, for use in the development of Open Source applications. Qt is a comprehensive C++ framework for cross-platform application development. - - - You need a commercial Qt license for development of proprietary (closed source) applications. Please see <a href="http://qtsoftware.com/company/model.html">qtsoftware.com/company/model.html</a> for an overview of Qt licensing. - You need a commercial Qt license for development of proprietary (closed source) applications. Please see <a href="http://qtsoftware.com/company/model.html">qtsoftware.com/company/model.html</a> for an overview of Qt licensing. - - - This program is licensed to you under the terms of the Qt Commercial License Agreement. For details, see the file LICENSE that came with this software distribution. - This program is licensed to you under the terms of the Qt Commercial License Agreement. For details, see the file LICENSE that came with this software distribution. - - - + About %1 Über %1 - + Updating search index Suchindex wird aufgebaut - + Looking for Qt Documentation... Suche nach Qt-Dokumentation ... - + &Window &Fenster @@ -798,54 +686,47 @@ Zoom - Add - Hinzufügen - - - Remove - Entfernen - - - + &File &Datei - + &Edit &Bearbeiten - + &View &Ansicht - + &Go &Gehe zu + + + ALT+Home + + &Bookmarks &Lesezeichen - + &Help &Hilfe - You need a commercial Qt license for development of proprietary (closed source) applications. Please see <a href="http://qtsoftware.com/company/about/businessmodel">http://qtsoftware.com/company/about/businessmodel</a> for an overview of Qt licensing. - Sie benötigen eine kommerzielle Qt Lizenz für die Entwicklung von proprietären (geschlossenen) Anwendungen. Besuchen Sie <a href="http://qtsoftware.com/company/about/businessmodel">http://qtsoftware.com/company/about/businessmodel</a> um sich einen Überblick über die Qt Lizenzvergabe zu verschaffen. - - - + ALT+O ALT+O - + CTRL+D CTRL+D @@ -853,15 +734,7 @@ PreferencesDialog - From Local File System... - Von Dateisystem... - - - Download from Help Server... - Von Hilfe-Server herunterladen... - - - + Add Documentation Dokumentation hinzufügen @@ -902,7 +775,7 @@ OK - + Use custom settings Benutzerdefinierte Einstellungen verwenden @@ -979,22 +852,6 @@ Add... Hinzufügen ... - - Network - Netzwerk - - - Use Http Proxy - Http Proxy - - - Http Proxy: - Http Proxy: - - - Port: - Port: - Options @@ -1015,13 +872,34 @@ Homepage Startseite + + + On help start: + Zu Beginn: + + + + Show my home page + Startseite zeigen + + + + Show a blank page + Leere Seite zeigen + + + + Show my tabs from last session + Reiter aus letzter Sitzung zeigen + + + + Blank Page + Leere Seite + QObject - - New Folder - Neuer Ordner - The specified collection file does not exist! @@ -1085,7 +963,7 @@ Qt Assistant - + Could not register documentation file %1 @@ -1128,12 +1006,6 @@ Grund: The specified collection file could not be read! Die angegebene Katalogdatei (collection file) kann nicht gelesen werden. - - - - Bookmark - Lesezeichen - RemoteControl @@ -1170,10 +1042,6 @@ Grund: Select All Alles markieren - - Open Link - Link öffnen - TopicChooser diff --git a/translations/linguist_de.ts b/translations/linguist_de.ts index 48f1f2e4d..8924b6e3b 100644 --- a/translations/linguist_de.ts +++ b/translations/linguist_de.ts @@ -1,25 +1,10 @@ - - - - - (New Entry) - (Neuer Eintrag) - - - - @default - - (New Phrase) - (Neue Phrase) - - AboutDialog - + Qt Linguist Qt Linguist @@ -74,11 +59,6 @@ Retranslate entries with existing translation Einträge mit bereits existierender Übersetzung neu übersetzen - - - Note that the modified entries will be reset to unfinished if 'Set translated entries to finished' above is unchecked. - Beachten Sie, dass die geänderten Einträge in den Status 'unerledigt' zurückgesetzt werden, wenn 'Übersetzung als erledigt markieren' deaktiviert ist. - Translate also finished entries @@ -99,11 +79,6 @@ Move down Nach unten - - - The batch translator will search through the selected phrase books in the order given above. - Der automatische Übersetzer wird in der angegebenen Reihenfolge durch die ausgewählten Wörterbücher gehen. - &Run @@ -114,6 +89,16 @@ Cancel Abbrechen + + + Note that the modified entries will be reset to unfinished if 'Set translated entries to finished' above is unchecked + Geänderte Einträge werden als unerledigt gekennzeichnet, wenn die obige Einstellung 'Übersetzung als erledigt markieren' nicht aktiviert ist + + + + The batch translator will search through the selected phrase books in the order given above + Der automatische Übersetzer wird in der angegebenen Reihenfolge durch die ausgewählten Wörterbücher gehen + DataModel @@ -155,61 +140,6 @@ Es wird mit einer einfachen Universalform gearbeitet. Universalform - - EditorPage - - Source text - Ursprungstext - - - This area shows the source text. - Dieser Bereich zeigt den Ursprungstext. - - - This area shows a comment that may guide you, and the context in which the text occurs. - Dieser Bereich zeigt eventuelle Kommentare und den Kontext, in dem der Text auftritt. - - - Existing %1 translation - Existierende Übersetzung %1 - - - Translation - Übersetzung - - - %1 translation - Übersetzung %1 - - - %1 translation (%2) - Übersetzung %1 (%2) - - - This is where you can enter or modify the translation of some source text. - Hier können Sie die Übersetzung des Ursprungstextes eingeben bzw. ändern. - - - German - Deutsch - - - Japanese - Japanisch - - - French - Französisch - - - Polish - Polnisch - - - Chinese - Chinesisch - - ErrorsView @@ -250,19 +180,11 @@ Es wird mit einer einfachen Universalform gearbeitet. FindDialog - - Qt Linguist - Qt Linguist - This window allows you to search for some text in the translation source file. Dieses Fenster erlaubt die Suche in der Übersetzungsdatei. - - Find what: - Suchen nach: - Type in the text to search for. @@ -278,37 +200,21 @@ Es wird mit einer einfachen Universalform gearbeitet. Source texts are searched when checked. Wenn aktiviert, wird in den Ursprungstexten gesucht. - - Source texts - Ursprungsstexte - Translations are searched when checked. Wenn ausgewählt, wird in den Übersetzungen gesucht. - - Translations - Übersetzungen - Texts such as 'TeX' and 'tex' are considered as different when checked. Wenn aktiviert, werden Texte wie 'TeX' und 'tex' als unterschiedlich betrachtet. - - Match case - Groß-/Kleinschreibung beachten - Comments and contexts are searched when checked. Wenn ausgewählt, werden Kommentare und Kontextnamen durchsucht. - - Comments - Kommentare - Find @@ -364,10 +270,6 @@ Es wird mit einer einfachen Universalform gearbeitet. Cancel Abbrechen - - Ignore accelerators - Kurztasten ignorieren - @@ -376,16 +278,56 @@ Es wird mit einer einfachen Universalform gearbeitet. - FormHolder + FormMultiWidget + + + Alt+Delete + translate, but don't change + + + + + Shift+Alt+Insert + translate, but don't change + + + + + Alt+Insert + translate, but don't change + + + + + Confirmation - Qt Linguist + Bestätigung - Qt Linguist + - Preview Form - Vorschau + + Delete non-empty length variant? + Soll die ausgefüllte Längenvariante gelöscht werden? LRelease - + + Dropped %n message(s) which had no ID. + + Es wurde ein Eintrag ohne Bezeichner gelöscht. + Es wurde %n Einträge ohne Bezeichner gelöscht. + + + + + Excess context/disambiguation dropped from %n message(s). + + Es wurde überflüssiger Kontext beziehungsweise überflüssige Infomation zur Unterscheidung bei einem Eintrag entfernt. + Es wurde überflüssiger Kontext beziehungsweise überflüssige Infomation zur Unterscheidung bei %n Einträgen entfernt. + + + + Generated %n translation(s) (%1 finished and %2 unfinished) @@ -407,89 +349,6 @@ Es wird mit einer einfachen Universalform gearbeitet. - - LanguagesDialog - - Open Translation File - Öffne Übersetzungsdatei - - - Qt translation sources (%1);;Qt translation sources (*.ts);;XLIFF localization files (*.xlf);;All files (*) - Qt Übersetzungsdateien (%1);;Qt Übersetzungsdateien (*.ts);;XLIFF Lokalisierungsdateien (*.xlf);;Alle Dateien (*) - - - Auxiliary Languages - Unterstützende Sprachen - - - Locale - Regionalschema - - - File - Datei - - - <html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Move selected language up</p></body></html> - <html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Bewege ausgewählte Sprache herauf</p></body></html> - - - up - Hoch - - - <html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;">Move selected language down</p></body></html> - <html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;">Bewege ausgewählte Sprache herunter</p></body></html> - - - down - Herunter - - - <html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Remove selected language</p></body></html> - <html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Entferne ausgewählte Sprache</p></body></html> - - - remove - Entfernen - - - <html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Open auxiliary language files</p></body></html> - <html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Öffne unterstützende Sprachen</p></body></html> - - - ... - ... - - - OK - OK - - MainWindow @@ -537,10 +396,6 @@ p, li { white-space: pre-wrap; } &Toolbars &Werkzeugleisten - - Too&ls - &Werkzeuge - &Help @@ -556,19 +411,11 @@ p, li { white-space: pre-wrap; } &File &Datei - - Re&cently Opened Files - &Zuletzt geöffnete Dateien - &Edit &Bearbeiten - - &New - &Neu - &Open... @@ -610,51 +457,26 @@ p, li { white-space: pre-wrap; } Save changes made to this Qt translation source file Änderungen an der Qt-Übersetzungsdatei speichern - - - Previous unfinished item. - Vorheriger unerledigter Eintrag. - Move to the previous unfinished item. Zum vorherigen unerledigten Eintrag gehen. - - - Next unfinished item. - Nächster unerledigter Eintrag. - Move to the next unfinished item. Zum nächsten unerledigten Eintrag gehen. - - - Move to previous item. - Zum vorigen Eintrag gehen. - Move to the previous item. Zum vorigen Eintrag gehen. - - - Next item. - Nächster Eintrag. - Move to the next item. Zum nächsten Eintrag gehen. - - - Mark item as done and move to the next unfinished item. - Eintrag als erledigt markieren und zum nächsten unerledigten Eintrag gehen. - Mark this item as done and move to the next unfinished item. @@ -665,21 +487,11 @@ p, li { white-space: pre-wrap; } Copy from source text Ursprungstext übernehmen - - - Toggle the validity check of accelerators. - Prüfung der Tastenkürzel ein- bzw. ausschalten. - Toggle the validity check of accelerators, i.e. whether the number of ampersands in the source and translation text is the same. If the check fails, a message is shown in the warnings window. Die Prüfung der Tastenkürzel, das heißt, die Übereinstimmung der kaufmännischen Und-Zeichen in Quelle und Übersetzung ein- bzw. ausschalten. Bei Fehlschlag wird eine Warnung im Hinweis-Fenster angezeigt. - - - Toggle the validity check of ending punctuation. - Prüfung der Satzendezeichen am Ende des Textes ein- bzw. ausschalten. - Toggle the validity check of ending punctuation. If the check fails, a message is shown in the warnings window. @@ -690,11 +502,6 @@ p, li { white-space: pre-wrap; } Toggle checking that phrase suggestions are used. If the check fails, a message is shown in the warnings window. Die Prüfung der Verwendung der Wörterbuchvorschläge ein- bzw. ausschalten. Bei Fehlschlag wird eine Warnung im Hinweis-Fenster angezeigt. - - - Toggle the validity check of place markers. - Prüfung der Platzhalter ein- bzw. ausschalten. - Toggle the validity check of place markers, i.e. whether %1, %2, ... are used consistently in the source text and translation text. If the check fails, a message is shown in the warnings window. @@ -716,14 +523,14 @@ p, li { white-space: pre-wrap; } Ctrl+S + - Save &As... Speichern &unter... - + Save As... Speichern unter ... @@ -747,10 +554,6 @@ p, li { white-space: pre-wrap; } &Print... &Drucken ... - - Print a list of all the phrases in the current Qt translation source file. - Drucke die Liste aller Übersetzungen in der aktuellen Qt Übersetzungsdatei. - Ctrl+P @@ -761,10 +564,6 @@ p, li { white-space: pre-wrap; } &Undo &Rückgängig - - Undo the last editing operation performed on the translation. - Mache die letzte Änderung an der Übersetzung rückgängig. - Recently Opened &Files @@ -915,10 +714,6 @@ p, li { white-space: pre-wrap; } Ctrl+W Ctrl+W - - Moves to the previous unfinished item. - Gehe zum letzten unerledigten Eintrag. - Ctrl+K @@ -929,23 +724,11 @@ p, li { white-space: pre-wrap; } &Next Unfinished &Nächster Unerledigter - - Moves to the next unfinished item. - Gehe zum nächsten unerledigten Eintrag. - - - Ctrl+L - Ctrl+L - P&rev V&orheriger - - Moves to the previous item. - Gehe zum letzten Eintrag. - Ctrl+Shift+K @@ -956,27 +739,11 @@ p, li { white-space: pre-wrap; } Ne&xt Nä&chster - - Moves to the next item. - Gehe zum nächsten Eintrag. - - - Ctrl+Shift+L - Ctrl+Shift+L - &Done and Next &Fertig und Nächster - - Marks this item as done and moves to the next unfinished item. - Markiere diesen Eintrag als erledigt und gehe zum nächsten unerledigten Eintrg. - - - &Begin from source - Übernehme &Ursprungstext - Copies the source text into the translation field. @@ -992,38 +759,21 @@ p, li { white-space: pre-wrap; } &Accelerators &Kurzbefehle - - Toggle validity checks of accelerators. - Aktiviere/Deaktiviere Validitätsprüfung für Kurztasten. - &Ending Punctuation &Punktierung am Ende - - Toggle validity checks of ending punctuation. - Aktiviere/Deaktiviere Validitätsprüfung für Punktierung am Ende des Textes. - &Phrase matches &Wörterbuch - - - Toggle checking that phrase suggestions are used. - Überprüfung, ob Wörterbucheinträge benutzt werden, aktivieren/deaktivieren. - Place &Marker Matches Platz&halter - - Toggle validity checks of place markers. - Aktiviere/Deaktiviere Validitätsprüfung für Platzhalter . - &New Phrase Book... @@ -1140,36 +890,31 @@ p, li { white-space: pre-wrap; } Die Übersetzung aller Einträge ersetzen, die dem Suchtext entsprechen. + - &Batch Translation... &Automatische Übersetzung ... - + Batch translate all entries using the information in the phrase books. Alle Einträge automatisch mit Hilfe des Wörterbuchs übersetzen. + - Release As... Freigeben unter ... - - Create a Qt message file suitable for released applications from the current message file. The filename will automatically be determined from the name of the .ts file. - Eine Qt-Nachrichtendatei aus der aktuellen Übersetzungsdatei erzeugen. Der Dateiname wird automatisch aus dem Namen der TS-Datei abgeleitet. - - - + This is the application's main window. - + Source text Ursprungstext @@ -1181,17 +926,17 @@ p, li { white-space: pre-wrap; } - + Context Kontext - + Items Einträge - + This panel lists the source contexts. Dieser Bereich zeigt die Kontexte an. @@ -1219,10 +964,10 @@ p, li { white-space: pre-wrap; } MOD status bar: file(s) modified - + Geändert - + Loading... Lade ... @@ -1275,14 +1020,19 @@ Soll die erstgenannte Datei übersprungen werden? Datei gespeichert. - - + + <center><img src=":/images/splash.png"/></img><p>%1</p></center><p>Qt Linguist is a tool for adding translations to Qt applications.</p><p>Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).</p><p>The program is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.</p> + + + + + Release Freigeben - + Qt message files for released applications (*.qm) All files (*) Qt-Nachrichtendateien (*.qm) @@ -1295,7 +1045,7 @@ Alle Dateien (*) Datei erzeugt. - + Printing... Drucke ... @@ -1346,7 +1096,7 @@ Alle Dateien (*) - + @@ -1358,18 +1108,11 @@ Alle Dateien (*) Qt Linguist - + Cannot find the string '%1'. Kann Zeichenkette '%1' nicht finden. - - Translated %n entries to '%1' - - Ein Eintrag wurde mit '%1' übersetzt - %n Einträge wurden mit '%1' übersetzt - - Search And Translate in '%1' - Qt Linguist @@ -1463,16 +1206,7 @@ Alle Dateien (*) Version %1 - Open Source Edition - Open Source Edition - - - - <center><img src=":/images/splash.png"/></img><p>%1</p></center><p>Qt Linguist is a tool for adding translations to Qt applications.</p><p>%2</p><p>Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).</p><p>The program is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.</p> - <center><img src=":/images/splash.png"/></img><p>%1</p></center><p>Qt Linguist ist ein Werkzeug zum Übersetzen von Qt-Anwendungen.</p><p>%2</p><p>Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).</p><p>The program is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.</p> - - - + Do you want to save the modified files? Möchten Sie die geänderten Dateien speichern? @@ -1559,13 +1293,13 @@ Alle Dateien (*) Alles speichern - + &Release All Alles f&reigeben - + Close All Alle schließen @@ -1590,37 +1324,37 @@ Alle Dateien (*) Suchen und &übersetzen ... - + File Datei - - + + Edit Bearbeiten - - + + Translation Übersetzung - - + + Validation Validierung - - + + Help Hilfe - + Cannot read from phrase book '%1'. Wörterbuch '%1' kann nicht gelesen werden. @@ -1650,7 +1384,7 @@ Alle Dateien (*) Möchten Sie das Wörterbuch '%1' speichern? - + All Alle @@ -1670,21 +1404,13 @@ Alle Dateien (*) F5 - - + + Translation File &Settings... E&instellungen ... - Other &Languages... - A&ndere Sprachen... - - - Edit which other languages to show. - Welche anderen Sprachen sollen dargestellt werden. - - - + &Add to Phrase Book Zum Wörterbuch &hinzufügen @@ -1703,22 +1429,93 @@ Alle Dateien (*) Ctrl+Shift+J Ctrl+Shift+J - - - MessageEditor - - German - Deutsch + + Previous unfinished item + Vorheriger unerledigter Eintrag - - Japanese - Japanisch + + Next unfinished item + Nächster unerledigter Eintrag - - French + + Move to previous item + Zum vorigen Eintrag gehen + + + + Next item + Nächster Eintrag + + + + Mark item as done and move to the next unfinished item + Eintrag als erledigt markieren und zum nächsten unerledigten Eintrag gehen + + + + Copies the source text into the translation field + Kopiert den Ursprungstext in das Übersetzungsfeld + + + + Toggle the validity check of accelerators + Prüfung der Tastenkürzel ein- bzw. ausschalten + + + + Toggle the validity check of ending punctuation + Prüfung der Satzendezeichen am Ende des Textes ein- bzw. ausschalten + + + + Toggle checking that phrase suggestions are used + Überprüfung, ob Wörterbucheinträge benutzt werden, aktivieren/deaktivieren + + + + Toggle the validity check of place markers + Prüfung der Platzhalter ein- bzw. ausschalten' + + + + Create a Qt message file suitable for released applications from the current message file. The filename will automatically be determined from the name of the TS file. + Eine Qt-Nachrichtendatei aus der aktuellen Übersetzungsdatei erzeugen. Der Dateiname wird automatisch aus dem Namen der TS-Datei abgeleitet. + + + + Length Variants + Längenvarianten + + + + MessageEditor + + + + This is the right panel of the main window. + + + + + Russian + Russisch + + + + German + Deutsch + + + + Japanese + Japanisch + + + + French Französisch @@ -1732,7 +1529,7 @@ Alle Dateien (*) Chinesisch - + This whole panel allows you to view and edit the translation of some source text. Dieser Bereich erlaubt die Darstellung und Änderung der Übersetzung eines Textes. @@ -1747,7 +1544,7 @@ Alle Dateien (*) Dieser Bereich zeigt den Ursprungstext. - + Source text (Plural) Ursprungstext (Plural) @@ -1757,7 +1554,7 @@ Alle Dateien (*) Dieser Bereich zeigt die Pluralform des Ursprungstexts. - + Developer comments Hinweise des Entwicklers @@ -1772,12 +1569,12 @@ Alle Dateien (*) Hier können Sie Hinweise für den eigenen Gebrauch eintragen. Diese haben keinen Einflusse auf die Übersetzung. - + %1 translation (%2) Übersetzung %1 (%2) - + This is where you can enter or modify the translation of the above source text. Hier können Sie die Übersetzung des Ursprungstextes eingeben bzw. ändern. @@ -1792,55 +1589,15 @@ Alle Dateien (*) %1 Hinweise des Übersetzers - + '%1' Line: %2 '%1' Zeile: %2 - - %1 Translation (%2) - Übersetzung %1 (%2) - - - bell - bell - - - backspace - Rücktaste - - - new page - Neue Seite - - - new line - Neue Zeile - - - carriage return - Carriage Return - - - tab - Tab - MessageModel - - Context - Kontext - - - Items - Einträge - - - Index - Index - Completion status for %1 @@ -1862,17 +1619,10 @@ Zeile: %2 <unbenannter Kontext> - - MessagesTreeView - - Done - Done - - MsgEdit - + This is the right panel of the main window. @@ -1881,17 +1631,18 @@ Zeile: %2 PhraseBookBox - %1 - %2[*] - %1 - %2[*] - - - + Go to Phrase > Edit Phrase Book... The dialog that pops up is a PhraseBookBox. - + + (New Entry) + (Neuer Eintrag) + + + %1[*] - Qt Linguist %1[*] - Qt Linguist @@ -1910,10 +1661,6 @@ Zeile: %2 Edit Phrase Book Wörterbuch bearbeiten - - This window allows you to add, modify, or delete phrases in a phrase book. - Dieses Fenster erlaubt das Hinzufügen, Ändern und Entfernen von Einträgen aus dem Wörterbuch. - This window allows you to add, modify, or delete entries in a phrase book. @@ -1974,18 +1721,6 @@ Zeile: %2 Settin&gs... &Einstellungen ... - - &New Phrase - &Neuer Eintrag - - - Click here to remove the phrase from the phrase book. - Entferne den Eintrag aus dem Wörterbuch. - - - &Remove Phrase - &Entferne Eintrag - Click here to save the changes made. @@ -2028,7 +1763,7 @@ Zeile: %2 PhraseView - + Insert Einfügen @@ -2056,7 +1791,7 @@ Zeile: %2 Kompilierte Qt-Übersetzungen - + Translation files (%1);; Übersetzungsdateien (%1);; @@ -2077,25 +1812,10 @@ Zeile: %2 Qt Linguist - - C++ source files - C++-Quelltextdateien - - - - Java source files - Java-Quelltextdateien - - - + GNU Gettext localization files GNU-Gettext-Übersetzungsdateien - - - Qt Script source files - Qt-Skript-Quelltextdateien - Qt translation sources (format 1.1) @@ -2112,60 +1832,16 @@ Zeile: %2 Qt-Übersetzungsdateien (aktuelles Format) - - Qt Designer form files - Formulardateien für Qt Designer - - - - Qt Jambi form files - Formulardateien für Qt Jambi - - - + XLIFF localization files XLIFF-Übersetzungsdateien - + Qt Linguist 'Phrase Book' Qt-Linguist-Wörterbuch - - QtWindowListMenu - - Tile - Teilen - - - Cascade - Kaskadieren - - - Close - Schließen - - - Close All - Alle schließen - - - - SortedMessagesModel - - Source text - Ursprungstext - - - Translation - Übersetzung - - - Index - Index - - SourceCodeView @@ -2191,10 +1867,6 @@ Zeile: %2 Statistics Statistiken - - &Close - &Schließen - Translation @@ -2231,406 +1903,8 @@ Zeile: %2 Schließen - - TrPreviewTool - - <No Translation> - <Keine Übersetzung> - - - Open Forms - Öffne Maske - - - User interface form files (*.ui);;All files (*.*) - User Interface Masken Dateien (*.ui);;Alle Dateien (*.*) - - - Could not load form file(s): - - Könnte Quelldateien nicht laden: - - - - Load Translation - Lade Übersetzung - - - Translation files (*.qm);;All files (*.*) - Übersetzungsdateien (*.qm);;Alle Dateien (*.*) - - - Could not load translation file: - - Konnte Übersetzungsdatei nicht laden: - - - - Could not reload translation file(s): - - Konnte Übersetzungsdateien nicht erneut laden: - - - - Qt Translation Preview Tool: Warning - Qt Vorschau: Warnung - - - About - Info - - - Could not load form file: -%1. - Konnte Maskendatei nicht laden. -%1. - - - - TrPreviewToolClass - - Qt Translation Preview Tool - Qt Vorschau Tool - - - &View - &Ansicht - - - &Views - &Ansichten - - - &Help - &Hilfe - - - &File - &Datei - - - Forms - Masken - - - &Open Form... - &Öffne Maske... - - - &Load Translation... - &Lade Übersetzung... - - - &Reload Translations - Lade Übersetzungen &neu - - - F5 - F5 - - - &Close - &Schließen - - - About - Info - - - About Qt - Über Qt - - - - TrWindow - - Context - Kontext - - - This panel lists the source contexts. - Dieser Bereich zeigt die Kontexte an. - - - Strings - Zeichenketten - - - Phrases and guesses - Wörterbuch und Vorschläge - - - Source code - Quelltext - - - Warnings - Warnungen - - - MOD - MOD - - - Loading... - Lade... - - - Qt Linguist - Qt Linguist - - - Cannot open '%1'. - Kann '%1' nicht öffnen. - - - %n source phrase(s) loaded. - - Einen Ursprungstext geladen. - %n Ursprungstexte geladen. - - - - Open Translation File - Öffne Übersetzungsdatei - - - Qt translation sources (*.ts);;XLIFF localization files (*.xlf);;All files (*) - Qt Übersetzungsdateien (*.ts);;Qt Übersetzungsdateien (*.ts);;Alle Dateien (*) - - - File saved. - Datei gespeichert. - - - Cannot save '%1'. - Kann '%1' nicht speichern. - - - Qt translation source (*.ts) -XLIFF localization file (*.xlf) -All files (*) - Qt Übersetzungsdateien (*.ts) -Qt Übersetzungsdateien (*.ts) -Alle Dateien (*) - - - Release - Freigeben - - - Qt message files for released applications (*.qm) -All files (*) - Qt Nachrichtendateien (*.qm) -Alle Dateien (*) - - - File created. - Datei erzeugt. - - - Printing... - Drucke... - - - Context: %1 - Kontext: %1 - - - finished - erledigt - - - unresolved - ungelöst - - - obsolete - veraltet - - - Printing... (page %1) - Drucke... (Seite %1) - - - Printing completed - Drucken beendet - - - Printing aborted - Drucken abgebrochen - - - Search wrapped. - Suche beginnt von oben. - - - Cannot find the string '%1'. - Kann Zeichenkette '%1' nicht finden. - - - Translate - Übersetzungen - - - Translated %n entries to '%1' - - Ein Eintrag wurde mit '%1' übersetzt - %n Einträge wurden mit '%1' übersetzt - - - - Create New Phrase Book - Erzeugen eines neuen Wörterbuchs - - - Qt phrase books (*.qph) -All files (*) - Qt Wörterbücher (*.qph) -Alle Dateien (*) - - - A file called '%1' already exists. Please choose another name. - Die Datei '%1' existiert schon. Bitte wählen Sie einen anderen Namen. - - - Phrase book created. - Wörterbuch erzeugt. - - - Open Phrase Book - Öffne Wörterbuch - - - Qt phrase books (*.qph);;All files (*) - Qt Wörterbücher (*.qph);;Alle Dateien (*) - - - %n phrase(s) loaded. - - Ein Wörterbucheintrag geladen. - %n Wörterbucheinträge geladen. - - - - Add to phrase book - Hinzufügen zum Wörterbuch - - - Adding phrase to phrasebook %1 - Eintrag zu Wörterbuch %1 hinzufügen - - - Select phrase book to add to - Zu welchem Wörterbuch soll der Eintrag hinzugefügt werden? - - - Unable to launch Qt Assistant (%1) - Kann Qt Assistant nicht starten (%1) - - - Version %1 - Version %1 - - - Open Source Edition - Open Source Edition - - - <center><img src=":/images/splash.png"/></img><p>%1</p></center><p>Qt Linguist is a tool for adding translations to Qt applications.</p><p>%2</p><p>Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).</p><p>The program is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.</p> - <center><img src=":/images/splash.png"/></img><p>%1</p></center><p>Qt Linguist ist ein Werkzeug zum Übersetzen von Qt Anwendungen.</p><p>%2</p><p>Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).</p><p>The program is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.</p> - - - Do you want to save '%1'? - Wollen Sie '%1' speichern? - - - Qt Linguist by Trolltech[*] - Qt Linguist von Trolltech[*] - - - %1 - %2[*] - %1 - %2[*] - - - Qt Linguist by Trolltech - Qt Linguist von Trolltech - - - No untranslated phrases left. - Alle Einträge sind übersetzt. - - - &Window - &Fenster - - - Minimize - Minimieren - - - Ctrl+M - Ctrl+M - - - Display the manual for %1. - Zeige Handbuch für %1 an. - - - Display information about %1. - Zeige Informationen über %1 an. - - - File - Datei - - - Edit - Bearbeiten - - - Translation - Übersetzung - - - Validation - Validierung - - - Help - Hilfe - - - Cannot read from phrase book '%1'. - Kann Wörterbuch '%1' nicht lesen. - - - Close this phrase book. - Schließe dieses Wörterbuch. - - - Allow you to add, modify, or delete phrases of this phrase book. - Erlaubt das Hinzufügen, Ändern und Entfernen von Einträgen aus dem Wörterbuch. - - - Print the entries of the phrase book. - Drucke die Einträge des Wörterbuchs. - - - Cannot create phrase book '%1'. - Kann Wörterbuch '%1' nicht erzeugen. - - - Do you want to save phrasebook '%1'? - Wollen Sie das Wörterbuch '%1' speichern? - - TranslateDialog - - Qt Linguist - Qt Linguist - This window allows you to search for some text in the translation source file. @@ -2702,25 +1976,6 @@ Alle Dateien (*) Abbrechen - - TranslationSettings - - Qt Linguist - Translation file settings - Qt Linguist - Einstellungen der Übersetzungsdatei - - - Target language - Zielsprache - - - Language - Sprache - - - Country/Region - Land/Region - - TranslationSettingsDialog @@ -2755,47 +2010,4 @@ Alle Dateien (*) Zielsprache - - databaseTranslationDialog - - Qt Linguist - Batch Translation - Qt Linguist - Automatische Übersetzung - - - Options - Optionen - - - Only translate entries with no translation - Übersetze nur Einträge ohne bisherige Übersetzung - - - Set translated entries to finished - Markiere Übersetzung als erledigt - - - Phrase book preference - Wörterbücher - - - Move up - Nach oben - - - Move down - Nach unten - - - The batch translator will search through the selected phrasebooks in the order given above. - Der automatische Übersetzer wird in der angegebenen Reihenfolge durch die ausgewählten Wörterbücher gehen. - - - &Run - &Ausführen - - - &Cancel - &Abbrechen - - diff --git a/translations/qt_help_de.ts b/translations/qt_help_de.ts index 9d48661f1..8e6cb8562 100644 --- a/translations/qt_help_de.ts +++ b/translations/qt_help_de.ts @@ -111,8 +111,9 @@ QHelpDBReader - + Cannot open database '%1' '%2': %3 + The placeholders are: %1 - The name of the database which cannot be opened %2 - The unique id for the connection %3 - The actual error string Kann Datenbank nicht öffnen: '%1' '%2': %3 @@ -200,17 +201,22 @@ Dateien einfügen... - + + The referenced file %1 must be inside or within a subdirectory of (%2). Skipping it. + Die referenzierte Datei %1 muss sich im Verzeichnis %2 oder in einem Unterverzeichnis davon befinden. Sie wird übersprungen. + + + The file %1 does not exist! Skipping it. Die Datei %1 existiert nicht. Wird übersprungen. - + Cannot open file %1! Skipping it. Die Datei %1 kann nicht geöffnet werden. Wird übersprungen. - + The filter %1 is already registered! Der Filter %1 ist bereits registriert. @@ -243,17 +249,27 @@ QHelpSearchQueryWidget - + Search for: Suche nach: + + + Previous search + Vorige Suche + + + + Next search + Nächste Suche + Search Suche - + Advanced search Erweiterte Suche @@ -263,22 +279,22 @@ Worte <B>ähnlich</B> zu: - + <B>without</B> the words: <B>ohne</B> die Wörter: - + with <B>exact phrase</B>: mit der <B>genauen Wortgruppe</B>: - + with <B>all</B> of the words: mit <B>allen</B> Wörtern: - + with <B>at least one</B> of the words: mit <B>irgendeinem</B> der Wörter: @@ -307,7 +323,7 @@ Ohne Titel - + Unknown token. Unbekanntes Token. @@ -347,7 +363,7 @@ Fehlendes Attribut in Schlagwort in Zeile %1. - + The input file %1 could not be opened! Die Eingabe-Datei %1 kann nicht geöffnet werden. -- cgit v1.2.3 From 4111f8d417409579d591798c491f9f2aa7c0021d Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Mon, 10 Aug 2009 16:54:28 +0200 Subject: New mkspecs for Windows Mobile 6.5 We need extra mkspecs for Windows Mobile 6.5 to support gestures, since gestures are only supported with 6.5 Reviewed-by: Maurice --- .../default_post.prf | 1 + mkspecs/wincewm65professional-msvc2005/qmake.conf | 5 +++ .../wincewm65professional-msvc2005/qplatformdefs.h | 42 +++++++++++++++++++++ .../default_post.prf | 1 + mkspecs/wincewm65professional-msvc2008/qmake.conf | 3 ++ .../wincewm65professional-msvc2008/qplatformdefs.h | 43 ++++++++++++++++++++++ 6 files changed, 95 insertions(+) create mode 100644 mkspecs/wincewm65professional-msvc2005/default_post.prf create mode 100644 mkspecs/wincewm65professional-msvc2005/qmake.conf create mode 100644 mkspecs/wincewm65professional-msvc2005/qplatformdefs.h create mode 100644 mkspecs/wincewm65professional-msvc2008/default_post.prf create mode 100644 mkspecs/wincewm65professional-msvc2008/qmake.conf create mode 100644 mkspecs/wincewm65professional-msvc2008/qplatformdefs.h diff --git a/mkspecs/wincewm65professional-msvc2005/default_post.prf b/mkspecs/wincewm65professional-msvc2005/default_post.prf new file mode 100644 index 000000000..86bc964a5 --- /dev/null +++ b/mkspecs/wincewm65professional-msvc2005/default_post.prf @@ -0,0 +1 @@ +include(../wincewm60professional-msvc2005/default_post.prf) diff --git a/mkspecs/wincewm65professional-msvc2005/qmake.conf b/mkspecs/wincewm65professional-msvc2005/qmake.conf new file mode 100644 index 000000000..b4ae0966c --- /dev/null +++ b/mkspecs/wincewm65professional-msvc2005/qmake.conf @@ -0,0 +1,5 @@ +include(../wincewm60professional-msvc2005/qmake.conf) + +DEFINES += QT_WINCE_GESTURES +QMAKE_LIBS_GUI += TouchGestureCore.lib + diff --git a/mkspecs/wincewm65professional-msvc2005/qplatformdefs.h b/mkspecs/wincewm65professional-msvc2005/qplatformdefs.h new file mode 100644 index 000000000..4317bc11e --- /dev/null +++ b/mkspecs/wincewm65professional-msvc2005/qplatformdefs.h @@ -0,0 +1,42 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the qmake spec of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "../wincewm60professional-msvc2005/qplatformdefs.h" diff --git a/mkspecs/wincewm65professional-msvc2008/default_post.prf b/mkspecs/wincewm65professional-msvc2008/default_post.prf new file mode 100644 index 000000000..c85456184 --- /dev/null +++ b/mkspecs/wincewm65professional-msvc2008/default_post.prf @@ -0,0 +1 @@ +include(../wincewm65professional-msvc2005/default_post.prf) diff --git a/mkspecs/wincewm65professional-msvc2008/qmake.conf b/mkspecs/wincewm65professional-msvc2008/qmake.conf new file mode 100644 index 000000000..552c7c8be --- /dev/null +++ b/mkspecs/wincewm65professional-msvc2008/qmake.conf @@ -0,0 +1,3 @@ +include(../wincewm65professional-msvc2005/qmake.conf) +QMAKE_COMPILER_DEFINES -= _MSC_VER=1400 +QMAKE_COMPILER_DEFINES += _MSC_VER=1500 diff --git a/mkspecs/wincewm65professional-msvc2008/qplatformdefs.h b/mkspecs/wincewm65professional-msvc2008/qplatformdefs.h new file mode 100644 index 000000000..7f724f9b2 --- /dev/null +++ b/mkspecs/wincewm65professional-msvc2008/qplatformdefs.h @@ -0,0 +1,43 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the qmake spec of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "../wincewm65professional-msvc2005/qplatformdefs.h" + -- cgit v1.2.3 From 9a92aee8ff94a1b705e92f895831f9437762da75 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Mon, 10 Aug 2009 16:56:22 +0200 Subject: Gesture support for Windows Mobile 6.5 Gestures on Windows Mobile 6.5 rely on a statically linked library, that is added in the mkspecs for Windows Mobile 6.5 In the case the gesture functions do not have been resolved (==0), we do not call them. Reviewed-by: Joerg --- src/gui/kernel/qapplication_win.cpp | 58 ++++++++++++++++++++++++++----------- 1 file changed, 41 insertions(+), 17 deletions(-) diff --git a/src/gui/kernel/qapplication_win.cpp b/src/gui/kernel/qapplication_win.cpp index bdee6ecd0..281be3343 100644 --- a/src/gui/kernel/qapplication_win.cpp +++ b/src/gui/kernel/qapplication_win.cpp @@ -51,6 +51,9 @@ extern void qt_wince_hide_taskbar(HWND hwnd); //defined in qguifunctions_wince.c #ifdef Q_WS_WINCE_WM #include #include +#ifdef QT_WINCE_GESTURES +#include +#endif #endif #include "qapplication.h" @@ -815,30 +818,41 @@ void qt_init(QApplicationPrivate *priv, int) ptrSetProcessDPIAware(); #endif + priv->GetGestureInfo = 0; + priv->GetGestureExtraArgs = 0; + +#ifdef Q_WS_WINCE_WM + priv->GetGestureInfo = (PtrGetGestureInfo) &TKGetGestureInfo; + priv->GetGestureExtraArgs = (PtrGetGestureExtraArgs) &TKGetGestureExtraArguments; + priv->CloseGestureInfoHandle = (PtrCloseGestureInfoHandle) 0; + priv->SetGestureConfig = (PtrSetGestureConfig) 0; + priv->GetGestureConfig = (PtrGetGestureConfig) 0; +#else priv->GetGestureInfo = - (PtrGetGestureInfo)QLibrary::resolve(QLatin1String("user32"), - "GetGestureInfo"); + (PtrGetGestureInfo)QLibrary::resolve(QLatin1String("user32"), + "GetGestureInfo"); priv->GetGestureExtraArgs = - (PtrGetGestureExtraArgs)QLibrary::resolve(QLatin1String("user32"), - "GetGestureExtraArgs"); + (PtrGetGestureExtraArgs)QLibrary::resolve(QLatin1String("user32"), + "GetGestureExtraArgs"); priv->CloseGestureInfoHandle = - (PtrCloseGestureInfoHandle)QLibrary::resolve(QLatin1String("user32"), - "CloseGestureInfoHandle"); + (PtrCloseGestureInfoHandle)QLibrary::resolve(QLatin1String("user32"), + "CloseGestureInfoHandle"); + priv->SetGestureConfig = + (PtrSetGestureConfig)QLibrary::resolve(QLatin1String("user32"), + "SetGestureConfig"); priv->SetGestureConfig = - (PtrSetGestureConfig)QLibrary::resolve(QLatin1String("user32"), - "SetGestureConfig"); - priv->GetGestureConfig = - (PtrGetGestureConfig)QLibrary::resolve(QLatin1String("user32"), - "GetGestureConfig"); + (PtrGetGestureConfig)QLibrary::resolve(QLatin1String("user32"), + "GetGestureConfig"); priv->BeginPanningFeedback = - (PtrBeginPanningFeedback)QLibrary::resolve(QLatin1String("uxtheme"), - "BeginPanningFeedback"); + (PtrBeginPanningFeedback)QLibrary::resolve(QLatin1String("uxtheme"), + "BeginPanningFeedback"); priv->UpdatePanningFeedback = - (PtrUpdatePanningFeedback)QLibrary::resolve(QLatin1String("uxtheme"), - "UpdatePanningFeedback"); + (PtrUpdatePanningFeedback)QLibrary::resolve(QLatin1String("uxtheme"), + "UpdatePanningFeedback"); priv->EndPanningFeedback = (PtrEndPanningFeedback)QLibrary::resolve(QLatin1String("uxtheme"), "EndPanningFeedback"); +#endif } /***************************************************************************** @@ -3720,7 +3734,16 @@ bool QETWidget::translateGestureEvent(const MSG &msg) gi.cbSize = sizeof(GESTUREINFO); QApplicationPrivate *qAppPriv = getQApplicationPrivateInternal(); - BOOL bResult = qAppPriv->GetGestureInfo((HANDLE)msg.lParam, &gi); +#ifdef Q_WS_WINCE_WM +#define GID_ZOOM 0xf000 +#define GID_ROTATE 0xf001 +#define GID_TWOFINGERTAP 0xf002 +#define GID_ROLLOVER 0xf003 +#endif + BOOL bResult = false; + if (qAppPriv->GetGestureInfo) + bResult = qAppPriv->GetGestureInfo((HANDLE)msg.lParam, &gi); + const QPoint widgetPos = QPoint(gi.ptsLocation.x, gi.ptsLocation.y); QWidget *alienWidget = !internalWinId() ? this : childAt(widgetPos); @@ -3751,7 +3774,8 @@ bool QETWidget::translateGestureEvent(const MSG &msg) default: break; } - qAppPriv->CloseGestureInfoHandle((HANDLE)msg.lParam); + if (qAppPriv->CloseGestureInfoHandle) + qAppPriv->CloseGestureInfoHandle((HANDLE)msg.lParam); if (event.gestureType != QNativeGestureEvent::None) qt_sendSpontaneousEvent(widget, &event); } else { -- cgit v1.2.3 From d918f98a4ab80405e0fe75fadf8491069a4c7ab8 Mon Sep 17 00:00:00 2001 From: Harald Fernengel Date: Mon, 10 Aug 2009 17:02:32 +0200 Subject: Make chooseConfig work on some EGL implementations According to the spec, if we pass a 0 out pointer, EGL should tell us how many configurations are available. However, we pass a 0 out pointer, but say that it's 256 elements big, it confuses some implementations. Fix that by passing a 0 out pointer and saying that it has space for 0 elements. Now we correctly get the amount of available configs. Reviewed-by: Rhys Weatherley --- src/gui/egl/qegl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/egl/qegl.cpp b/src/gui/egl/qegl.cpp index ebdac9a60..1c45a58eb 100644 --- a/src/gui/egl/qegl.cpp +++ b/src/gui/egl/qegl.cpp @@ -95,7 +95,7 @@ bool QEglContext::chooseConfig do { // Get the number of matching configurations for this set of properties. EGLint matching = 0; - if (!eglChooseConfig(dpy, props.properties(), 0, 256, &matching) || !matching) + if (!eglChooseConfig(dpy, props.properties(), 0, 0, &matching) || !matching) continue; // If we want the best pixel format, then return the first -- cgit v1.2.3 From c3610da4be9b12bfe01b565db5ed2508da88c120 Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Mon, 10 Aug 2009 12:13:46 +0200 Subject: tst_QSharedPointer fixed for Windows CE We cannot create too many threads on Windows CE. Reviewed-By: thartman --- tests/auto/qsharedpointer/tst_qsharedpointer.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/auto/qsharedpointer/tst_qsharedpointer.cpp b/tests/auto/qsharedpointer/tst_qsharedpointer.cpp index 1101a0888..516729cb8 100644 --- a/tests/auto/qsharedpointer/tst_qsharedpointer.cpp +++ b/tests/auto/qsharedpointer/tst_qsharedpointer.cpp @@ -1373,7 +1373,9 @@ void tst_QSharedPointer::threadStressTest_data() QTest::newRow("5+10") << 5 << 10; QTest::newRow("5+30") << 5 << 30; +#ifndef Q_OS_WINCE QTest::newRow("100+100") << 100 << 100; +#endif } void tst_QSharedPointer::threadStressTest() -- cgit v1.2.3 From a6d51bc97a923bd990e5188035f7c913456138f7 Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Mon, 10 Aug 2009 15:12:08 +0200 Subject: respect QAbstractSpinBox::NoButtons in windowsce / windowsmobile styles Code is adapted from QCommonStyle which handles this case for other styles. Reviewed-by: thartman --- src/gui/styles/qwindowscestyle.cpp | 6 +++++- src/gui/styles/qwindowsmobilestyle.cpp | 4 ++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/gui/styles/qwindowscestyle.cpp b/src/gui/styles/qwindowscestyle.cpp index 997fc722f..cd13dd8a7 100644 --- a/src/gui/styles/qwindowscestyle.cpp +++ b/src/gui/styles/qwindowscestyle.cpp @@ -1951,7 +1951,11 @@ QRect QWindowsCEStyle::subControlRect(ComplexControl control, const QStyleOption rect = QRect(x, y , bs.width(), bs.height()); break; case SC_SpinBoxEditField: - rect = QRect(lx, fw, rx-2, spinbox->rect.height() - 2*fw); + if (spinbox->buttonSymbols == QAbstractSpinBox::NoButtons) { + rect = QRect(lx, fw, spinbox->rect.width() - 2*fw - 2, spinbox->rect.height() - 2*fw); + } else { + rect = QRect(lx, fw, rx-2, spinbox->rect.height() - 2*fw); + } break; case SC_SpinBoxFrame: rect = spinbox->rect; diff --git a/src/gui/styles/qwindowsmobilestyle.cpp b/src/gui/styles/qwindowsmobilestyle.cpp index c70b4c83f..e7080423e 100644 --- a/src/gui/styles/qwindowsmobilestyle.cpp +++ b/src/gui/styles/qwindowsmobilestyle.cpp @@ -2984,7 +2984,11 @@ QRect QWindowsMobileStyle::subControlRect(ComplexControl control, const QStyleOp rect = QRect(x + bs.width(), 0, bs.width(), bs.height()); break; case SC_SpinBoxEditField: + if (spinBox->buttonSymbols == QAbstractSpinBox::NoButtons) { + rect = QRect(lx, fw, spinBox->rect.width() - 2*fw - 2, spinBox->rect.height() - 2*fw); + } else { rect = QRect(lx, fw, rx-2, spinBox->rect.height() - 2*fw); + } break; case SC_SpinBoxFrame: rect = spinBox->rect; -- cgit v1.2.3 From 8262b8b7dfda60446685eed8ec373c4da252cbeb Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Mon, 10 Aug 2009 15:18:35 +0200 Subject: remove compiler warning for Windows CE whitespaces fixed Reviewed-by: TrustMe --- src/corelib/io/qprocess_win.cpp | 46 ++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/src/corelib/io/qprocess_win.cpp b/src/corelib/io/qprocess_win.cpp index eae17b4cf..d8da606c6 100644 --- a/src/corelib/io/qprocess_win.cpp +++ b/src/corelib/io/qprocess_win.cpp @@ -372,32 +372,30 @@ void QProcessPrivate::startProcess() qDebug(" pass environment : %s", environment.isEmpty() ? "no" : "yes"); #endif - DWORD dwCreationFlags = CREATE_NO_WINDOW; - #if defined(Q_OS_WINCE) - QString fullPathProgram = program; - if (!QDir::isAbsolutePath(fullPathProgram)) - fullPathProgram = QFileInfo(fullPathProgram).absoluteFilePath(); - fullPathProgram.replace(QLatin1Char('/'), QLatin1Char('\\')); - success = CreateProcess((wchar_t*)fullPathProgram.utf16(), - (wchar_t*)args.utf16(), - 0, 0, false, 0, 0, 0, 0, pid); + QString fullPathProgram = program; + if (!QDir::isAbsolutePath(fullPathProgram)) + fullPathProgram = QFileInfo(fullPathProgram).absoluteFilePath(); + fullPathProgram.replace(QLatin1Char('/'), QLatin1Char('\\')); + success = CreateProcess((wchar_t*)fullPathProgram.utf16(), + (wchar_t*)args.utf16(), + 0, 0, false, 0, 0, 0, 0, pid); #else - dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT; - STARTUPINFOW startupInfo = { sizeof( STARTUPINFO ), 0, 0, 0, - (ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT, - (ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT, - 0, 0, 0, - STARTF_USESTDHANDLES, - 0, 0, 0, - stdinChannel.pipe[0], stdoutChannel.pipe[1], stderrChannel.pipe[1] - }; - success = CreateProcess(0, (wchar_t*)args.utf16(), - 0, 0, TRUE, dwCreationFlags, - environment ? envlist.data() : 0, - workingDirectory.isEmpty() ? 0 - : (wchar_t*)QDir::toNativeSeparators(workingDirectory).utf16(), - &startupInfo, pid); + DWORD dwCreationFlags = CREATE_NO_WINDOW; + dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT; + STARTUPINFOW startupInfo = { sizeof( STARTUPINFO ), 0, 0, 0, + (ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT, + (ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT, + 0, 0, 0, + STARTF_USESTDHANDLES, + 0, 0, 0, + stdinChannel.pipe[0], stdoutChannel.pipe[1], stderrChannel.pipe[1] + }; + success = CreateProcess(0, (wchar_t*)args.utf16(), + 0, 0, TRUE, dwCreationFlags, + environment ? envlist.data() : 0, + workingDirectory.isEmpty() ? 0 : (wchar_t*)QDir::toNativeSeparators(workingDirectory).utf16(), + &startupInfo, pid); if (stdinChannel.pipe[0] != INVALID_Q_PIPE) { CloseHandle(stdinChannel.pipe[0]); -- cgit v1.2.3 From 33e9b82813f5573be6e5a780524044a2170d8dd4 Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Mon, 10 Aug 2009 17:00:27 +0200 Subject: don't test dbus stuff where no dbus is Reviewed-by: Leo --- tests/auto/auto.pro | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro index d3e295be0..d7f27bd1b 100644 --- a/tests/auto/auto.pro +++ b/tests/auto/auto.pro @@ -106,8 +106,6 @@ SUBDIRS += \ qdate \ qdatetime \ qdatetimeedit \ - qdbuspendingcall \ - qdbuspendingreply \ qdebug \ qdesktopservices \ qdesktopwidget \ @@ -457,6 +455,8 @@ unix:!embedded:contains(QT_CONFIG, dbus):SUBDIRS += \ qdbusmarshall \ qdbusmetaobject \ qdbusmetatype \ + qdbuspendingcall \ + qdbuspendingreply \ qdbusperformance \ qdbusreply \ qdbusthreading \ -- cgit v1.2.3 From 70b5327e51481bf7b91d8fad50e3fc9ff3a1e888 Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Mon, 10 Aug 2009 12:13:02 +0200 Subject: QtWebKit compile fix for Windows CE There's no getenv on Windows CE. Reviewed-By: Simon Hausmann --- src/3rdparty/webkit/WebKit/qt/Api/qwebpage.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/3rdparty/webkit/WebKit/qt/Api/qwebpage.cpp b/src/3rdparty/webkit/WebKit/qt/Api/qwebpage.cpp index 1a45fe69c..613a72fd0 100644 --- a/src/3rdparty/webkit/WebKit/qt/Api/qwebpage.cpp +++ b/src/3rdparty/webkit/WebKit/qt/Api/qwebpage.cpp @@ -105,7 +105,7 @@ void QWEBKIT_EXPORT qt_drt_overwritePluginDirectories() PluginDatabase* db = PluginDatabase::installedPlugins(/* populate */ false); Vector paths; - String qtPath(getenv("QTWEBKIT_PLUGIN_PATH")); + String qtPath(qgetenv("QTWEBKIT_PLUGIN_PATH").data()); qtPath.split(UChar(':'), /* allowEmptyEntries */ false, paths); db->setPluginDirectories(paths); -- cgit v1.2.3 From 35ef002453cbe9841e23a7d33064a51dbe99fb06 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Mon, 10 Aug 2009 17:15:03 +0200 Subject: Manual merge --- src/gui/kernel/qapplication_win.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/gui/kernel/qapplication_win.cpp b/src/gui/kernel/qapplication_win.cpp index 5843c3446..bb910b70e 100644 --- a/src/gui/kernel/qapplication_win.cpp +++ b/src/gui/kernel/qapplication_win.cpp @@ -3728,7 +3728,7 @@ bool QETWidget::translateGestureEvent(const MSG &msg) memset(&gi, 0, sizeof(GESTUREINFO)); gi.cbSize = sizeof(GESTUREINFO); - QApplicationPrivate *qAppPriv = getQApplicationPrivateInternal(); + QApplicationPrivate *qAppPriv = QApplicationPrivate::instance(); #ifdef Q_WS_WINCE_WM #define GID_ZOOM 0xf000 #define GID_ROTATE 0xf001 @@ -3739,8 +3739,6 @@ bool QETWidget::translateGestureEvent(const MSG &msg) if (qAppPriv->GetGestureInfo) bResult = qAppPriv->GetGestureInfo((HANDLE)msg.lParam, &gi); - QApplicationPrivate *qAppPriv = QApplicationPrivate::instance(); - BOOL bResult = qAppPriv->GetGestureInfo((HANDLE)msg.lParam, &gi); if (bResult) { const QPoint widgetPos = QPoint(gi.ptsLocation.x, gi.ptsLocation.y); QWidget *alienWidget = !internalWinId() ? this : childAt(widgetPos); -- cgit v1.2.3 From 13a31fe82845f8b1f4d86919080d3b2a87c4d061 Mon Sep 17 00:00:00 2001 From: Jens Bache-Wiig Date: Mon, 10 Aug 2009 17:15:03 +0200 Subject: Introducing icon theme support Added some static functions to QIcon to support desktop themes based on the freedesktop spec. It is not intended to replace KIcon and the intention is to use it when available to share icon cache between applications. Applications currently using icon themes are Assistant, Designer and the textedit demo. Reviewed-by: ogoffart --- demos/textedit/textedit.cpp | 65 +- doc/src/snippets/code/src_gui_image_qicon.cpp | 9 + src/gui/gui.pro | 1 - src/gui/image/image.pri | 3 + src/gui/image/qicon.cpp | 226 ++++-- src/gui/image/qicon.h | 10 + src/gui/image/qicon_p.h | 138 ++++ src/gui/image/qiconloader.cpp | 599 ++++++++++++++++ src/gui/image/qiconloader_p.h | 185 +++++ src/gui/kernel/qapplication_x11.cpp | 4 +- src/gui/styles/gtksymbols.cpp | 8 +- src/gui/styles/gtksymbols_p.h | 1 + src/gui/styles/qcleanlooksstyle.cpp | 563 +-------------- src/gui/styles/qcleanlooksstyle_p.h | 2 - src/gui/styles/qcommonstyle.cpp | 770 ++++++--------------- src/gui/styles/qcommonstyle_p.h | 13 - src/gui/styles/qgtkstyle.cpp | 96 +-- src/gui/styles/qgtkstyle.h | 4 + .../testtheme/16x16/actions/appointment-new.png | Bin 0 -> 897 bytes .../testtheme/22x22/actions/appointment-new.png | Bin 0 -> 1411 bytes .../testtheme/32x32/actions/appointment-new.png | Bin 0 -> 2399 bytes tests/auto/qicon/icons/testtheme/index.theme | 492 +++++++++++++ .../icons/testtheme/scalable/actions/svg-only.svg | 425 ++++++++++++ .../themeparent/16x16/actions/address-book-new.png | Bin 0 -> 796 bytes .../themeparent/16x16/actions/appointment-new.png | Bin 0 -> 897 bytes .../themeparent/22x22/actions/address-book-new.png | Bin 0 -> 924 bytes .../themeparent/22x22/actions/appointment-new.png | Bin 0 -> 1411 bytes .../themeparent/32x32/actions/address-book-new.png | Bin 0 -> 1897 bytes .../themeparent/32x32/actions/appointment-new.png | Bin 0 -> 2399 bytes tests/auto/qicon/icons/themeparent/index.theme | 492 +++++++++++++ .../scalable/actions/address-book-new.svg | 389 +++++++++++ .../scalable/actions/appointment-new.svg | 425 ++++++++++++ tests/auto/qicon/tst_qicon.cpp | 67 ++ tools/assistant/compat/mainwindow.cpp | 10 + tools/assistant/tools/assistant/mainwindow.cpp | 13 + .../components/buddyeditor/buddyeditor_plugin.cpp | 5 +- .../components/formeditor/formwindowmanager.cpp | 22 +- .../signalsloteditor/signalsloteditor_plugin.cpp | 3 +- .../tabordereditor/tabordereditor_plugin.cpp | 4 +- tools/designer/src/designer/qdesigner_actions.cpp | 7 +- tools/designer/src/lib/shared/actioneditor.cpp | 18 +- tools/designer/src/lib/shared/qtresourceview.cpp | 10 +- 42 files changed, 3784 insertions(+), 1295 deletions(-) create mode 100644 src/gui/image/qicon_p.h create mode 100644 src/gui/image/qiconloader.cpp create mode 100644 src/gui/image/qiconloader_p.h create mode 100644 tests/auto/qicon/icons/testtheme/16x16/actions/appointment-new.png create mode 100644 tests/auto/qicon/icons/testtheme/22x22/actions/appointment-new.png create mode 100644 tests/auto/qicon/icons/testtheme/32x32/actions/appointment-new.png create mode 100644 tests/auto/qicon/icons/testtheme/index.theme create mode 100644 tests/auto/qicon/icons/testtheme/scalable/actions/svg-only.svg create mode 100644 tests/auto/qicon/icons/themeparent/16x16/actions/address-book-new.png create mode 100644 tests/auto/qicon/icons/themeparent/16x16/actions/appointment-new.png create mode 100644 tests/auto/qicon/icons/themeparent/22x22/actions/address-book-new.png create mode 100644 tests/auto/qicon/icons/themeparent/22x22/actions/appointment-new.png create mode 100644 tests/auto/qicon/icons/themeparent/32x32/actions/address-book-new.png create mode 100644 tests/auto/qicon/icons/themeparent/32x32/actions/appointment-new.png create mode 100644 tests/auto/qicon/icons/themeparent/index.theme create mode 100644 tests/auto/qicon/icons/themeparent/scalable/actions/address-book-new.svg create mode 100644 tests/auto/qicon/icons/themeparent/scalable/actions/appointment-new.svg diff --git a/demos/textedit/textedit.cpp b/demos/textedit/textedit.cpp index d1e12bbf5..31b419a72 100644 --- a/demos/textedit/textedit.cpp +++ b/demos/textedit/textedit.cpp @@ -158,14 +158,16 @@ void TextEdit::setupFileActions() QAction *a; - a = new QAction(QIcon(rsrcPath + "/filenew.png"), tr("&New"), this); + QIcon newIcon = QIcon::fromTheme("document-new", QIcon(rsrcPath + "/filenew.png")); + a = new QAction( newIcon, tr("&New"), this); a->setPriority(QAction::LowPriority); a->setShortcut(QKeySequence::New); connect(a, SIGNAL(triggered()), this, SLOT(fileNew())); tb->addAction(a); menu->addAction(a); - a = new QAction(QIcon(rsrcPath + "/fileopen.png"), tr("&Open..."), this); + a = new QAction(QIcon::fromTheme("document-open", QIcon(rsrcPath + "/fileopen.png")), + tr("&Open..."), this); a->setShortcut(QKeySequence::Open); connect(a, SIGNAL(triggered()), this, SLOT(fileOpen())); tb->addAction(a); @@ -173,7 +175,8 @@ void TextEdit::setupFileActions() menu->addSeparator(); - actionSave = a = new QAction(QIcon(rsrcPath + "/filesave.png"), tr("&Save"), this); + actionSave = a = new QAction(QIcon::fromTheme("document-save", QIcon(rsrcPath + "/filesave.png")), + tr("&Save"), this); a->setShortcut(QKeySequence::Save); connect(a, SIGNAL(triggered()), this, SLOT(fileSave())); a->setEnabled(false); @@ -187,17 +190,21 @@ void TextEdit::setupFileActions() menu->addSeparator(); #ifndef QT_NO_PRINTER - a = new QAction(QIcon(rsrcPath + "/fileprint.png"), tr("&Print..."), this); + a = new QAction(QIcon::fromTheme("document-print", QIcon(rsrcPath + "/fileprint.png")), + tr("&Print..."), this); + a->setPriority(QAction::LowPriority); a->setShortcut(QKeySequence::Print); connect(a, SIGNAL(triggered()), this, SLOT(filePrint())); tb->addAction(a); menu->addAction(a); - a = new QAction(QIcon(rsrcPath + "/fileprint.png"), tr("Print Preview..."), this); + a = new QAction(QIcon::fromTheme("fileprint", QIcon(rsrcPath + "/fileprint.png")), + tr("Print Preview..."), this); connect(a, SIGNAL(triggered()), this, SLOT(filePrintPreview())); menu->addAction(a); - a = new QAction(QIcon(rsrcPath + "/exportpdf.png"), tr("&Export PDF..."), this); + a = new QAction(QIcon::fromTheme("exportpdf", QIcon(rsrcPath + "/exportpdf.png")), + tr("&Export PDF..."), this); a->setPriority(QAction::LowPriority); a->setShortcut(Qt::CTRL + Qt::Key_D); connect(a, SIGNAL(triggered()), this, SLOT(filePrintPdf())); @@ -218,32 +225,36 @@ void TextEdit::setupEditActions() QToolBar *tb = new QToolBar(this); tb->setWindowTitle(tr("Edit Actions")); addToolBar(tb); - QMenu *menu = new QMenu(tr("&Edit"), this); menuBar()->addMenu(menu); QAction *a; - a = actionUndo = new QAction(QIcon(rsrcPath + "/editundo.png"), tr("&Undo"), this); + a = actionUndo = new QAction(QIcon::fromTheme("edit-undo", QIcon(rsrcPath + "/editundo.png")), + tr("&Undo"), this); a->setShortcut(QKeySequence::Undo); tb->addAction(a); menu->addAction(a); - a = actionRedo = new QAction(QIcon(rsrcPath + "/editredo.png"), tr("&Redo"), this); + a = actionRedo = new QAction(QIcon::fromTheme("edit-redo", QIcon(rsrcPath + "/editredo.png")), + tr("&Redo"), this); a->setPriority(QAction::LowPriority); a->setShortcut(QKeySequence::Redo); tb->addAction(a); menu->addAction(a); menu->addSeparator(); - a = actionCut = new QAction(QIcon(rsrcPath + "/editcut.png"), tr("Cu&t"), this); + a = actionCut = new QAction(QIcon::fromTheme("edit-cut", QIcon(rsrcPath + "/editcut.png")), + tr("Cu&t"), this); a->setPriority(QAction::LowPriority); a->setShortcut(QKeySequence::Cut); tb->addAction(a); menu->addAction(a); - a = actionCopy = new QAction(QIcon(rsrcPath + "/editcopy.png"), tr("&Copy"), this); + a = actionCopy = new QAction(QIcon::fromTheme("edit-copy", QIcon(rsrcPath + "/editcopy.png")), + tr("&Copy"), this); a->setPriority(QAction::LowPriority); a->setShortcut(QKeySequence::Copy); tb->addAction(a); menu->addAction(a); - a = actionPaste = new QAction(QIcon(rsrcPath + "/editpaste.png"), tr("&Paste"), this); + a = actionPaste = new QAction(QIcon::fromTheme("edit-paste", QIcon(rsrcPath + "/editpaste.png")), + tr("&Paste"), this); a->setPriority(QAction::LowPriority); a->setShortcut(QKeySequence::Paste); tb->addAction(a); @@ -260,10 +271,11 @@ void TextEdit::setupTextActions() QMenu *menu = new QMenu(tr("F&ormat"), this); menuBar()->addMenu(menu); - actionTextBold = new QAction(QIcon(rsrcPath + "/textbold.png"), tr("&Bold"), this); - actionTextBold->setPriority(QAction::LowPriority); + actionTextBold = new QAction(QIcon::fromTheme("format-text-bold", QIcon(rsrcPath + "/textbold.png")), + tr("&Bold"), this); actionTextBold->setShortcut(Qt::CTRL + Qt::Key_B); - QFont bold; + actionTextBold->setPriority(QAction::LowPriority); + QFont bold; bold.setBold(true); actionTextBold->setFont(bold); connect(actionTextBold, SIGNAL(triggered()), this, SLOT(textBold())); @@ -271,7 +283,8 @@ void TextEdit::setupTextActions() menu->addAction(actionTextBold); actionTextBold->setCheckable(true); - actionTextItalic = new QAction(QIcon(rsrcPath + "/textitalic.png"), tr("&Italic"), this); + actionTextItalic = new QAction(QIcon::fromTheme("format-text-italic", QIcon(rsrcPath + "/textitalic.png")), + tr("&Italic"), this); actionTextItalic->setPriority(QAction::LowPriority); actionTextItalic->setShortcut(Qt::CTRL + Qt::Key_I); QFont italic; @@ -282,9 +295,10 @@ void TextEdit::setupTextActions() menu->addAction(actionTextItalic); actionTextItalic->setCheckable(true); - actionTextUnderline = new QAction(QIcon(rsrcPath + "/textunder.png"), tr("&Underline"), this); - actionTextUnderline->setPriority(QAction::LowPriority); + actionTextUnderline = new QAction(QIcon::fromTheme("format-text-underline", QIcon(rsrcPath + "/textunder.png")), + tr("&Underline"), this); actionTextUnderline->setShortcut(Qt::CTRL + Qt::Key_U); + actionTextUnderline->setPriority(QAction::LowPriority); QFont underline; underline.setUnderline(true); actionTextUnderline->setFont(underline); @@ -300,15 +314,16 @@ void TextEdit::setupTextActions() // Make sure the alignLeft is always left of the alignRight if (QApplication::isLeftToRight()) { - actionAlignLeft = new QAction(QIcon(rsrcPath + "/textleft.png"), tr("&Left"), grp); - actionAlignCenter = new QAction(QIcon(rsrcPath + "/textcenter.png"), tr("C&enter"), grp); - actionAlignRight = new QAction(QIcon(rsrcPath + "/textright.png"), tr("&Right"), grp); + actionAlignLeft = new QAction(QIcon::fromTheme("format-justify-left", QIcon(rsrcPath + "/textleft.png")), + tr("&Left"), grp); + actionAlignCenter = new QAction(QIcon::fromTheme("format-justify-center", QIcon(rsrcPath + "/textcenter.png")), tr("C&enter"), grp); + actionAlignRight = new QAction(QIcon::fromTheme("format-justify-right", QIcon(rsrcPath + "/textright.png")), tr("&Right"), grp); } else { - actionAlignRight = new QAction(QIcon(rsrcPath + "/textright.png"), tr("&Right"), grp); - actionAlignCenter = new QAction(QIcon(rsrcPath + "/textcenter.png"), tr("C&enter"), grp); - actionAlignLeft = new QAction(QIcon(rsrcPath + "/textleft.png"), tr("&Left"), grp); + actionAlignRight = new QAction(QIcon::fromTheme("format-justify-right", QIcon(rsrcPath + "/textright.png")), tr("&Right"), grp); + actionAlignCenter = new QAction(QIcon::fromTheme("format-justify-center", QIcon(rsrcPath + "/textcenter.png")), tr("C&enter"), grp); + actionAlignLeft = new QAction(QIcon::fromTheme("format-justify-left", QIcon(rsrcPath + "/textleft.png")), tr("&Left"), grp); } - actionAlignJustify = new QAction(QIcon(rsrcPath + "/textjustify.png"), tr("&Justify"), grp); + actionAlignJustify = new QAction(QIcon::fromTheme("format-justify-fill", QIcon(rsrcPath + "/textjustify.png")), tr("&Justify"), grp); actionAlignLeft->setShortcut(Qt::CTRL + Qt::Key_L); actionAlignLeft->setCheckable(true); diff --git a/doc/src/snippets/code/src_gui_image_qicon.cpp b/doc/src/snippets/code/src_gui_image_qicon.cpp index 2b7c89315..455fd843e 100644 --- a/doc/src/snippets/code/src_gui_image_qicon.cpp +++ b/doc/src/snippets/code/src_gui_image_qicon.cpp @@ -20,3 +20,12 @@ void MyWidget::drawIcon(QPainter *painter, QPoint pos) painter->drawPixmap(pos, pixmap); } //! [2] + +//! [3] + QIcon undoicon = QIcon::fromTheme("edit-undo"); +//! [3] + +//! [4] + QIcon undoicon = QIcon::fromTheme("edit-undo", QIcon(":/undo.png")); +//! [4] + diff --git a/src/gui/gui.pro b/src/gui/gui.pro index b77bfdc31..a49d680e7 100644 --- a/src/gui/gui.pro +++ b/src/gui/gui.pro @@ -46,4 +46,3 @@ contains(DEFINES,QT_EVAL):include($$QT_SOURCE_TREE/src/corelib/eval.pri) QMAKE_DYNAMIC_LIST_FILE = $$PWD/QtGui.dynlist DEFINES += Q_INTERNAL_QAPP_SRC - diff --git a/src/gui/image/image.pri b/src/gui/image/image.pri index b9c36dc01..baf212522 100644 --- a/src/gui/image/image.pri +++ b/src/gui/image/image.pri @@ -6,6 +6,8 @@ HEADERS += \ image/qbitmap.h \ image/qicon.h \ + image/qicon_p.h \ + image/qiconloader_p.h \ image/qiconengine.h \ image/qiconengineplugin.h \ image/qimage.h \ @@ -32,6 +34,7 @@ HEADERS += \ SOURCES += \ image/qbitmap.cpp \ image/qicon.cpp \ + image/qiconloader.cpp \ image/qimage.cpp \ image/qimageiohandler.cpp \ image/qimagereader.cpp \ diff --git a/src/gui/image/qicon.cpp b/src/gui/image/qicon.cpp index fa407c78a..7a435140e 100644 --- a/src/gui/image/qicon.cpp +++ b/src/gui/image/qicon.cpp @@ -40,9 +40,11 @@ ****************************************************************************/ #include "qicon.h" +#include "qicon_p.h" #include "qiconengine.h" #include "qiconengineplugin.h" #include "private/qfactoryloader_p.h" +#include "private/qiconloader_p.h" #include "qapplication.h" #include "qstyleoption.h" #include "qpainter.h" @@ -50,6 +52,7 @@ #include "qstyle.h" #include "qpixmapcache.h" #include "qvariant.h" +#include "qcache.h" #include "qdebug.h" #ifdef Q_WS_MAC @@ -57,6 +60,11 @@ #include #endif +#ifdef Q_WS_X11 +#include "private/qt_x11_p.h" +#include "private/qkde_p.h" +#endif + QT_BEGIN_NAMESPACE /*! @@ -94,73 +102,14 @@ QT_BEGIN_NAMESPACE static QBasicAtomicInt serialNumCounter = Q_BASIC_ATOMIC_INITIALIZER(1); -class QIconPrivate -{ -public: - QIconPrivate(): engine(0), ref(1), serialNum(serialNumCounter.fetchAndAddRelaxed(1)), detach_no(0), engine_version(2), v1RefCount(0) {} - - ~QIconPrivate() { - if (engine_version == 1) { - if (!v1RefCount->deref()) { - delete engine; - delete v1RefCount; - } - } else if (engine_version == 2) { - delete engine; - } - } - - QIconEngine *engine; - - QAtomicInt ref; - int serialNum; - int detach_no; - int engine_version; - - QAtomicInt *v1RefCount; -}; - - -struct QPixmapIconEngineEntry +QIconPrivate::QIconPrivate() + : engine(0), ref(1), + serialNum(serialNumCounter.fetchAndAddRelaxed(1)), + detach_no(0), + engine_version(2), + v1RefCount(0) { - QPixmapIconEngineEntry():mode(QIcon::Normal), state(QIcon::Off){} - QPixmapIconEngineEntry(const QPixmap &pm, QIcon::Mode m = QIcon::Normal, QIcon::State s = QIcon::Off) - :pixmap(pm), size(pm.size()), mode(m), state(s){} - QPixmapIconEngineEntry(const QString &file, const QSize &sz = QSize(), QIcon::Mode m = QIcon::Normal, QIcon::State s = QIcon::Off) - :fileName(file), size(sz), mode(m), state(s){} - QPixmap pixmap; - QString fileName; - QSize size; - QIcon::Mode mode; - QIcon::State state; - bool isNull() const {return (fileName.isEmpty() && pixmap.isNull()); } -}; - -class QPixmapIconEngine : public QIconEngineV2 { -public: - QPixmapIconEngine(); - QPixmapIconEngine(const QPixmapIconEngine &); - ~QPixmapIconEngine(); - void paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state); - QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state); - QPixmapIconEngineEntry *bestMatch(const QSize &size, QIcon::Mode mode, QIcon::State state, bool sizeOnly); - QSize actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state); - void addPixmap(const QPixmap &pixmap, QIcon::Mode mode, QIcon::State state); - void addFile(const QString &fileName, const QSize &size, QIcon::Mode mode, QIcon::State state); - - // v2 functions - QString key() const; - QIconEngineV2 *clone() const; - bool read(QDataStream &in); - bool write(QDataStream &out) const; - void virtual_hook(int id, void *data); - -private: - QPixmapIconEngineEntry *tryMatch(const QSize &size, QIcon::Mode mode, QIcon::State state); - QVector pixmaps; - - friend QDataStream &operator<<(QDataStream &s, const QIcon &icon); -}; +} QPixmapIconEngine::QPixmapIconEngine() { @@ -918,6 +867,146 @@ QList QIcon::availableSizes(Mode mode, State state) const return engine->availableSizes(mode, state); } +/*! + \since 4.6 + + Sets the search paths for icon themes. + \sa themeSearchPaths(), fromTheme() +*/ +void QIcon::setThemeSearchPaths(const QStringList &paths) +{ + QIconLoader::instance()->setThemeSearchPath(paths); +} + +/*! + \since 4.6 + + Returns the search paths for icon themes. + + The default value will depend on the platform: + + On X11, the search path will use the XDG_DATA_DIRS environment + variable if available. + + On Windows the search path defaults to [Application Directory]/icons + + On Mac the default search path will search in the + [Contents/Resources/icons] part of the application bundle. + + \sa setThemeSearchPaths(), fromName() +*/ +QStringList QIcon::themeSearchPaths() +{ + return QIconLoader::instance()->themeSearchPaths(); +} + +/*! + \since 4.6 + + Sets the current icon theme. + + The name should correspond to a directory name in the + current \ themeSearchPath() containing an index.theme + file describing it's contents.. + +*/ +void QIcon::setThemeName(const QString &path) +{ + QIconLoader::instance()->setThemeName(path); +} + +/*! + \since 4.6 + + Returns the name of the current icon theme. + + On X11, the current icon theme depends on your desktop + settings. On other platforms it is not set by default. + + \sa themeSearchPaths(), themeIcon(), fromTheme(), hasThemeIcon() +*/ +QString QIcon::themeName() +{ + return QIconLoader::instance()->themeName(); +} + +/*! + \since 4.6 + + Returns the QIcon corresponding to \a name in the current + icon theme. If no such icon is found in the current theme + \a fallback is return instead. + + To use an icon theme on Windows or Mac, you will need to + bundle a compliant theme with your application and make sure + it is located in your themeSarchPaths. + + The lastest version of the freedesktop icon specification and naming + spesification can be obtained here: + http://standards.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html + http://standards.freedesktop.org/icon-naming-spec/icon-naming-spec-latest.html + + To fetch an icon from the current icon theme: + + \snippet doc/src/snippets/code/src_gui_image_qicon.cpp 3 + + Or if you want to provide a guaranteed fallback for platforms that + do not support theme icons, you can use the second argument: + + \snippet doc/src/snippets/code/src_gui_image_qicon.cpp 4 + + \note By default, only X11 will support themed icons. In order to + use themed icons on Mac and Windows, you will have to bundle a + compliant theme in one of your themeSearchPaths() and set the + appropriate themeName(). + + \sa themeName(), themeSearchPaths() +*/ +QIcon QIcon::fromTheme(const QString &name, const QIcon &fallback) +{ + + static QCache iconCache; + + QIcon icon; + +#ifdef Q_WS_X11 + if (X11->desktopEnvironment == DE_KDE) { + icon = QKde::kdeIcon(name); + if (!icon.isNull()) + return icon; + } +#endif + + if (iconCache.contains(name)) { + icon = *iconCache.object(name); + } else { + QIcon *cachedIcon = new QIcon(new QIconLoaderEngine(name)); + iconCache.insert(name, cachedIcon); + icon = *cachedIcon; + } + + if (icon.availableSizes().isEmpty()) + return fallback; + + return icon; +} + +/*! + \since 4.6 + + Returns true if there is an icon available for a \a name in the current + icon theme, otherwise returns false. + + \sa themeSearchPaths(), fromTheme() +*/ +bool QIcon::hasThemeIcon(const QString &name) +{ + QIcon icon = fromTheme(name); + + return !icon.isNull(); +} + + /***************************************************************************** QIcon stream functions *****************************************************************************/ @@ -989,6 +1078,11 @@ QDataStream &operator>>(QDataStream &s, QIcon &icon) QIconEngineV2 *engine = new QPixmapIconEngine; icon.d->engine = engine; engine->read(s); + } else if (key == QLatin1String("QIconLoaderEngine")) { + icon.d = new QIconPrivate; + QIconEngineV2 *engine = new QIconLoaderEngine(); + icon.d->engine = engine; + engine->read(s); #if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) } else if (QIconEngineFactoryInterfaceV2 *factory = qobject_cast(loaderV2()->instance(key))) { if (QIconEngineV2 *engine= factory->create()) { diff --git a/src/gui/image/qicon.h b/src/gui/image/qicon.h index c318e14ff..2a717179b 100644 --- a/src/gui/image/qicon.h +++ b/src/gui/image/qicon.h @@ -97,6 +97,16 @@ public: QList availableSizes(Mode mode = Normal, State state = Off) const; + static QIcon fromTheme(const QString &name, const QIcon &fallback = QIcon()); + static bool hasThemeIcon(const QString &name); + + static QStringList themeSearchPaths(); + static void setThemeSearchPaths(const QStringList &searchpath); + + static QString themeName(); + static void setThemeName(const QString &path); + + #ifdef QT3_SUPPORT enum Size { Small, Large, Automatic = Small }; static QT3_SUPPORT void setPixmapSize(Size which, const QSize &size); diff --git a/src/gui/image/qicon_p.h b/src/gui/image/qicon_p.h new file mode 100644 index 000000000..ccac4c30f --- /dev/null +++ b/src/gui/image/qicon_p.h @@ -0,0 +1,138 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QICON_P_H +#define QICON_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QIconPrivate +{ +public: + QIconPrivate(); + + ~QIconPrivate() { + if (engine_version == 1) { + if (!v1RefCount->deref()) { + delete engine; + delete v1RefCount; + } + } else if (engine_version == 2) { + delete engine; + } + } + + QIconEngine *engine; + + QAtomicInt ref; + int serialNum; + int detach_no; + int engine_version; + + QAtomicInt *v1RefCount; +}; + + +struct QPixmapIconEngineEntry +{ + QPixmapIconEngineEntry():mode(QIcon::Normal), state(QIcon::Off){} + QPixmapIconEngineEntry(const QPixmap &pm, QIcon::Mode m = QIcon::Normal, QIcon::State s = QIcon::Off) + :pixmap(pm), size(pm.size()), mode(m), state(s){} + QPixmapIconEngineEntry(const QString &file, const QSize &sz = QSize(), QIcon::Mode m = QIcon::Normal, QIcon::State s = QIcon::Off) + :fileName(file), size(sz), mode(m), state(s){} + QPixmap pixmap; + QString fileName; + QSize size; + QIcon::Mode mode; + QIcon::State state; + bool isNull() const {return (fileName.isEmpty() && pixmap.isNull()); } +}; + + + +class QPixmapIconEngine : public QIconEngineV2 { +public: + QPixmapIconEngine(); + QPixmapIconEngine(const QPixmapIconEngine &); + ~QPixmapIconEngine(); + void paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state); + QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state); + QPixmapIconEngineEntry *bestMatch(const QSize &size, QIcon::Mode mode, QIcon::State state, bool sizeOnly); + QSize actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state); + void addPixmap(const QPixmap &pixmap, QIcon::Mode mode, QIcon::State state); + void addFile(const QString &fileName, const QSize &size, QIcon::Mode mode, QIcon::State state); + + // v2 functions + QString key() const; + QIconEngineV2 *clone() const; + bool read(QDataStream &in); + bool write(QDataStream &out) const; + void virtual_hook(int id, void *data); + +private: + QPixmapIconEngineEntry *tryMatch(const QSize &size, QIcon::Mode mode, QIcon::State state); + QVector pixmaps; + + friend QDataStream &operator<<(QDataStream &s, const QIcon &icon); + friend class QIconThemeEngine; +}; + +QT_END_NAMESPACE + +#endif // QICON_P_H diff --git a/src/gui/image/qiconloader.cpp b/src/gui/image/qiconloader.cpp new file mode 100644 index 000000000..6bf8d3b35 --- /dev/null +++ b/src/gui/image/qiconloader.cpp @@ -0,0 +1,599 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef Q_WS_MAC +#include +#endif + +#ifdef Q_WS_X11 +#include +#include +#endif + +QT_BEGIN_NAMESPACE + +Q_GLOBAL_STATIC(QIconLoader, iconLoaderInstance) + +static QString systemThemeName() +{ + QString result; +#ifdef Q_WS_X11 + if (X11->desktopEnvironment == DE_GNOME) { + result = QGtk::getGConfString(QLatin1String("/desktop/gnome/interface/icon_theme"), + QLatin1String("gnome")); + } else if (X11->desktopEnvironment == DE_KDE) { + QString kdeDefault = X11->desktopVersion >= 4 ? + QString::fromLatin1("oxygen") : + QString::fromLatin1("crystalsvg"); + + QSettings settings(QKde::kdeHome() + + QLatin1String("/share/config/kdeglobals"), + QSettings::IniFormat); + + settings.beginGroup(QLatin1String("Icons")); + + result = settings.value(QLatin1String("Theme"), kdeDefault).toString(); + } +#endif + return result; +} + +static QString fallbackTheme() +{ + QString defaultTheme = systemThemeName(); + if (defaultTheme.isEmpty()) + defaultTheme = QLatin1String("hicolor"); + return defaultTheme; +} + +QIconLoader::QIconLoader() : + m_themeKey(1), m_supportsSvg(false) +{ + m_systemTheme = systemThemeName(); + + QFactoryLoader iconFactoryLoader(QIconEngineFactoryInterfaceV2_iid, + QLatin1String("/iconengines"), + Qt::CaseInsensitive); + if (iconFactoryLoader.keys().contains(QLatin1String("svg"))) + m_supportsSvg = true; +} + +QIconLoader *QIconLoader::instance() +{ + return iconLoaderInstance(); +} + +// Queries the system theme and invalidates existing +// icons if the theme has changed. +void QIconLoader::updateSystemTheme() +{ + // Only change if this is not explicitly set by the user + if (m_userTheme.isEmpty()) { + QString theme = systemThemeName(); + if (theme != m_systemTheme) { + m_systemTheme = theme; + invalidateKey(); + } + } +} + +void QIconLoader::setThemeName(const QString &themeName) +{ + m_userTheme = themeName; + invalidateKey(); +} + +void QIconLoader::setThemeSearchPath(const QStringList &searchPaths) +{ + m_iconDirs = searchPaths; + themeList.clear(); + invalidateKey(); +} + +QStringList QIconLoader::themeSearchPaths() const +{ + if (m_iconDirs.isEmpty()) { + +#if defined(Q_WS_X11) + + QString xdgDirString = QFile::decodeName(getenv("XDG_DATA_DIRS")); + if (xdgDirString.isEmpty()) + xdgDirString = QLatin1String("/usr/local/share/:/usr/share/"); + + QStringList xdgDirs = xdgDirString.split(QLatin1Char(':')); + + for (int i = 0 ; i < xdgDirs.size() ; ++i) { + QDir dir(xdgDirs[i]); + if (dir.exists()) + m_iconDirs.append(dir.path() + + QLatin1String("/icons")); + } + + if (X11->desktopEnvironment == DE_KDE) { + + m_iconDirs << QLatin1Char(':') + + QKde::kdeHome() + + QLatin1String("/share/icons"); + QStringList kdeDirs = + QFile::decodeName(getenv("KDEDIRS")).split(QLatin1Char(':')); + + for (int i = 0 ; i< kdeDirs.count() ; ++i) { + QDir dir(QLatin1Char(':') + kdeDirs.at(i) + + QLatin1String("/share/icons")); + if (dir.exists()) + m_iconDirs.append(dir.path()); + } + } + + // Add home directory first in search path + QDir homeDir(QDir::homePath() + QLatin1String("/.icons")); + if (homeDir.exists()) + m_iconDirs.prepend(homeDir.path()); + +#elif defined(Q_WS_WIN) + m_iconDirs.append(qApp->applicationDirPath() + + QLatin1String("/icons")); +#elif defined(Q_WS_MAC) + m_iconDirs.append(qApp->applicationDirPath() + + QLatin1String("/../Resources/icons")); +#endif + } + return m_iconDirs; +} + +QIconTheme::QIconTheme(const QString &themeName) + : m_valid(false) +{ + QFile themeIndex; + + QList keyList; + QStringList iconDirs = QIcon::themeSearchPaths(); + for ( int i = 0 ; i < iconDirs.size() ; ++i) { + QDir iconDir(iconDirs[i]); + QString themeDir = iconDir.path() + QLatin1Char('/') + themeName; + themeIndex.setFileName(themeDir + QLatin1String("/index.theme")); + if (themeIndex.exists()) { + m_contentDir = themeDir; + m_valid = true; + break; + } + } + + if (themeIndex.exists()) { + const QSettings indexReader(themeIndex.fileName(), QSettings::IniFormat); + QStringListIterator keyIterator(indexReader.allKeys()); + while (keyIterator.hasNext()) { + + const QString key = keyIterator.next(); + if (key.endsWith(QLatin1String("/Size"))) { + // Note the QSettings ini-format does not accept + // slashes in key names, hence we have to cheat + if (int size = indexReader.value(key).toInt()) { + QString directoryKey = key.left(key.size() - 5); + QIconDirInfo dirInfo(directoryKey); + dirInfo.size = size; + QString type = indexReader.value(directoryKey + + QLatin1String("/Type") + ).toString(); + + if (type == QLatin1String("Fixed")) + dirInfo.type = QIconDirInfo::Fixed; + else if (type == QLatin1String("Scalable")) + dirInfo.type = QIconDirInfo::Scalable; + else + dirInfo.type = QIconDirInfo::Threshold; + + dirInfo.threshold = indexReader.value(directoryKey + + QLatin1String("/Threshold"), + 2).toInt(); + + dirInfo.minSize = indexReader.value(directoryKey + + QLatin1String("/MinSize"), + size).toInt(); + + dirInfo.maxSize = indexReader.value(directoryKey + + QLatin1String("/MaxSize"), + size).toInt(); + m_keyList.append(dirInfo); + } + } + } + + // Parent themes provide fallbacks for missing icons + m_parents = indexReader.value( + QLatin1String("Icon Theme/Inherits")).toStringList(); + + // Ensure a default platform fallback for all themes + if (m_parents.isEmpty()) + m_parents.append(fallbackTheme()); + + // Ensure that all themes fall back to hicolor + if (!m_parents.isEmpty()) + m_parents.append(QLatin1String("hicolor")); + } +} + +QThemeIconEntries QIconLoader::findIconHelper(const QString &themeName, + const QString &iconName, + QStringList &visited) const +{ + QThemeIconEntries entries; + Q_ASSERT(!themeName.isEmpty()); + + QPixmap pixmap; + + // Used to protect against potential recursions + visited << themeName; + + QIconTheme theme = themeList.value(themeName); + if (!theme.isValid()) { + theme = QIconTheme(themeName); + if (!theme.isValid()) + theme = fallbackTheme(); + + themeList.insert(themeName, theme); + } + + QString contentDir = theme.contentDir() + QLatin1Char('/'); + QList subDirs = theme.keyList(); + + const QString svgext(QLatin1String(".svg")); + const QString pngext(QLatin1String(".png")); + + // Add all relevant files + for (int i = 0; i < subDirs.size() ; ++i) { + const QIconDirInfo &dirInfo = subDirs.at(i); + QString subdir = dirInfo.path; + QDir currentDir(contentDir + subdir); + + if (dirInfo.type == QIconDirInfo::Scalable && m_supportsSvg && + currentDir.exists(iconName + svgext)) { + ScalableEntry *iconEntry = new ScalableEntry; + iconEntry->dir = dirInfo; + iconEntry->filename = currentDir.filePath(iconName + svgext); + entries.append(iconEntry); + + } else if (currentDir.exists(iconName + pngext)) { + PixmapEntry *iconEntry = new PixmapEntry; + iconEntry->dir = dirInfo; + iconEntry->filename = currentDir.filePath(iconName + pngext); + // Notice we ensure that pixmap entries allways come before + // scalable to preserve search order afterwards + entries.prepend(iconEntry); + } + } + + if (entries.isEmpty()) { + const QStringList parents = theme.parents(); + // Search recursively through inherited themes + for (int i = 0 ; i < parents.size() ; ++i) { + + const QString parentTheme = parents.at(i).trimmed(); + + if (!visited.contains(parentTheme)) // guard against recursion + entries = findIconHelper(parentTheme, iconName, visited); + + if (!entries.isEmpty()) // success + break; + } + } + return entries; +} + +QThemeIconEntries QIconLoader::loadIcon(const QString &name) const +{ + if (!themeName().isEmpty()) { + QStringList visited; + return findIconHelper(themeName(), name, visited); + } + + return QThemeIconEntries(); +} + + +// -------- Icon Loader Engine -------- // + + +QIconLoaderEngine::QIconLoaderEngine(const QString& iconName) + : m_iconName(iconName), m_key(0) +{ +} + +QIconLoaderEngine::~QIconLoaderEngine() +{ + while (!m_entries.isEmpty()) + delete m_entries.takeLast(); + Q_ASSERT(m_entries.size() == 0); +} + +QIconLoaderEngine::QIconLoaderEngine(const QIconLoaderEngine &other) + : QIconEngineV2(other), + m_iconName(other.m_iconName), + m_key(0) +{ +} + +QIconEngineV2 *QIconLoaderEngine::clone() const +{ + return new QIconLoaderEngine(*this); +} + +bool QIconLoaderEngine::read(QDataStream &in) { + in >> m_iconName; + return true; +} + +bool QIconLoaderEngine::write(QDataStream &out) const +{ + out << m_iconName; + return true; +} + +bool QIconLoaderEngine::hasIcon() const +{ + return !(m_entries.isEmpty()); +} + +// Lazily load the icon +void QIconLoaderEngine::ensureLoaded() +{ + if (!(iconLoaderInstance()->themeKey() == m_key)) { + + while (!m_entries.isEmpty()) + delete m_entries.takeLast(); + + Q_ASSERT(m_entries.size() == 0); + m_entries = iconLoaderInstance()->loadIcon(m_iconName); + m_key = iconLoaderInstance()->themeKey(); + } +} + +void QIconLoaderEngine::paint(QPainter *painter, const QRect &rect, + QIcon::Mode mode, QIcon::State state) +{ + QSize pixmapSize = rect.size(); +#if defined(Q_WS_MAC) + pixmapSize *= qt_mac_get_scalefactor(); +#endif + painter->drawPixmap(rect, pixmap(pixmapSize, mode, state)); +} + +/* + * This algorithm is defined by the freedesktop spec: + * http://standards.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html + */ +static bool directoryMatchesSize(const QIconDirInfo &dir, int iconsize) +{ + if (dir.type == QIconDirInfo::Fixed) { + return dir.size == iconsize; + + } else if (dir.type == QIconDirInfo::Scalable) { + return dir.size <= dir.maxSize && + iconsize >= dir.minSize; + + } else if (dir.type == QIconDirInfo::Threshold) { + return iconsize >= dir.size - dir.threshold && + iconsize <= dir.size + dir.threshold; + } + + Q_ASSERT(1); // Not a valid value + return false; +} + +/* + * This algorithm is defined by the freedesktop spec: + * http://standards.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html + */ +static int directorySizeDistance(const QIconDirInfo &dir, int iconsize) +{ + if (dir.type == QIconDirInfo::Fixed) { + return qAbs(dir.size - iconsize); + + } else if (dir.type == QIconDirInfo::Scalable) { + if (iconsize < dir.minSize) + return dir.minSize - iconsize; + else if (iconsize > dir.maxSize) + return iconsize - dir.maxSize; + else + return 0; + + } else if (dir.type == QIconDirInfo::Threshold) { + if (iconsize < dir.size - dir.threshold) + return dir.minSize - iconsize; + else if (iconsize > dir.size + dir.threshold) + return iconsize - dir.maxSize; + else return 0; + } + + Q_ASSERT(1); // Not a valid value + return INT_MAX; +} + +QIconLoaderEngineEntry *QIconLoaderEngine::entryForSize(const QSize &size) +{ + int iconsize = qMin(size.width(), size.height()); + + // Note that m_entries are sorted so that png-files + // come first + + // Search for exact matches first + for (int i = 0; i < m_entries.count(); ++i) { + QIconLoaderEngineEntry *entry = m_entries.at(i); + if (directoryMatchesSize(entry->dir, iconsize)) { + return entry; + } + } + + // Find the minimum distance icon + int minimalSize = INT_MAX; + QIconLoaderEngineEntry *closestMatch = 0; + for (int i = 0; i < m_entries.count(); ++i) { + QIconLoaderEngineEntry *entry = m_entries.at(i); + int distance = directorySizeDistance(entry->dir, iconsize); + if (distance < minimalSize) { + minimalSize = distance; + closestMatch = entry; + } + } + return closestMatch; +} + +/* + * Returns the actual icon size. For scalable svg's this is equivalent + * to the requested size. Otherwise the closest match is returned. + * + * todo: the spec is a bit fuzzy in this area, but we should probably + * allow scaling down pixmap icons as well. + * + */ +QSize QIconLoaderEngine::actualSize(const QSize &size, QIcon::Mode mode, + QIcon::State state) +{ + ensureLoaded(); + + QIconLoaderEngineEntry *entry = entryForSize(size); + if (entry) { + const QIconDirInfo &dir = entry->dir; + if (dir.type == QIconDirInfo::Scalable) + return size; + else + return QSize(dir.size, dir.size); + } + return QIconEngineV2::actualSize(size, mode, state); +} + +QPixmap PixmapEntry::pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) +{ + Q_UNUSED(state); + + // Ensure that basePixmap is lazily initialized before generating the + // key, otherwise the cache key is not unique + if (basePixmap.isNull()) + basePixmap.load(filename); + + int actualSize = qMin(size.width(), size.height()); + QString key = QLatin1String("$qt_theme_") + + QString::number(basePixmap.cacheKey(), 16) + + QLatin1Char('_') + + QString::number(mode) + + QLatin1Char('_') + + QString::number(qApp->palette().cacheKey(), 16) + + QLatin1Char('_') + + QString::number(actualSize); + + QPixmap cachedPixmap; + if (QPixmapCache::find(key, &cachedPixmap)) { + return cachedPixmap; + } else { + QStyleOption opt(0); + opt.palette = qApp->palette(); + cachedPixmap = qApp->style()->generatedIconPixmap(mode, basePixmap, &opt); + QPixmapCache::insert(key, cachedPixmap); + } + return cachedPixmap; +} + +QPixmap ScalableEntry::pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) +{ + if (svgIcon.isNull()) + svgIcon = QIcon(filename); + + // Simply reuse svg icon engine + return svgIcon.pixmap(size, mode, state); +} + +QPixmap QIconLoaderEngine::pixmap(const QSize &size, QIcon::Mode mode, + QIcon::State state) +{ + ensureLoaded(); + + QIconLoaderEngineEntry *entry = entryForSize(size); + if (entry) + return entry->pixmap(size, mode, state); + + return QPixmap(); +} + +QString QIconLoaderEngine::key() const +{ + return QLatin1String("QIconLoaderEngine"); +} + +void QIconLoaderEngine::virtual_hook(int id, void *data) +{ + ensureLoaded(); + + switch (id) { + case QIconEngineV2::AvailableSizesHook: + { + QIconEngineV2::AvailableSizesArgument &arg + = *reinterpret_cast(data); + const QList directoryKey = iconLoaderInstance()->theme().keyList(); + arg.sizes.clear(); + + // Gets all sizes from the DirectoryInfo entries + for (int i = 0 ; i < m_entries.size() ; ++i) { + int size = m_entries.at(i)->dir.size; + arg.sizes.append(QSize(size, size)); + } + } + break; + default: + QIconEngineV2::virtual_hook(id, data); + } +} + +QT_END_NAMESPACE diff --git a/src/gui/image/qiconloader_p.h b/src/gui/image/qiconloader_p.h new file mode 100644 index 000000000..707107c6f --- /dev/null +++ b/src/gui/image/qiconloader_p.h @@ -0,0 +1,185 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDESKTOPICON_P_H +#define QDESKTOPICON_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QIconLoader; + +struct QIconDirInfo +{ + enum Type { Fixed, Scalable, Threshold }; + QIconDirInfo(const QString &_path = QString()) : + path(_path), + size(0), + maxSize(0), + minSize(0), + threshold(0), + type(Threshold) {} + QString path; + short size; + short maxSize; + short minSize; + short threshold; + Type type : 4; +}; + +class QIconLoaderEngineEntry + { +public: + virtual QPixmap pixmap(const QSize &size, + QIcon::Mode mode, + QIcon::State state) = 0; + QString filename; + QIconDirInfo dir; + static int count; +}; + +struct ScalableEntry : public QIconLoaderEngineEntry +{ + QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state); + QIcon svgIcon; +}; + +struct PixmapEntry : public QIconLoaderEngineEntry +{ + QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state); + QPixmap basePixmap; +}; + +typedef QList QThemeIconEntries; + +class QIconLoaderEngine : public QIconEngineV2 +{ +public: + QIconLoaderEngine(const QString& iconName = QString()); + ~QIconLoaderEngine(); + + void paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state); + QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state); + QSize actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state); + QIconEngineV2 *clone() const; + bool read(QDataStream &in); + bool write(QDataStream &out) const; + +private: + QString key() const; + bool hasIcon() const; + void ensureLoaded(); + void virtual_hook(int id, void *data); + QIconLoaderEngineEntry *entryForSize(const QSize &size); + QIconLoaderEngine(const QIconLoaderEngine &other); + QThemeIconEntries m_entries; + QString m_iconName; + uint m_key; + + friend class QIconLoader; +}; + +class QIconTheme +{ +public: + QIconTheme(const QString &name); + QIconTheme() : m_valid(false) {}; + QStringList parents() { return m_parents; } + QList keyList() { return m_keyList; } + QString contentDir() { return m_contentDir; } + bool isValid() { return m_valid; } + +private: + QString m_contentDir; + QList m_keyList; + QStringList m_parents; + bool m_valid; +}; + +class QIconLoader : public QObject +{ +public: + QIconLoader(); + QThemeIconEntries loadIcon(const QString &iconName) const; + uint themeKey() const { return m_themeKey; } + + QString themeName() const { return m_userTheme.isEmpty() ? m_systemTheme : m_userTheme; } + void setThemeName(const QString &themeName); + QIconTheme theme() { return themeList.value(themeName()); } + void setThemeSearchPath(const QStringList &searchPaths); + QStringList themeSearchPaths() const; + QIconDirInfo dirInfo(int dirindex); + static QIconLoader *instance(); + void updateSystemTheme(); + void invalidateKey() { m_themeKey++; } + +private: + QThemeIconEntries findIconHelper(const QString &themeName, + const QString &iconName, + QStringList &visited) const; + uint m_themeKey; + bool m_supportsSvg; + + mutable QString m_userTheme; + mutable QString m_systemTheme; + mutable QStringList m_iconDirs; + mutable QHash themeList; +}; + +QT_END_NAMESPACE + +#endif // QDESKTOPICON_P_H diff --git a/src/gui/kernel/qapplication_x11.cpp b/src/gui/kernel/qapplication_x11.cpp index 32e7e3c8a..221101a82 100644 --- a/src/gui/kernel/qapplication_x11.cpp +++ b/src/gui/kernel/qapplication_x11.cpp @@ -78,6 +78,7 @@ #include #include #include +#include #include "qstyle.h" #include "qmetaobject.h" #include "qtimer.h" @@ -1087,7 +1088,6 @@ static void qt_set_x11_resources(const char* font = 0, const char* fg = 0, if (QApplication::desktopSettingsAware()) { // first, read from settings QApplicationPrivate::x11_apply_settings(); - // the call to QApplication::style() below creates the system // palette, which breaks the logic after the RESOURCE_MANAGER // loop... so I have to save this value to be able to use it later @@ -1328,6 +1328,8 @@ static void qt_set_x11_resources(const char* font = 0, const char* fg = 0, QApplication::setEffectEnabled(Qt::UI_AnimateToolBox, effects.contains(QLatin1String("animatetoolbox"))); } + + QIconLoader::instance()->updateSystemTheme(); } diff --git a/src/gui/styles/gtksymbols.cpp b/src/gui/styles/gtksymbols.cpp index f947ac151..c8b4fda47 100644 --- a/src/gui/styles/gtksymbols.cpp +++ b/src/gui/styles/gtksymbols.cpp @@ -60,6 +60,7 @@ #include #include +#include #include #include @@ -341,9 +342,9 @@ static bool resolveGConf() typedef int (*x11ErrorHandler)(Display*, XErrorEvent*); -static QString getGConfString(const QString &value) +QString QGtk::getGConfString(const QString &value, const QString &fallback) { - QString retVal; + QString retVal = fallback; if (resolveGConf()) { g_type_init(); GConfClient* client = QGtk::gconf_client_get_default(); @@ -393,7 +394,7 @@ static QString getThemeName() // Fall back to gconf if (themeName.isEmpty() && resolveGConf()) - themeName = getGConfString(QLS("/desktop/gnome/interface/gtk_theme")); + themeName = QGtk::getGConfString(QLS("/desktop/gnome/interface/gtk_theme")); return themeName; } @@ -561,6 +562,7 @@ void QGtkStyleUpdateScheduler::updateTheme() QApplication::sendEvent(widget, &e); } } + QIconLoader::instance()->updateSystemTheme(); } static void add_widget(GtkWidget *widget) diff --git a/src/gui/styles/gtksymbols_p.h b/src/gui/styles/gtksymbols_p.h index 18c6dc55f..68e970a52 100644 --- a/src/gui/styles/gtksymbols_p.h +++ b/src/gui/styles/gtksymbols_p.h @@ -216,6 +216,7 @@ public: static QString openDirectory(QWidget *parent, const QString &caption, const QString &dir, QFileDialog::Options options); static QStringList openFilenames(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options); + static QString getGConfString(const QString &key, const QString &fallback = QString()); static Ptr_gtk_container_forall gtk_container_forall; static Ptr_gtk_init gtk_init; diff --git a/src/gui/styles/qcleanlooksstyle.cpp b/src/gui/styles/qcleanlooksstyle.cpp index 8f8878177..1782e3672 100644 --- a/src/gui/styles/qcleanlooksstyle.cpp +++ b/src/gui/styles/qcleanlooksstyle.cpp @@ -462,26 +462,6 @@ static const char * const qt_cleanlooks_checkbox_checked[] = { " ", " "}; -#ifdef Q_WS_X11 -extern "C" { - struct GConfClient; - struct GError; - typedef void (*Ptr_g_type_init)(); - typedef GConfClient* (*Ptr_gconf_client_get_default)(); - typedef char* (*Ptr_gconf_client_get_string)(GConfClient*, const char*, GError **); - typedef void (*Ptr_g_object_unref)(void *); - typedef void (*Ptr_g_error_free)(GError *); - typedef void (*Ptr_g_free)(void*); -} - -static Ptr_g_type_init p_g_type_init = 0; -static Ptr_gconf_client_get_default p_gconf_client_get_default = 0; -static Ptr_gconf_client_get_string p_gconf_client_get_string = 0; -static Ptr_g_object_unref p_g_object_unref = 0; -static Ptr_g_error_free p_g_error_free = 0; -static Ptr_g_free p_g_free = 0; -#endif - static void qt_cleanlooks_draw_gradient(QPainter *painter, const QRect &rect, const QColor &gradientStart, const QColor &gradientStop, Direction direction = TopDown, QBrush bgBrush = QBrush()) { @@ -3848,17 +3828,6 @@ QSize QCleanlooksStyle::sizeFromContents(ContentsType type, const QStyleOption * void QCleanlooksStyle::polish(QApplication *app) { QWindowsStyle::polish(app); -#ifdef Q_WS_X11 - Q_D(QCleanlooksStyle); - - QString dataDirs = QLatin1String(getenv("XDG_DATA_DIRS")); - - if (dataDirs.isEmpty()) - dataDirs = QLatin1String("/usr/local/share/:/usr/share/"); - - dataDirs.prepend(QDir::homePath() + QLatin1String("/:")); - d->iconDirs = dataDirs.split(QLatin1Char(':')); -#endif } /*! @@ -4376,44 +4345,6 @@ QRect QCleanlooksStyle::subElementRect(SubElement sr, const QStyleOption *opt, c return r; } -void QCleanlooksStylePrivate::lookupIconTheme() const -{ -#ifdef Q_WS_X11 - - if (themeName.isEmpty()) { - //resolve glib and gconf functions - p_g_type_init = (Ptr_g_type_init)QLibrary::resolve(QLatin1String("gobject-2.0"), 0, "g_type_init"); - p_gconf_client_get_default = (Ptr_gconf_client_get_default)QLibrary::resolve(QLatin1String("gconf-2"), 4, "gconf_client_get_default"); - p_gconf_client_get_string = (Ptr_gconf_client_get_string)QLibrary::resolve(QLatin1String("gconf-2"), 4, "gconf_client_get_string"); - p_g_object_unref = (Ptr_g_object_unref)QLibrary::resolve(QLatin1String("gobject-2.0"), 0, "g_object_unref"); - p_g_error_free = (Ptr_g_error_free)QLibrary::resolve(QLatin1String("glib-2.0"), 0, "g_error_free"); - p_g_free = (Ptr_g_free)QLibrary::resolve(QLatin1String("glib-2.0"), 0, "g_free"); - - if (p_g_type_init && - p_gconf_client_get_default && - p_gconf_client_get_string && - p_g_object_unref && - p_g_error_free && - p_g_free) { - - p_g_type_init(); - GConfClient* client = p_gconf_client_get_default(); - GError *err = 0; - char *str = p_gconf_client_get_string(client, "/desktop/gnome/interface/icon_theme", &err); - if (!err) { - themeName = QString::fromUtf8(str); - p_g_free(str); - } - p_g_object_unref(client); - if (err) - p_g_error_free (err); - } - if (themeName.isEmpty()) - themeName = QLatin1String("gnome"); - } -#endif -} - /*! \internal */ @@ -4421,165 +4352,6 @@ QIcon QCleanlooksStyle::standardIconImplementation(StandardPixmap standardIcon, const QStyleOption *option, const QWidget *widget) const { -#ifdef Q_WS_X11 - Q_D(const QCleanlooksStyle); - if (!QApplication::desktopSettingsAware()) - return QWindowsStyle::standardIconImplementation(standardIcon, option, widget); - QIcon icon; - QPixmap pixmap; - QPixmap link; - d->lookupIconTheme(); - switch (standardIcon) { - case SP_DirIcon: { - icon = QIcon(proxy()->standardPixmap(standardIcon, option, widget)); - icon.addPixmap(proxy()->standardPixmap(SP_DirClosedIcon, option, widget), - QIcon::Normal, QIcon::Off); - pixmap = d->findIcon(16, QLatin1String("gnome-fs-directory.png")); - if (!pixmap.isNull()) - icon.addPixmap(pixmap, QIcon::Normal, QIcon::Off); - pixmap = d->findIcon(48, QLatin1String("gnome-fs-directory.png")); - if (!pixmap.isNull()) - icon.addPixmap(pixmap, QIcon::Normal, QIcon::Off); - pixmap = d->findIcon(16, QLatin1String("gnome-fs-directory-accept.png")); - if (!pixmap.isNull()) - icon.addPixmap(pixmap, QIcon::Normal, QIcon::On); - pixmap = d->findIcon(16, QLatin1String("gnome-fs-directory-accept.png")); - if (!pixmap.isNull()) - icon.addPixmap(pixmap, QIcon::Normal, QIcon::On); - } - break; - case SP_DirLinkIcon: - { - icon = QIcon(proxy()->standardPixmap(standardIcon, option, widget)); - QPixmap link = d->findIcon(12, QLatin1String("emblem-symbolic-link.png")); - if (!link.isNull()) { - icon.addPixmap(proxy()->standardPixmap(SP_DirLinkIcon, option, widget)); - pixmap = d->findIcon(16, QLatin1String("gnome-fs-directory.png")); - if (!pixmap.isNull()) { - QPainter painter(&pixmap); - painter.drawPixmap(8, 8, 8, 8, link); - painter.end(); - icon.addPixmap(pixmap); - } - } - break; - } - case SP_FileIcon: - { - icon = d->createIcon(QLatin1String("unknown.png")); - if (icon.isNull()) - icon = d->createIcon(QLatin1String("gnome-fs-regular.png")); - if (icon.isNull()) - icon = d->createIcon(QLatin1String("stock_new.png")); - break; - } - case SP_DialogCloseButton: - { - icon = d->createIcon(QLatin1String("gtk-close.png")); - if (icon.isNull()) - icon = d->createIcon(QLatin1String("stock-close.png")); - break; - } - case SP_DirHomeIcon: - { - icon = d->createIcon(QLatin1String("folder_home.png")); - if (icon.isNull()) - icon = d->createIcon(QLatin1String("gnome_home.png")); - break; - } - case SP_DriveFDIcon: - { - icon = d->createIcon(QLatin1String("gnome-dev-floppy.png")); - break; - } - case SP_ComputerIcon: - { - icon = d->createIcon(QLatin1String("gnome-fs-client.png")); - break; - } - case SP_DesktopIcon: - { - icon = d->createIcon(QLatin1String("gnome-fs-desktop.png")); - break; - } - case SP_TrashIcon: - { - icon = d->createIcon(QLatin1String("gnome-fs-trash-empty.png")); - break; - } - case SP_DriveCDIcon: - case SP_DriveDVDIcon: - { - icon = d->createIcon(QLatin1String("gnome-dev-cdrom.png")); - break; - } - case SP_DriveHDIcon: - { - icon = d->createIcon(QLatin1String("gnome-dev-harddisk.png")); - break; - } - case SP_ArrowUp: - { - icon = d->createIcon(QLatin1String("stock_up.png")); - break; - } - case SP_ArrowDown: - { - icon = d->createIcon(QLatin1String("stock_down.png")); - break; - } - case SP_ArrowRight: - { - icon = d->createIcon(QLatin1String("stock_right.png")); - break; - } - case SP_ArrowLeft: - { - icon = d->createIcon(QLatin1String("stock_left.png")); - break; - } - case SP_BrowserReload: - { - icon = d->createIcon(QLatin1String("view-refresh.png")); - break; - } - case SP_BrowserStop: - { - pixmap = d->findIcon(24, QLatin1String("stop.png")); - break; - } - case SP_FileLinkIcon: - { - icon = QIcon(proxy()->standardPixmap(standardIcon, option, widget)); - QPixmap link = d->findIcon(12, QLatin1String("emblem-symbolic-link.png")); - if (!link.isNull()) { - icon.addPixmap(proxy()->standardPixmap(SP_FileLinkIcon,option, widget)); - pixmap = d->findIcon(16, QLatin1String("unknown.png")); - if (pixmap.isNull()) - pixmap = d->findIcon(16, QLatin1String("stock_new.png")); - if (!pixmap.isNull()) { - QPainter painter(&pixmap); - painter.drawPixmap(8, 8, 8, 8, link); - painter.end(); - icon.addPixmap(pixmap); - } - } - break; - } - case SP_ArrowForward: - if (QApplication::layoutDirection() == Qt::RightToLeft) - return standardIconImplementation(SP_ArrowLeft, option, widget); - return standardIconImplementation(SP_ArrowRight, option, widget); - case SP_ArrowBack: - if (QApplication::layoutDirection() == Qt::RightToLeft) - return standardIconImplementation(SP_ArrowRight, option, widget); - return standardIconImplementation(SP_ArrowLeft, option, widget); - default: - icon = QIcon(proxy()->standardPixmap(standardIcon, option, widget)); - } - if (!icon.isNull()) - return icon; -#endif // Q_WS_X11 return QWindowsStyle::standardIconImplementation(standardIcon, option, widget); } @@ -4589,341 +4361,10 @@ QIcon QCleanlooksStyle::standardIconImplementation(StandardPixmap standardIcon, QPixmap QCleanlooksStyle::standardPixmap(StandardPixmap standardPixmap, const QStyleOption *opt, const QWidget *widget) const { -#ifdef Q_WS_X11 - Q_D(const QCleanlooksStyle); QPixmap pixmap; - if (!QApplication::desktopSettingsAware()) - return QWindowsStyle::standardPixmap(standardPixmap, opt, widget); - d->lookupIconTheme(); + #ifndef QT_NO_IMAGEFORMAT_XPM switch (standardPixmap) { - case SP_MessageBoxInformation: - { - pixmap = d->findIcon(48, QLatin1String("dialog-info.png")); - if (pixmap.isNull()) - pixmap = d->findIcon(48, QLatin1String("stock_dialog-info.png")); - if (!pixmap.isNull()) - return pixmap; - break; - } - case SP_MessageBoxWarning: - { - pixmap = d->findIcon(48, QLatin1String("dialog-warning.png")); - if (pixmap.isNull()) - pixmap = d->findIcon(48, QLatin1String("stock_dialog-warning.png")); - if (!pixmap.isNull()) - return pixmap; - break; - } - case SP_MessageBoxCritical: - { - pixmap = d->findIcon(48, QLatin1String("dialog-error.png")); - if (pixmap.isNull()) - pixmap = d->findIcon(48, QLatin1String("stock_dialog-error.png")); - if (!pixmap.isNull()) - return pixmap; - break; - } - case SP_MessageBoxQuestion: - { - pixmap = d->findIcon(48, QLatin1String("dialog-question.png")); - if (!pixmap.isNull()) - return pixmap; - break; - } - case SP_DirHomeIcon: - { - pixmap = d->findIcon(16, QLatin1String("folder_home.png")); - if (pixmap.isNull()) - pixmap = d->findIcon(16, QLatin1String("gnome_home.png")); - if (!pixmap.isNull()) - return pixmap; - break; - } - case SP_DialogOpenButton: - case SP_DirOpenIcon: - { - pixmap = d->findIcon(24, QLatin1String("stock_open.png")); - if (!pixmap.isNull()) - return pixmap; - break; - } - case SP_FileIcon: - { - pixmap = d->findIcon(24, QLatin1String("unknown.png")); - if (pixmap.isNull()) - pixmap = d->findIcon(24, QLatin1String("gnome-fs-regular.png")); - if (pixmap.isNull()) - pixmap = d->findIcon(24, QLatin1String("stock_new.png")); - if (!pixmap.isNull()) - return pixmap; - break; - } - case SP_FileLinkIcon: - { - pixmap = d->findIcon(24, QLatin1String("emblem-symbolic-link.png")); - if (!pixmap.isNull()) { - QPixmap fileIcon = d->findIcon(24, QLatin1String("unknown.png")); - if (fileIcon.isNull()) - fileIcon = d->findIcon(24, QLatin1String("stock_new.png")); - if (!fileIcon.isNull()) { - QPainter painter(&fileIcon); - painter.setRenderHint(QPainter::SmoothPixmapTransform); - painter.drawPixmap(12, 12, 12, 12, pixmap); - return fileIcon; - } - } - break; - } - case SP_DirClosedIcon: - case SP_DirIcon: - { - pixmap = d->findIcon(24, QLatin1String("gnome-fs-directory.png")); - if (!pixmap.isNull()) - return pixmap; - break; - } - case SP_DirLinkIcon: - { - pixmap = d->findIcon(24, QLatin1String("emblem-symbolic-link.png")); - if (!pixmap.isNull()) { - QPixmap dirIcon = d->findIcon(24, QLatin1String("gnome-fs-directory.png")); - if (!dirIcon.isNull()) { - QPainter painter(&dirIcon); - painter.setRenderHint(QPainter::SmoothPixmapTransform); - painter.drawPixmap(12, 12, 12, 12, pixmap); - return dirIcon; - } - } - break; - } - case SP_DriveFDIcon: - { - pixmap = d->findIcon(24, QLatin1String("gnome-dev-floppy.png")); - if (!pixmap.isNull()) - return pixmap; - break; - } - case SP_ComputerIcon: - { - pixmap = d->findIcon(24, QLatin1String("gnome-fs-client.png")); - if (!pixmap.isNull()) - return pixmap; - break; - } - case SP_DesktopIcon: - { - pixmap = d->findIcon(24, QLatin1String("gnome-fs-desktop.png")); - if (!pixmap.isNull()) - return pixmap; - break; - } - case SP_TrashIcon: - { - pixmap = d->findIcon(24, QLatin1String("gnome-fs-trash-empty.png")); - if (!pixmap.isNull()) - return pixmap; - break; - } - case SP_DriveCDIcon: - case SP_DriveDVDIcon: - { - pixmap = d->findIcon(24, QLatin1String("gnome-dev-cdrom.png")); - if (!pixmap.isNull()) - return pixmap; - break; - } - case SP_DriveHDIcon: - { - pixmap = d->findIcon(24, QLatin1String("gnome-dev-harddisk.png")); - if (!pixmap.isNull()) - return pixmap; - break; - } - case SP_FileDialogToParent: - { - pixmap = d->findIcon(16, QLatin1String("stock_up.png")); - if (!pixmap.isNull()) - return pixmap; - break; - } - case SP_FileDialogNewFolder: - { - pixmap = d->findIcon(16, QLatin1String("stock_new-dir.png")); - if (!pixmap.isNull()) - return pixmap; - break; - } - case SP_ArrowUp: - { - pixmap = d->findIcon(16, QLatin1String("stock_up.png")); - if (!pixmap.isNull()) - return pixmap; - break; - } - case SP_ArrowDown: - { - pixmap = d->findIcon(16, QLatin1String("stock_down.png")); - if (!pixmap.isNull()) - return pixmap; - break; - } - case SP_ArrowRight: - { - pixmap = d->findIcon(16, QLatin1String("stock_right.png")); - if (!pixmap.isNull()) - return pixmap; - break; - } - case SP_ArrowLeft: - { - pixmap = d->findIcon(16, QLatin1String("stock_left.png")); - if (!pixmap.isNull()) - return pixmap; - break; - } - case SP_DialogCloseButton: - { - pixmap = d->findIcon(24, QLatin1String("gtk-close.png")); - if (pixmap.isNull()) - pixmap = d->findIcon(24, QLatin1String("stock-close.png")); - if (!pixmap.isNull()) - return pixmap; - break; - } - case SP_DialogApplyButton: - { - pixmap = d->findIcon(24, QLatin1String("dialog-apply.png")); - if (pixmap.isNull()) - pixmap = d->findIcon(24, QLatin1String("stock-apply.png")); - if (!pixmap.isNull()) - return pixmap; - break; - } - case SP_DialogResetButton: - { - pixmap = d->findIcon(24, QLatin1String("gtk-clear.png")); - if (!pixmap.isNull()) - return pixmap; - break; - } - case SP_DialogHelpButton: - { - pixmap = d->findIcon(24, QLatin1String("gtk-help.png")); - if (!pixmap.isNull()) - return pixmap; - break; - } - case SP_DialogOkButton: - { - pixmap = d->findIcon(24, QLatin1String("dialog-ok.png")); - if (pixmap.isNull()) - pixmap = d->findIcon(24, QLatin1String("stock-ok.png")); - if (!pixmap.isNull()) - return pixmap; - break; - } - case SP_DialogCancelButton: - { - pixmap = d->findIcon(24, QLatin1String("dialog-cancel.png")); - if (pixmap.isNull()) - pixmap = d->findIcon(24, QLatin1String("stock-cancel.png")); - if (pixmap.isNull()) - pixmap = d->findIcon(24, QLatin1String("process-stop.png")); - if (!pixmap.isNull()) - return pixmap; - break; - } - case SP_DialogSaveButton: - { - pixmap = d->findIcon(24, QLatin1String("stock_save.png")); - if (!pixmap.isNull()) - return pixmap; - break; - } - case SP_BrowserStop: - { - pixmap = d->findIcon(16, QLatin1String("process-stop.png")); - if (!pixmap.isNull()) - return pixmap; - break; - } - case SP_BrowserReload: - { - pixmap = d->findIcon(16, QLatin1String("view-refresh.png")); - if (!pixmap.isNull()) - return pixmap; - break; - } - case SP_MediaPlay: - { - pixmap = d->findIcon(24, QLatin1String("media-playback-start.png")); - if (!pixmap.isNull()) - return pixmap; - break; - } - case SP_MediaPause: - { - pixmap = d->findIcon(24, QLatin1String("media-playback-pause.png")); - if (!pixmap.isNull()) - return pixmap; - break; - } - case SP_MediaStop: - { - pixmap = d->findIcon(24, QLatin1String("media-playback-stop.png")); - if (!pixmap.isNull()) - return pixmap; - break; - } - case SP_MediaVolume: - { - pixmap = d->findIcon(16, QLatin1String("audio-volume-medium.png")); - if (!pixmap.isNull()) - return pixmap; - break; - } - case SP_MediaVolumeMuted: - { - pixmap = d->findIcon(16, QLatin1String("audio-volume-muted.png")); - if (!pixmap.isNull()) - return pixmap; - break; - } - case SP_MediaSeekForward: - { - pixmap = d->findIcon(24, QLatin1String("media-seek-forward.png")); - if (!pixmap.isNull()) - return pixmap; - break; - } - case SP_MediaSeekBackward: - { - pixmap = d->findIcon(24, QLatin1String("media-seek-backward.png")); - if (!pixmap.isNull()) - return pixmap; - break; - } - case SP_MediaSkipForward: - { - pixmap = d->findIcon(24, QLatin1String("media-skip-forward.png")); - if (!pixmap.isNull()) - return pixmap; - break; - } - case SP_MediaSkipBackward: - { - pixmap = d->findIcon(24, QLatin1String("media-skip-backward.png")); - if (!pixmap.isNull()) - return pixmap; - break; - } - case SP_TitleBarMenuButton: - case SP_TitleBarShadeButton: - case SP_TitleBarUnshadeButton: - case SP_TitleBarMaxButton: - case SP_TitleBarContextHelpButton: - return QWindowsStyle::standardPixmap(standardPixmap, opt, widget); case SP_TitleBarNormalButton: return QPixmap((const char **)dock_widget_restore_xpm); case SP_TitleBarMinButton: @@ -4936,7 +4377,7 @@ QPixmap QCleanlooksStyle::standardPixmap(StandardPixmap standardPixmap, const QS break; } #endif //QT_NO_IMAGEFORMAT_XPM -#endif //Q_WS_X11 + return QWindowsStyle::standardPixmap(standardPixmap, opt, widget); } diff --git a/src/gui/styles/qcleanlooksstyle_p.h b/src/gui/styles/qcleanlooksstyle_p.h index a26d40db0..d325499df 100644 --- a/src/gui/styles/qcleanlooksstyle_p.h +++ b/src/gui/styles/qcleanlooksstyle_p.h @@ -71,8 +71,6 @@ public: ~QCleanlooksStylePrivate() { } - - void lookupIconTheme() const; }; QT_END_NAMESPACE diff --git a/src/gui/styles/qcommonstyle.cpp b/src/gui/styles/qcommonstyle.cpp index c7feb2507..387885600 100644 --- a/src/gui/styles/qcommonstyle.cpp +++ b/src/gui/styles/qcommonstyle.cpp @@ -840,176 +840,8 @@ static void drawArrow(const QStyle *style, const QStyleOptionToolButton *toolbut #endif // QT_NO_TOOLBUTTON - #ifdef Q_WS_X11 // These functions are used to parse the X11 freedesktop icon spec -void QCommonStylePrivate::lookupIconTheme() const -{ - if (!themeName.isEmpty()) - return; - - QString dataDirs = QString::fromLocal8Bit(getenv("XDG_DATA_DIRS")); - if (dataDirs.isEmpty()) - dataDirs = QLatin1String("/usr/local/share/:/usr/share/"); - dataDirs += QLatin1Char(':') + QKde::kdeHome() + QLatin1String("/share"); - dataDirs.prepend(QDir::homePath() + QLatin1String("/:")); - QStringList kdeDirs = QString::fromLocal8Bit(getenv("KDEDIRS")).split(QLatin1Char(':'), QString::SkipEmptyParts); - foreach (const QString &dirName, kdeDirs) - dataDirs.append(QLatin1Char(':') + dirName + QLatin1String("/share")); - iconDirs = dataDirs.split(QLatin1Char(':')); - - QFileInfo fileInfo(QLatin1String("/usr/share/icons/default.kde")); - QDir dir(fileInfo.canonicalFilePath()); - QString kdeDefault = (X11->desktopEnvironment != DE_KDE || X11->desktopVersion >= 4) - ? QString::fromLatin1("oxygen") : QString::fromLatin1("crystalsvg"); - QString defaultTheme = fileInfo.exists() ? dir.dirName() : kdeDefault; - QSettings settings(QKde::kdeHome() + - QLatin1String("/share/config/kdeglobals"), QSettings::IniFormat); - settings.beginGroup(QLatin1String("Icons")); - themeName = settings.value(QLatin1String("Theme"), defaultTheme).toString(); -} - -QIconTheme QCommonStylePrivate::parseIndexFile(const QString &themeName) const -{ - Q_Q(const QCommonStyle); - QIconTheme theme; - QFile themeIndex; - QStringList parents; - QHash dirList; - - for ( int i = 0 ; i < iconDirs.size() && !themeIndex.exists() ; ++i) { - QString contentDir = QLatin1String(iconDirs[i].startsWith(QDir::homePath()) ? - "/.icons/" : "/icons/"); - themeIndex.setFileName(iconDirs[i] + contentDir + - themeName + QLatin1String("/index.theme")); - } - - if (themeIndex.open(QIODevice::ReadOnly | QIODevice::Text)) { - - QTextStream in(&themeIndex); - - while (!in.atEnd()) { - - QString line = in.readLine(); - - if (line.startsWith(QLatin1String("Inherits="))) { - line = line.right(line.length() - 9); - parents = line.split(QLatin1Char(',')); - } - - if (line.startsWith(QLatin1Char('['))) { - line = line.trimmed(); - line.chop(1); - QString dirName = line.right(line.length() - 1); - if (!in.atEnd()) { - line = in.readLine(); - int size; - if (line.startsWith(QLatin1String("Size="))) { - size = line.right(line.length() - 5).toInt(); - if (size) - dirList.insertMulti(size, dirName); - } - } - } - } - } - - if (q->inherits("QPlastiqueStyle")) { - QFileInfo fileInfo(QLatin1String("/usr/share/icons/default.kde")); - QDir dir(fileInfo.canonicalFilePath()); - QString defaultKDETheme = dir.exists() ? dir.dirName() : QString::fromLatin1("crystalsvg"); - if (!parents.contains(defaultKDETheme) && themeName != defaultKDETheme) - parents.append(defaultKDETheme); - } else if (parents.isEmpty() && themeName != QLatin1String("hicolor")) { - parents.append(QLatin1String("hicolor")); - } - theme = QIconTheme(dirList, parents); - return theme; -} - -QPixmap QCommonStylePrivate::findIconHelper(int size, - const QString &themeName, - const QString &iconName, - QStringList &visited) const -{ - QPixmap pixmap; - - if (!themeName.isEmpty()) { - - visited << themeName; - QIconTheme theme = themeList.value(themeName); - - if (!theme.isValid()) { - theme = parseIndexFile(themeName); - themeList.insert(themeName, theme); - } - - if (!theme.isValid()) - return QPixmap(); - - QList subDirs = theme.dirList().values(size); - - for ( int i = 0 ; i < iconDirs.size() ; ++i) { - for ( int j = 0 ; j < subDirs.size() ; ++j) { - QString contentDir = (iconDirs[i].startsWith(QDir::homePath())) ? - QLatin1String("/.icons/") : QLatin1String("/icons/"); - QString fileName = iconDirs[i] + contentDir + themeName + QLatin1Char('/') + subDirs[j] + QLatin1Char('/') + iconName; - QFile file(fileName); - if (file.exists()) - pixmap.load(fileName); - if (!pixmap.isNull()) - break; - } - } - - if (pixmap.isNull()) { - QStringList parents = theme.parents(); - //search recursively through inherited themes - for (int i = 0 ; pixmap.isNull() && i < parents.size() ; ++i) { - QString parentTheme = parents[i].trimmed(); - if (!visited.contains(parentTheme)) //guard against endless recursion - pixmap = findIconHelper(size, parentTheme, iconName, visited); - } - } - } - return pixmap; -} - -/*! \internal - find a pixmap with the given size and name from the freedesktop theme. -*/ -QPixmap QCommonStylePrivate::findIcon(int size, const QString &name) const -{ - QIcon icon = QKde::kdeIcon(name); - if (!icon.isNull()) - return icon.pixmap(size); - - QPixmap pixmap; - QString pixmapName = QLatin1String("$qt") + name + QString::number(size); - - if (QPixmapCache::find(pixmapName, pixmap)) - return pixmap; - - if (!themeName.isEmpty()) { - QStringList visited; - pixmap = findIconHelper(size, themeName, name, visited); - } - QPixmapCache::insert(pixmapName, pixmap); - return pixmap; -} -/*! \internal - create an Icon from the freedesktop theme. - */ -QIcon QCommonStylePrivate::createIcon(const QString &name) const -{ - QIcon icon = QKde::kdeIcon(name); - if (icon.isNull()) { - icon.addPixmap(findIcon(16, name)); - icon.addPixmap(findIcon(24, name)); - icon.addPixmap(findIcon(32, name)); - } - return icon; -} /*!internal Checks if you are running KDE and looks up the toolbar @@ -4859,8 +4691,24 @@ int QCommonStyle::pixelMetric(PixelMetric m, const QStyleOption *opt, const QWid ret = int(QStyleHelper::dpiScaled(6.)); break; - case PM_TabBarIconSize: case PM_ToolBarIconSize: +#ifdef Q_WS_X11 + if (X11->desktopVersion >= 4) { + static int iconSize = 0; + if (!iconSize) { + QSettings settings(QKde::kdeHome() + + QLatin1String("/share/config/kdeglobals"), + QSettings::IniFormat); + settings.beginGroup(QLatin1String("ToolbarIcons")); + iconSize = settings.value(QLatin1String("Size"), QLatin1String("22")).toInt(); + } + ret = iconSize; + } else +#endif + ret = proxy()->pixelMetric(PM_SmallIconSize, opt, widget); + break; + + case PM_TabBarIconSize: case PM_ListViewIconSize: ret = proxy()->pixelMetric(PM_SmallIconSize, opt, widget); break; @@ -5371,293 +5219,161 @@ QPixmap QCommonStyle::standardPixmap(StandardPixmap sp, const QStyleOption *opti Q_UNUSED(widget); Q_UNUSED(sp); #else -#ifdef Q_WS_X11 - Q_D(const QCommonStyle); QPixmap pixmap; - if (QApplication::desktopSettingsAware()) { - d->lookupIconTheme(); + + if (QApplication::desktopSettingsAware() && !QIcon::themeName().isEmpty()) { switch (sp) { case SP_DirHomeIcon: - { - pixmap = d->findIcon(16, QLatin1String("folder_home.png")); - if (!pixmap.isNull()) - return pixmap; - break; - } + pixmap = QIcon::fromTheme(QLatin1String("user-home")).pixmap(16); + break; case SP_MessageBoxInformation: - { - pixmap = d->findIcon(32, QLatin1String("messagebox_info.png")); - if (!pixmap.isNull()) - return pixmap; - break; - } + pixmap = QIcon::fromTheme(QLatin1String("messagebox_info")).pixmap(16); + break; case SP_MessageBoxWarning: - { - pixmap = d->findIcon(32, QLatin1String("messagebox_warning.png")); - if (!pixmap.isNull()) - return pixmap; - break; - } + pixmap = QIcon::fromTheme(QLatin1String("messagebox_warning")).pixmap(16); + break; case SP_MessageBoxCritical: - { - pixmap = d->findIcon(32, QLatin1String("messagebox_critical.png")); - if (!pixmap.isNull()) - return pixmap; - break; - } + pixmap = QIcon::fromTheme(QLatin1String("messagebox_critical")).pixmap(16); + break; case SP_MessageBoxQuestion: - { - pixmap = d->findIcon(32, QLatin1String("help.png")); - if (!pixmap.isNull()) - return pixmap; - break; - } + pixmap = QIcon::fromTheme(QLatin1String("help")).pixmap(16); + break; case SP_DialogOpenButton: case SP_DirOpenIcon: - { - pixmap = d->findIcon(16, QLatin1String("folder-open.png")); - if (pixmap.isNull()) - pixmap = d->findIcon(16, QLatin1String("folder_open.png")); - if (!pixmap.isNull()) - return pixmap; - break; - } + pixmap = QIcon::fromTheme(QLatin1String("folder-open")).pixmap(16); + break; case SP_FileIcon: - { - pixmap = d->findIcon(16, QLatin1String("text-x-generic.png")); - if (pixmap.isNull()) - pixmap = d->findIcon(16, QLatin1String("empty.png")); - if (!pixmap.isNull()) - return pixmap; - break; - } - case SP_FileLinkIcon: - { - pixmap = d->findIcon(16, QLatin1String("link_overlay.png")); - if (!pixmap.isNull()) { - QPixmap fileIcon = d->findIcon(16, QLatin1String("text-x-generic.png")); - if (fileIcon.isNull()) - fileIcon = d->findIcon(16, QLatin1String("empty.png")); - if (!fileIcon.isNull()) { - QPainter painter(&fileIcon); - painter.drawPixmap(0, 0, 16, 16, pixmap); - return fileIcon; - } - } - break; - } + pixmap = QIcon::fromTheme(QLatin1String("text-x-generic"), + QIcon::fromTheme(QLatin1String("empty"))).pixmap(16); + break; case SP_DirClosedIcon: case SP_DirIcon: - { - pixmap = d->findIcon(16, QLatin1String("folder.png")); - if (!pixmap.isNull()) - return pixmap; + pixmap = QIcon::fromTheme(QLatin1String("folder")).pixmap(16); break; - } - case SP_DirLinkIcon: - { - pixmap = d->findIcon(16, QLatin1String("link_overlay.png")); - if (!pixmap.isNull()) { - QPixmap dirIcon = d->findIcon(16, QLatin1String("folder.png")); - if (!dirIcon.isNull()) { - QPainter painter(&dirIcon); - painter.drawPixmap(0, 0, 16, 16, pixmap); - return dirIcon; - } - } - break; - } case SP_DriveFDIcon: - { - pixmap = d->findIcon(16, QLatin1String("media-floppy.png")); - if (pixmap.isNull()) - pixmap = d->findIcon(16, QLatin1String("3floppy_unmount.png")); - if (!pixmap.isNull()) - return pixmap; + pixmap = QIcon::fromTheme(QLatin1String("media-floppy"), + QIcon::fromTheme(QLatin1String("3floppy_unmount"))).pixmap(16); break; - } case SP_ComputerIcon: - { - pixmap = d->findIcon(16, QLatin1String("computer.png")); - if (pixmap.isNull()) - pixmap = d->findIcon(16, QLatin1String("system.png")); - if (!pixmap.isNull()) - return pixmap; + pixmap = QIcon::fromTheme(QLatin1String("computer"), + QIcon::fromTheme(QLatin1String("system"))).pixmap(16); break; - } case SP_DesktopIcon: - { - pixmap = d->findIcon(16, QLatin1String("user-desktop.png")); - if (pixmap.isNull()) - pixmap = d->findIcon(16, QLatin1String("desktop.png")); - if (!pixmap.isNull()) - return pixmap; + pixmap = QIcon::fromTheme(QLatin1String("user-desktop"), + QIcon::fromTheme(QLatin1String("desktop"))).pixmap(16); break; - } case SP_TrashIcon: - { - pixmap = d->findIcon(16, QLatin1String("user-trash.png")); - if (pixmap.isNull()) - pixmap = d->findIcon(16, QLatin1String("trashcan_empty.png")); - if (!pixmap.isNull()) - return pixmap; + pixmap = QIcon::fromTheme(QLatin1String("user-trash"), + QIcon::fromTheme(QLatin1String("trashcan_empty"))).pixmap(16); break; - } case SP_DriveCDIcon: case SP_DriveDVDIcon: - { - pixmap = d->findIcon(16, QLatin1String("media-optical.png")); - if (pixmap.isNull()) - pixmap = d->findIcon(16, QLatin1String("cdrom_unmount.png")); - if (!pixmap.isNull()) - return pixmap; + pixmap = QIcon::fromTheme(QLatin1String("media-optical"), + QIcon::fromTheme(QLatin1String("cdrom_unmount"))).pixmap(16); break; - } case SP_DriveHDIcon: - { - pixmap = d->findIcon(16, QLatin1String("drive-harddisk.png")); - if (pixmap.isNull()) - pixmap = d->findIcon(16, QLatin1String("hdd_unmount.png")); - if (!pixmap.isNull()) - return pixmap; + pixmap = QIcon::fromTheme(QLatin1String("drive-harddisk"), + QIcon::fromTheme(QLatin1String("hdd_unmount"))).pixmap(16); break; - } case SP_FileDialogToParent: - { - pixmap = d->findIcon(32, QLatin1String("go-up.png")); - if (pixmap.isNull()) - pixmap = d->findIcon(32, QLatin1String("up.png")); - if (!pixmap.isNull()) - return pixmap; + pixmap = QIcon::fromTheme(QLatin1String("go-up"), + QIcon::fromTheme(QLatin1String("up"))).pixmap(16); break; - } case SP_FileDialogNewFolder: - { - pixmap = d->findIcon(16, QLatin1String("folder_new.png")); - if (!pixmap.isNull()) - return pixmap; + pixmap = QIcon::fromTheme(QLatin1String("folder_new")).pixmap(16); break; - } case SP_ArrowUp: - { - pixmap = d->findIcon(32, QLatin1String("go-up.png")); - if (pixmap.isNull()) - pixmap = d->findIcon(32, QLatin1String("up.png")); - if (!pixmap.isNull()) - return pixmap; + pixmap = QIcon::fromTheme(QLatin1String("go-up"), + QIcon::fromTheme(QLatin1String("up"))).pixmap(16); break; - } case SP_ArrowDown: - { - pixmap = d->findIcon(32, QLatin1String("go-down.png")); - if (pixmap.isNull()) - pixmap = d->findIcon(32, QLatin1String("down.png")); - if (!pixmap.isNull()) - return pixmap; + pixmap = QIcon::fromTheme(QLatin1String("go-down"), + QIcon::fromTheme(QLatin1String("down"))).pixmap(16); break; - } case SP_ArrowRight: - { - pixmap = d->findIcon(32, QLatin1String("go-next.png")); - if (pixmap.isNull()) - pixmap = d->findIcon(32, QLatin1String("forward.png")); - if (!pixmap.isNull()) - return pixmap; + pixmap = QIcon::fromTheme(QLatin1String("go-next"), + QIcon::fromTheme(QLatin1String("forward"))).pixmap(16); break; - } case SP_ArrowLeft: - { - pixmap = d->findIcon(32, QLatin1String("go-previous.png")); - if (pixmap.isNull()) - pixmap = d->findIcon(32, QLatin1String("back.png")); - if (!pixmap.isNull()) - return pixmap; + pixmap = QIcon::fromTheme(QLatin1String("go-previous"), + QIcon::fromTheme(QLatin1String("back"))).pixmap(16); break; - } case SP_FileDialogDetailedView: - { - pixmap = d->findIcon(16, QLatin1String("view_detailed.png")); - if (!pixmap.isNull()) - return pixmap; + pixmap = QIcon::fromTheme(QLatin1String("view_detailed")).pixmap(16); break; - } - case SP_FileDialogListView: - { - pixmap = d->findIcon(16, QLatin1String("view_icon.png")); - if (!pixmap.isNull()) - return pixmap; + pixmap = QIcon::fromTheme(QLatin1String("view_icon")).pixmap(16); break; - } case SP_BrowserReload: - { - pixmap = d->findIcon(32, QLatin1String("reload.png")); - if (!pixmap.isNull()) - return pixmap; + pixmap = QIcon::fromTheme(QLatin1String("reload")).pixmap(16); break; - } case SP_BrowserStop: - { - pixmap = d->findIcon(32, QLatin1String("stop.png")); - if (!pixmap.isNull()) - return pixmap; + pixmap = QIcon::fromTheme(QLatin1String("process-stop")).pixmap(16); break; - } case SP_MediaPlay: - { - pixmap = d->findIcon(16, QLatin1String("player_play.png")); - if (!pixmap.isNull()) - return pixmap; + pixmap = QIcon::fromTheme(QLatin1String("media-playback-start")).pixmap(16); break; - } case SP_MediaPause: - { - pixmap = d->findIcon(16, QLatin1String("player_pause.png")); - if (!pixmap.isNull()) - return pixmap; + pixmap = QIcon::fromTheme(QLatin1String("media-playback-pause")).pixmap(16); break; - } case SP_MediaStop: - { - pixmap = d->findIcon(16, QLatin1String("player_stop.png")); - if (!pixmap.isNull()) - return pixmap; + pixmap = QIcon::fromTheme(QLatin1String("media-playback-stop")).pixmap(16); break; - } case SP_MediaSeekForward: - { - pixmap = d->findIcon(16, QLatin1String("player_fwd.png")); - if (!pixmap.isNull()) - return pixmap; + pixmap = QIcon::fromTheme(QLatin1String("media-seek-forward")).pixmap(16); break; - } case SP_MediaSeekBackward: - { - pixmap = d->findIcon(16, QLatin1String("player_rew.png")); - if (!pixmap.isNull()) - return pixmap; + pixmap = QIcon::fromTheme(QLatin1String("media-seek-backward")).pixmap(16); break; - } case SP_MediaSkipForward: - { - pixmap = d->findIcon(16, QLatin1String("player_end.png")); - if (!pixmap.isNull()) - return pixmap; + pixmap = QIcon::fromTheme(QLatin1String("media-skip-backward")).pixmap(16); break; - } case SP_MediaSkipBackward: - { - pixmap = d->findIcon(16, QLatin1String("player_start.png")); - if (!pixmap.isNull()) - return pixmap; + pixmap = QIcon::fromTheme(QLatin1String("media-skip-backward")).pixmap(16); + break; + case SP_DialogResetButton: + pixmap = QIcon::fromTheme(QLatin1String("edit-clear")).pixmap(24); + break; + case SP_DialogHelpButton: + pixmap = QIcon::fromTheme(QLatin1String("help-contents")).pixmap(24); + break; + case SP_DialogCancelButton: + pixmap = QIcon::fromTheme(QLatin1String("process-stop")).pixmap(24); + break; + case SP_DialogSaveButton: + pixmap = QIcon::fromTheme(QLatin1String("document-save")).pixmap(24); break; + case SP_FileLinkIcon: + pixmap = QIcon::fromTheme(QLatin1String("emblem-symbolic-link")).pixmap(16); + if (!pixmap.isNull()) { + QPixmap fileIcon = QIcon::fromTheme(QLatin1String("text-x-generic")).pixmap(16); + if (fileIcon.isNull()) + fileIcon = QIcon::fromTheme(QLatin1String("empty")).pixmap(16); + if (!fileIcon.isNull()) { + QPainter painter(&fileIcon); + painter.drawPixmap(0, 0, 16, 16, pixmap); + return fileIcon; + } } - + break; + case SP_DirLinkIcon: + pixmap = QIcon::fromTheme(QLatin1String("emblem-symbolic-link")).pixmap(16); + if (!pixmap.isNull()) { + QPixmap dirIcon = QIcon::fromTheme(QLatin1String("folder")).pixmap(16); + if (!dirIcon.isNull()) { + QPainter painter(&dirIcon); + painter.drawPixmap(0, 0, 16, 16, pixmap); + return dirIcon; + } + } + break; default: break; } } -#endif //Q_WS_X11 + + if (!pixmap.isNull()) + return pixmap; #endif //QT_NO_IMAGEFORMAT_PNG switch (sp) { #ifndef QT_NO_IMAGEFORMAT_XPM @@ -5793,254 +5509,178 @@ QIcon QCommonStyle::standardIconImplementation(StandardPixmap standardIcon, cons const QWidget *widget) const { QIcon icon; - if (QApplication::desktopSettingsAware()) { -#ifdef Q_WS_X11 - Q_D(const QCommonStyle); - d->lookupIconTheme(); - QPixmap pixmap; + if (QApplication::desktopSettingsAware() && !QIcon::themeName().isEmpty()) { switch (standardIcon) { case SP_DirHomeIcon: - { - icon = d->createIcon(QLatin1String("folder_home.png")); + icon = QIcon::fromTheme(QLatin1String("user-home")); break; - } case SP_MessageBoxInformation: - { - icon = d->createIcon(QLatin1String("dialog-information.png")); - if (icon.isNull()) - icon = d->createIcon(QLatin1String("messagebox_info.png")); + icon = QIcon::fromTheme(QLatin1String("dialog-information")); break; - } case SP_MessageBoxWarning: - { - icon = d->createIcon(QLatin1String("dialog-warning.png")); - icon = d->createIcon(QLatin1String("dialog-warning.png")); - if (icon.isNull()) - icon = d->createIcon(QLatin1String("messagebox_warning.png")); + icon = QIcon::fromTheme(QLatin1String("dialog-warning")); break; - } case SP_MessageBoxCritical: - { - icon = d->createIcon(QLatin1String("dialog-error.png")); - if (icon.isNull()) - icon = d->createIcon(QLatin1String("messagebox_critical.png")); + icon = QIcon::fromTheme(QLatin1String("dialog-error")); break; - } case SP_MessageBoxQuestion: - { - icon = d->createIcon(QLatin1String("help.png")); + icon = QIcon::fromTheme(QLatin1String("dialog-question")); break; - } case SP_DialogOpenButton: case SP_DirOpenIcon: - { - icon = d->createIcon(QLatin1String("folder-open.png")); - if (icon.isNull()) - icon = d->createIcon(QLatin1String("folder_open.png")); + icon = QIcon::fromTheme(QLatin1String("folder-open")); break; - } case SP_FileIcon: - { - icon = d->createIcon(QLatin1String("text-x-generic.png")); - if (icon.isNull()) - icon = d->createIcon(QLatin1String("empty.png")); + icon = QIcon::fromTheme(QLatin1String("text-x-generic")); break; - } case SP_DirClosedIcon: case SP_DirIcon: - { - icon = d->createIcon(QLatin1String("folder.png")); + icon = QIcon::fromTheme(QLatin1String("folder")); break; - } case SP_DriveFDIcon: - { - icon = d->createIcon(QLatin1String("floppy_unmount.png")); + icon = QIcon::fromTheme(QLatin1String("floppy_unmount")); break; - } case SP_ComputerIcon: - { - icon = d->createIcon(QLatin1String("computer.png")); - if (icon.isNull()) - icon = d->createIcon(QLatin1String("system.png")); + icon = QIcon::fromTheme(QLatin1String("computer"), + QIcon::fromTheme(QLatin1String("system"))); break; - } case SP_DesktopIcon: - { - icon = d->createIcon(QLatin1String("user-desktop.png")); + icon = QIcon::fromTheme(QLatin1String("user-desktop")); break; - } case SP_TrashIcon: - { - icon = d->createIcon(QLatin1String("user-trash.png")); + icon = QIcon::fromTheme(QLatin1String("user-trash")); break; - } case SP_DriveCDIcon: case SP_DriveDVDIcon: - { - icon = d->createIcon(QLatin1String("media-optical.png")); - if (icon.isNull()) - icon = d->createIcon(QLatin1String("cdrom_unmount.png")); + icon = QIcon::fromTheme(QLatin1String("media-optical")); break; - } case SP_DriveHDIcon: - { - icon = d->createIcon(QLatin1String("drive-harddisk.png")); - if (icon.isNull()) - icon = d->createIcon(QLatin1String("hdd_unmount.png")); + icon = QIcon::fromTheme(QLatin1String("drive-harddisk")); break; - } case SP_FileDialogToParent: - { - icon = d->createIcon(QLatin1String("go-up.png")); - if (icon.isNull()) - icon = d->createIcon(QLatin1String("up.png")); + icon = QIcon::fromTheme(QLatin1String("go-up")); break; - } case SP_FileDialogNewFolder: - { - icon = d->createIcon(QLatin1String("folder_new.png")); + icon = QIcon::fromTheme(QLatin1String("folder-new")); break; - } case SP_ArrowUp: - { - icon = d->createIcon(QLatin1String("go-up.png")); - if (icon.isNull()) - icon = d->createIcon(QLatin1String("up.png")); + icon = QIcon::fromTheme(QLatin1String("go-up")); break; - } case SP_ArrowDown: - { - icon = d->createIcon(QLatin1String("go-down.png")); - if (icon.isNull()) - icon = d->createIcon(QLatin1String("down.png")); + icon = QIcon::fromTheme(QLatin1String("go-down")); break; - } case SP_ArrowRight: - { - icon = d->createIcon(QLatin1String("go-next.png")); - if (icon.isNull()) - icon = d->createIcon(QLatin1String("forward.png")); + icon = QIcon::fromTheme(QLatin1String("go-next")); break; - } case SP_ArrowLeft: - { - icon = d->createIcon(QLatin1String("go-previous.png")); - if (icon.isNull()) - icon = d->createIcon(QLatin1String("back.png")); + icon = QIcon::fromTheme(QLatin1String("go-previous")); + break; + case SP_DialogHelpButton: + icon = QIcon::fromTheme(QLatin1String("help-contents")); + break; + case SP_DialogCancelButton: + icon = QIcon::fromTheme(QLatin1String("process-stop")); + break; + case SP_DialogCloseButton: + icon = QIcon::fromTheme(QLatin1String("window-close")); + break; + case SP_DialogApplyButton: + icon = QIcon::fromTheme(QLatin1String("dialog-ok-apply")); + break; + case SP_DialogOkButton: + icon = QIcon::fromTheme(QLatin1String("dialog-ok")); break; - } case SP_FileDialogDetailedView: - { - icon = d->createIcon(QLatin1String("view-list-details.png")); - if (icon.isNull()) - icon = d->createIcon(QLatin1String("view_detailed.png")); + icon = QIcon::fromTheme(QLatin1String("view-list-details")); break; - } case SP_FileDialogListView: - { - icon = d->createIcon(QLatin1String("view-list-icons.png")); - if (icon.isNull()) - icon = d->createIcon(QLatin1String("view_icon.png")); + icon = QIcon::fromTheme(QLatin1String("view-list-icons")); break; - } case SP_BrowserReload: - { - icon = d->createIcon(QLatin1String("view-refresh.png")); - if (icon.isNull()) - icon = d->createIcon(QLatin1String("reload.png")); + icon = QIcon::fromTheme(QLatin1String("view-refresh")); break; - } case SP_BrowserStop: - { - icon = d->createIcon(QLatin1String("process-stop.png")); - if (icon.isNull()) - icon = d->createIcon(QLatin1String("stop.png")); + icon = QIcon::fromTheme(QLatin1String("process-stop")); break; - } case SP_MediaPlay: - { - icon = d->createIcon(QLatin1String("media-playback-start.png")); - if (icon.isNull()) - icon = d->createIcon(QLatin1String("player_play.png")); + icon = QIcon::fromTheme(QLatin1String("media-playback-start")); break; - } case SP_MediaPause: - { - icon = d->createIcon(QLatin1String("media-playback-pause.png")); - if (icon.isNull()) - icon = d->createIcon(QLatin1String("player_pause.png")); + icon = QIcon::fromTheme(QLatin1String("media-playback-pause")); break; - } case SP_MediaStop: - { - icon = d->createIcon(QLatin1String("media-playback-stop.png")); - if (icon.isNull()) - icon = d->createIcon(QLatin1String("player_stop.png")); + icon = QIcon::fromTheme(QLatin1String("media-playback-stop")); break; - } case SP_MediaSeekForward: - { - icon = d->createIcon(QLatin1String("media-skip-forward.png")); - if (icon.isNull()) - icon = d->createIcon(QLatin1String("player_fwd.png")); + icon = QIcon::fromTheme(QLatin1String("media-seek-forward")); break; - } case SP_MediaSeekBackward: - { - icon = d->createIcon(QLatin1String("media-skip-backward.png")); - if (icon.isNull()) - icon = d->createIcon(QLatin1String("player_rew.png")); + icon = QIcon::fromTheme(QLatin1String("media-seek-backward")); break; - } case SP_MediaSkipForward: - { - icon = d->createIcon(QLatin1String("media-skip-forward.png")); - if (icon.isNull()) - icon = d->createIcon(QLatin1String("player_end.png")); + icon = QIcon::fromTheme(QLatin1String("media-skip-forward")); break; - } case SP_MediaSkipBackward: - { - icon = d->createIcon(QLatin1String("media-skip-backward.png")); - if (icon.isNull()) - icon = d->createIcon(QLatin1String("player_start.png")); + icon = QIcon::fromTheme(QLatin1String("media-skip-backward")); break; - } - - case SP_FileLinkIcon: { - icon = QIcon(proxy()->standardPixmap(standardIcon, option, widget)); - QPixmap pixmap = d->findIcon(32, QLatin1String("link_overlay.png")); - if (!pixmap.isNull()) { - QPixmap fileIcon = d->findIcon(32, QLatin1String("text-x-generic.png")); - if (fileIcon.isNull()) - fileIcon = d->findIcon(32, QLatin1String("empty.png")); - if (!fileIcon.isNull()) { - QPainter painter(&fileIcon); - painter.drawPixmap(0, 0, 32, 32, pixmap); - icon.addPixmap(fileIcon); + case SP_MediaVolume: + icon = QIcon::fromTheme(QLatin1String("audio-volume-medium")); + break; + case SP_MediaVolumeMuted: + icon = QIcon::fromTheme(QLatin1String("audio-volume-muted")); + break; + case SP_DialogResetButton: + icon = QIcon::fromTheme(QLatin1String("edit-clear")); + break; + case SP_ArrowForward: + if (QApplication::layoutDirection() == Qt::RightToLeft) + return standardIconImplementation(SP_ArrowLeft, option, widget); + return standardIconImplementation(SP_ArrowRight, option, widget); + case SP_ArrowBack: + if (QApplication::layoutDirection() == Qt::RightToLeft) + return standardIconImplementation(SP_ArrowRight, option, widget); + return standardIconImplementation(SP_ArrowLeft, option, widget); + case SP_FileLinkIcon: + { + QIcon linkIcon = QIcon::fromTheme(QLatin1String("emblem-symbolic-link")); + if (!linkIcon.isNull()) { + QIcon baseIcon = standardIconImplementation(SP_FileIcon, option, widget); + const QList sizes = baseIcon.availableSizes(QIcon::Normal, QIcon::Off); + for (int i = 0 ; i < sizes.size() ; ++i) { + int size = sizes[i].width(); + QPixmap basePixmap = baseIcon.pixmap(size); + QPixmap linkPixmap = linkIcon.pixmap(size/2); + QPainter painter(&basePixmap); + painter.drawPixmap(size/2, size/2, linkPixmap); + icon.addPixmap(basePixmap); + } } } - } - break; - case SP_DirLinkIcon: { - icon = QIcon(proxy()->standardPixmap(standardIcon, option, widget)); - QPixmap pixmap = d->findIcon(32, QLatin1String("link_overlay.png")); - if (!pixmap.isNull()) { - QPixmap fileIcon = d->findIcon(32, QLatin1String("folder.png")); - if (!fileIcon.isNull()) { - QPainter painter(&fileIcon); - painter.drawPixmap(0, 0, 32, 32, pixmap); - icon.addPixmap(fileIcon); + break; + case SP_DirLinkIcon: + { + QIcon linkIcon = QIcon::fromTheme(QLatin1String("emblem-symbolic-link")); + if (!linkIcon.isNull()) { + QIcon baseIcon = standardIconImplementation(SP_DirIcon, option, widget); + const QList sizes = baseIcon.availableSizes(QIcon::Normal, QIcon::Off); + for (int i = 0 ; i < sizes.size() ; ++i) { + int size = sizes[i].width(); + QPixmap basePixmap = baseIcon.pixmap(size); + QPixmap linkPixmap = linkIcon.pixmap(size/2); + QPainter painter(&basePixmap); + painter.drawPixmap(size/2, size/2, linkPixmap); + icon.addPixmap(basePixmap); + } } - } } break; default: break; } + if (!icon.isNull()) return icon; -#elif defined(Q_WS_MAC) +#if defined(Q_WS_MAC) OSType iconType = 0; switch (standardIcon) { case QStyle::SP_MessageBoxQuestion: @@ -6131,11 +5771,9 @@ QIcon QCommonStyle::standardIconImplementation(StandardPixmap standardIcon, cons ReleaseIconRef(overlayIcon); return retIcon; } - -#endif //Q_WS_X11 || Q_WS_MAC +#endif // Q_WS_MAC } - switch (standardIcon) { #ifndef QT_NO_IMAGEFORMAT_PNG case SP_FileDialogNewFolder: diff --git a/src/gui/styles/qcommonstyle_p.h b/src/gui/styles/qcommonstyle_p.h index f2af5b23b..cff46e69d 100644 --- a/src/gui/styles/qcommonstyle_p.h +++ b/src/gui/styles/qcommonstyle_p.h @@ -122,20 +122,7 @@ public: } #endif mutable QIcon tabBarcloseButtonIcon; - -//icon detection on X11 -#ifdef Q_WS_X11 - void lookupIconTheme() const; int lookupToolButtonStyle() const; - QIcon createIcon(const QString &) const; - QPixmap findIcon(int size, const QString &) const; - QPixmap findIconHelper(int size, const QString &, const QString &, QStringList &visited) const; - QIconTheme parseIndexFile(const QString &themeName) const; - mutable QString themeName; - mutable QStringList iconDirs; - mutable QHash themeList; -#endif - }; QT_END_NAMESPACE diff --git a/src/gui/styles/qgtkstyle.cpp b/src/gui/styles/qgtkstyle.cpp index 660b4c3de..f6d8c889d 100644 --- a/src/gui/styles/qgtkstyle.cpp +++ b/src/gui/styles/qgtkstyle.cpp @@ -3239,6 +3239,7 @@ QSize QGtkStyle::sizeFromContents(ContentsType type, const QStyleOption *option, return newSize; } + /*! \reimp */ QPixmap QGtkStyle::standardPixmap(StandardPixmap sp, const QStyleOption *option, const QWidget *widget) const @@ -3271,65 +3272,80 @@ QPixmap QGtkStyle::standardPixmap(StandardPixmap sp, const QStyleOption *option, } break; - case SP_DialogDiscardButton: { + case SP_DialogDiscardButton: return QGtkPainter::getIcon(GTK_STOCK_DELETE); - } - - case SP_DialogOkButton: { + case SP_DialogOkButton: return QGtkPainter::getIcon(GTK_STOCK_OK); - } - - case SP_DialogCancelButton: { + case SP_DialogCancelButton: return QGtkPainter::getIcon(GTK_STOCK_CANCEL); - } - - case SP_DialogYesButton: { + case SP_DialogYesButton: return QGtkPainter::getIcon(GTK_STOCK_YES); - } - - case SP_DialogNoButton: { + case SP_DialogNoButton: return QGtkPainter::getIcon(GTK_STOCK_NO); - } - - case SP_DialogOpenButton: { + case SP_DialogOpenButton: return QGtkPainter::getIcon(GTK_STOCK_OPEN); - } - - case SP_DialogCloseButton: { + case SP_DialogCloseButton: return QGtkPainter::getIcon(GTK_STOCK_CLOSE); - } - - case SP_DialogApplyButton: { + case SP_DialogApplyButton: return QGtkPainter::getIcon(GTK_STOCK_APPLY); - } - - case SP_DialogSaveButton: { + case SP_DialogSaveButton: return QGtkPainter::getIcon(GTK_STOCK_SAVE); - } - - case SP_MessageBoxWarning: { + case SP_MessageBoxWarning: return QGtkPainter::getIcon(GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_DIALOG); - } - - case SP_MessageBoxQuestion: { + case SP_MessageBoxQuestion: return QGtkPainter::getIcon(GTK_STOCK_DIALOG_QUESTION, GTK_ICON_SIZE_DIALOG); - } - - case SP_MessageBoxInformation: { + case SP_MessageBoxInformation: return QGtkPainter::getIcon(GTK_STOCK_DIALOG_INFO, GTK_ICON_SIZE_DIALOG); - } - - case SP_MessageBoxCritical: { + case SP_MessageBoxCritical: return QGtkPainter::getIcon(GTK_STOCK_DIALOG_ERROR, GTK_ICON_SIZE_DIALOG); - } - default: return QCleanlooksStyle::standardPixmap(sp, option, widget); } + return pixmap; +} - return QPixmap(); +/*! + \internal +*/ +QIcon QGtkStyle::standardIconImplementation(StandardPixmap standardIcon, + const QStyleOption *option, + const QWidget *widget) const +{ + if (!QGtk::isThemeAvailable()) + return QCleanlooksStyle::standardIconImplementation(standardIcon, option, widget); + switch (standardIcon) { + case SP_DialogDiscardButton: + return QGtkPainter::getIcon(GTK_STOCK_DELETE); + case SP_DialogOkButton: + return QGtkPainter::getIcon(GTK_STOCK_OK); + case SP_DialogCancelButton: + return QGtkPainter::getIcon(GTK_STOCK_CANCEL); + case SP_DialogYesButton: + return QGtkPainter::getIcon(GTK_STOCK_YES); + case SP_DialogNoButton: + return QGtkPainter::getIcon(GTK_STOCK_NO); + case SP_DialogOpenButton: + return QGtkPainter::getIcon(GTK_STOCK_OPEN); + case SP_DialogCloseButton: + return QGtkPainter::getIcon(GTK_STOCK_CLOSE); + case SP_DialogApplyButton: + return QGtkPainter::getIcon(GTK_STOCK_APPLY); + case SP_DialogSaveButton: + return QGtkPainter::getIcon(GTK_STOCK_SAVE); + case SP_MessageBoxWarning: + return QGtkPainter::getIcon(GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_DIALOG); + case SP_MessageBoxQuestion: + return QGtkPainter::getIcon(GTK_STOCK_DIALOG_QUESTION, GTK_ICON_SIZE_DIALOG); + case SP_MessageBoxInformation: + return QGtkPainter::getIcon(GTK_STOCK_DIALOG_INFO, GTK_ICON_SIZE_DIALOG); + case SP_MessageBoxCritical: + return QGtkPainter::getIcon(GTK_STOCK_DIALOG_ERROR, GTK_ICON_SIZE_DIALOG); + default: + return QCleanlooksStyle::standardIconImplementation(standardIcon, option, widget); + } } + /*! \reimp */ QRect QGtkStyle::subElementRect(SubElement element, const QStyleOption *option, const QWidget *widget) const { diff --git a/src/gui/styles/qgtkstyle.h b/src/gui/styles/qgtkstyle.h index e12f175f1..f12de521c 100644 --- a/src/gui/styles/qgtkstyle.h +++ b/src/gui/styles/qgtkstyle.h @@ -106,6 +106,10 @@ public: void unpolish(QWidget *widget); void unpolish(QApplication *app); + +protected Q_SLOTS: + QIcon standardIconImplementation(StandardPixmap standardIcon, const QStyleOption *option, + const QWidget *widget = 0) const; }; diff --git a/tests/auto/qicon/icons/testtheme/16x16/actions/appointment-new.png b/tests/auto/qicon/icons/testtheme/16x16/actions/appointment-new.png new file mode 100644 index 000000000..18b7c6781 Binary files /dev/null and b/tests/auto/qicon/icons/testtheme/16x16/actions/appointment-new.png differ diff --git a/tests/auto/qicon/icons/testtheme/22x22/actions/appointment-new.png b/tests/auto/qicon/icons/testtheme/22x22/actions/appointment-new.png new file mode 100644 index 000000000..d676ffd46 Binary files /dev/null and b/tests/auto/qicon/icons/testtheme/22x22/actions/appointment-new.png differ diff --git a/tests/auto/qicon/icons/testtheme/32x32/actions/appointment-new.png b/tests/auto/qicon/icons/testtheme/32x32/actions/appointment-new.png new file mode 100644 index 000000000..85daef3b0 Binary files /dev/null and b/tests/auto/qicon/icons/testtheme/32x32/actions/appointment-new.png differ diff --git a/tests/auto/qicon/icons/testtheme/index.theme b/tests/auto/qicon/icons/testtheme/index.theme new file mode 100644 index 000000000..e18736ab4 --- /dev/null +++ b/tests/auto/qicon/icons/testtheme/index.theme @@ -0,0 +1,492 @@ +[Icon Theme] +_Name=Test +_Comment=Test Theme +Inherits=crystalsvg, themeparent +Example=x-directory-normal + +# KDE Specific Stuff +DisplayDepth=32 +LinkOverlay=link_overlay +LockOverlay=lock_overlay +ZipOverlay=zip_overlay +DesktopDefault=48 +DesktopSizes=16,22,32,48,64,72,96,128 +ToolbarDefault=22 +ToolbarSizes=16,22,32,48 +MainToolbarDefault=22 +MainToolbarSizes=16,22,32,48 +SmallDefault=16 +SmallSizes=16 +PanelDefault=32 +PanelSizes=16,22,32,48,64,72,96,128 + +# Directory list +Directories=16x16/actions,16x16/apps,16x16/categories,16x16/devices,16x16/emblems,16x16/emotes,16x16/mimetypes,16x16/places,16x16/status,22x22/actions,22x22/apps,22x22/categories,22x22/devices,22x22/emblems,22x22/emotes,22x22/mimetypes,22x22/places,22x22/status,24x24/actions,24x24/apps,24x24/categories,24x24/devices,24x24/emblems,24x24/emotes,24x24/mimetypes,24x24/places,24x24/status,32x32/actions,32x32/apps,32x32/categories,32x32/devices,32x32/emblems,32x32/emotes,32x32/mimetypes,32x32/places,32x32/status,48x48/actions,48x48/apps,48x48/categories,48x48/devices,48x48/emblems,48x48/emotes,48x48/mimetypes,48x48/places,48x48/status,64x64/actions,64x64/apps,64x64/categories,64x64/devices,64x64/emblems,64x64/emotes,64x64/mimetypes,64x64/places,64x64/status,72x72/actions,72x72/apps,72x72/categories,72x72/devices,72x72/emblems,72x72/emotes,72x72/mimetypes,72x72/places,72x72/status,96x96/actions,96x96/apps,96x96/categories,96x96/devices,96x96/emblems,96x96/emotes,96x96/mimetypes,96x96/places,96x96/status,128x128/actions,128x128/apps,128x128/categories,128x128/devices,128x128/emblems,128x128/emotes,128x128/mimetypes,128x128/places,128x128/status,scalable/actions,scalable/apps,scalable/categories,scalable/devices,scalable/emblems,scalable/emotes,scalable/mimetypes,scalable/places,scalable/status + +[16x16/actions] +Size=16 +Context=Actions +Type=Fixed + +[16x16/apps] +Size=16 +Context=Applications +Type=Fixed + +[16x16/categories] +Size=16 +Context=Categories +Type=Fixed + +[16x16/devices] +Size=16 +Context=Devices +Type=Fixed + +[16x16/emblems] +Size=16 +Context=Emblems +Type=Fixed + +[16x16/emotes] +Size=16 +Context=Emotes +Type=Fixed + +[16x16/mimetypes] +Size=16 +Context=MimeTypes +Type=Fixed + +[16x16/places] +Size=16 +Context=Places +Type=Fixed + +[16x16/status] +Size=16 +Context=Status +Type=Fixed + +[22x22/actions] +Size=22 +Context=Actions +Type=Fixed + +[22x22/apps] +Size=22 +Context=Applications +Type=Fixed + +[22x22/categories] +Size=22 +Context=Categories +Type=Fixed + +[22x22/devices] +Size=22 +Context=Devices +Type=Fixed + +[22x22/emblems] +Size=22 +Context=Emblems +Type=Fixed + +[22x22/emotes] +Size=22 +Context=Emotes +Type=Fixed + +[22x22/mimetypes] +Size=22 +Context=MimeTypes +Type=Fixed + +[22x22/places] +Size=22 +Context=Places +Type=Fixed + +[22x22/status] +Size=22 +Context=Status +Type=Fixed + +[24x24/actions] +Size=24 +Context=Actions +Type=Fixed + +[24x24/apps] +Size=24 +Context=Applications +Type=Fixed + +[24x24/categories] +Size=24 +Context=Categories +Type=Fixed + +[24x24/devices] +Size=24 +Context=Devices +Type=Fixed + +[24x24/emblems] +Size=24 +Context=Emblems +Type=Fixed + +[24x24/emotes] +Size=24 +Context=Emotes +Type=Fixed + +[24x24/mimetypes] +Size=24 +Context=MimeTypes +Type=Fixed + +[24x24/places] +Size=24 +Context=Places +Type=Fixed + +[24x24/status] +Size=24 +Context=Status +Type=Fixed + +[32x32/actions] +Size=32 +Context=Actions +Type=Fixed + +[32x32/apps] +Size=32 +Context=Applications +Type=Fixed + +[32x32/categories] +Size=32 +Context=Categories +Type=Fixed + +[32x32/devices] +Size=32 +Context=Devices +Type=Fixed + +[32x32/emblems] +Size=32 +Context=Emblems +Type=Fixed + +[32x32/emotes] +Size=32 +Context=Emotes +Type=Fixed + +[32x32/mimetypes] +Size=32 +Context=MimeTypes +Type=Fixed + +[32x32/places] +Size=32 +Context=Places +Type=Fixed + +[32x32/status] +Size=32 +Context=Status +Type=Fixed + +[48x48/actions] +Size=48 +Context=Actions +Type=Fixed + +[48x48/apps] +Size=48 +Context=Applications +Type=Fixed + +[48x48/categories] +Size=48 +Context=Categories +Type=Fixed + +[48x48/devices] +Size=48 +Context=Devices +Type=Fixed + +[48x48/emblems] +Size=48 +Context=Emblems +Type=Fixed + +[48x48/emotes] +Size=48 +Context=Emotes +Type=Fixed + +[48x48/mimetypes] +Size=48 +Context=MimeTypes +Type=Fixed + +[48x48/places] +Size=48 +Context=Places +Type=Fixed + +[48x48/status] +Size=48 +Context=Status +Type=Fixed + +[64x64/actions] +Size=64 +Context=Actions +Type=Fixed + +[64x64/apps] +Size=64 +Context=Applications +Type=Fixed + +[64x64/categories] +Size=64 +Context=Categories +Type=Fixed + +[64x64/devices] +Size=64 +Context=Devices +Type=Fixed + +[64x64/emblems] +Size=64 +Context=Emblems +Type=Fixed + +[64x64/emotes] +Size=64 +Context=Emotes +Type=Fixed + +[64x64/mimetypes] +Size=64 +Context=MimeTypes +Type=Fixed + +[64x64/places] +Size=64 +Context=Places +Type=Fixed + +[64x64/status] +Size=64 +Context=Status +Type=Fixed + +[72x72/actions] +Size=72 +Context=Actions +Type=Fixed + +[72x72/apps] +Size=72 +Context=Applications +Type=Fixed + +[72x72/categories] +Size=72 +Context=Categories +Type=Fixed + +[72x72/devices] +Size=72 +Context=Devices +Type=Fixed + +[72x72/emblems] +Size=72 +Context=Emblems +Type=Fixed + +[72x72/emotes] +Size=72 +Context=Emotes +Type=Fixed + +[72x72/mimetypes] +Size=72 +Context=MimeTypes +Type=Fixed + +[72x72/places] +Size=72 +Context=Places +Type=Fixed + +[72x72/status] +Size=72 +Context=Status +Type=Fixed + +[96x96/actions] +Size=96 +Context=Actions +Type=Fixed + +[96x96/apps] +Size=96 +Context=Applications +Type=Fixed + +[96x96/categories] +Size=96 +Context=Categories +Type=Fixed + +[96x96/devices] +Size=96 +Context=Devices +Type=Fixed + +[96x96/emblems] +Size=96 +Context=Emblems +Type=Fixed + +[96x96/emotes] +Size=96 +Context=Emotes +Type=Fixed + +[96x96/mimetypes] +Size=96 +Context=MimeTypes +Type=Fixed + +[96x96/places] +Size=96 +Context=Places +Type=Fixed + +[96x96/status] +Size=96 +Context=Status +Type=Fixed + +[128x128/actions] +Size=128 +Context=Actions +Type=Fixed + +[128x128/apps] +Size=128 +Context=Applications +Type=Fixed + +[128x128/categories] +Size=128 +Context=Categories +Type=Fixed + +[128x128/devices] +Size=128 +Context=Devices +Type=Fixed + +[128x128/emblems] +Size=128 +Context=Emblems +Type=Fixed + +[128x128/emotes] +Size=128 +Context=Emotes +Type=Fixed + +[128x128/mimetypes] +Size=128 +Context=MimeTypes +Type=Fixed + +[128x128/places] +Size=128 +Context=Places +Type=Fixed + +[128x128/status] +Size=128 +Context=Status +Type=Fixed + +[scalable/actions] +Size=48 +Context=Actions +Type=Scalable +MinSize=32 +MaxSize=256 + +[scalable/apps] +Size=48 +Context=Applications +Type=Scalable +MinSize=32 +MaxSize=256 + +[scalable/categories] +Size=48 +Context=Categories +Type=Scalable +MinSize=32 +MaxSize=256 + +[scalable/devices] +Size=48 +Context=Devices +Type=Scalable +MinSize=32 +MaxSize=256 + +[scalable/emblems] +Size=48 +Context=Emblems +Type=Scalable +MinSize=32 +MaxSize=256 + +[scalable/emotes] +Size=48 +Context=Emotes +Type=Scalable +Minsize=32 +MaxSize=256 + +[scalable/mimetypes] +Size=48 +Context=MimeTypes +Type=Scalable +MinSize=32 +MaxSize=256 + +[scalable/places] +Size=48 +Context=Places +Type=Scalable +MinSize=32 +MaxSize=256 + +[scalable/status] +Size=48 +Context=Status +Type=Scalable +MinSize=32 +MaxSize=256 diff --git a/tests/auto/qicon/icons/testtheme/scalable/actions/svg-only.svg b/tests/auto/qicon/icons/testtheme/scalable/actions/svg-only.svg new file mode 100644 index 000000000..4cb14f82f --- /dev/null +++ b/tests/auto/qicon/icons/testtheme/scalable/actions/svg-only.svg @@ -0,0 +1,425 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + Jakub Steiner + + + http://jimmac.musichall.cz + + New Appointment + + + appointment + new + meeting + rvsp + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/auto/qicon/icons/themeparent/16x16/actions/address-book-new.png b/tests/auto/qicon/icons/themeparent/16x16/actions/address-book-new.png new file mode 100644 index 000000000..2098cfdf3 Binary files /dev/null and b/tests/auto/qicon/icons/themeparent/16x16/actions/address-book-new.png differ diff --git a/tests/auto/qicon/icons/themeparent/16x16/actions/appointment-new.png b/tests/auto/qicon/icons/themeparent/16x16/actions/appointment-new.png new file mode 100644 index 000000000..18b7c6781 Binary files /dev/null and b/tests/auto/qicon/icons/themeparent/16x16/actions/appointment-new.png differ diff --git a/tests/auto/qicon/icons/themeparent/22x22/actions/address-book-new.png b/tests/auto/qicon/icons/themeparent/22x22/actions/address-book-new.png new file mode 100644 index 000000000..fad446cd9 Binary files /dev/null and b/tests/auto/qicon/icons/themeparent/22x22/actions/address-book-new.png differ diff --git a/tests/auto/qicon/icons/themeparent/22x22/actions/appointment-new.png b/tests/auto/qicon/icons/themeparent/22x22/actions/appointment-new.png new file mode 100644 index 000000000..d676ffd46 Binary files /dev/null and b/tests/auto/qicon/icons/themeparent/22x22/actions/appointment-new.png differ diff --git a/tests/auto/qicon/icons/themeparent/32x32/actions/address-book-new.png b/tests/auto/qicon/icons/themeparent/32x32/actions/address-book-new.png new file mode 100644 index 000000000..420139d30 Binary files /dev/null and b/tests/auto/qicon/icons/themeparent/32x32/actions/address-book-new.png differ diff --git a/tests/auto/qicon/icons/themeparent/32x32/actions/appointment-new.png b/tests/auto/qicon/icons/themeparent/32x32/actions/appointment-new.png new file mode 100644 index 000000000..85daef3b0 Binary files /dev/null and b/tests/auto/qicon/icons/themeparent/32x32/actions/appointment-new.png differ diff --git a/tests/auto/qicon/icons/themeparent/index.theme b/tests/auto/qicon/icons/themeparent/index.theme new file mode 100644 index 000000000..e536a0bf2 --- /dev/null +++ b/tests/auto/qicon/icons/themeparent/index.theme @@ -0,0 +1,492 @@ +[Icon Theme] +_Name=Test +_Comment=Test Theme +Inherits=gnome,crystalsvg +Example=x-directory-normal + +# KDE Specific Stuff +DisplayDepth=32 +LinkOverlay=link_overlay +LockOverlay=lock_overlay +ZipOverlay=zip_overlay +DesktopDefault=48 +DesktopSizes=16,22,32,48,64,72,96,128 +ToolbarDefault=22 +ToolbarSizes=16,22,32,48 +MainToolbarDefault=22 +MainToolbarSizes=16,22,32,48 +SmallDefault=16 +SmallSizes=16 +PanelDefault=32 +PanelSizes=16,22,32,48,64,72,96,128 + +# Directory list +Directories=16x16/actions,16x16/apps,16x16/categories,16x16/devices,16x16/emblems,16x16/emotes,16x16/mimetypes,16x16/places,16x16/status,22x22/actions,22x22/apps,22x22/categories,22x22/devices,22x22/emblems,22x22/emotes,22x22/mimetypes,22x22/places,22x22/status,24x24/actions,24x24/apps,24x24/categories,24x24/devices,24x24/emblems,24x24/emotes,24x24/mimetypes,24x24/places,24x24/status,32x32/actions,32x32/apps,32x32/categories,32x32/devices,32x32/emblems,32x32/emotes,32x32/mimetypes,32x32/places,32x32/status,48x48/actions,48x48/apps,48x48/categories,48x48/devices,48x48/emblems,48x48/emotes,48x48/mimetypes,48x48/places,48x48/status,64x64/actions,64x64/apps,64x64/categories,64x64/devices,64x64/emblems,64x64/emotes,64x64/mimetypes,64x64/places,64x64/status,72x72/actions,72x72/apps,72x72/categories,72x72/devices,72x72/emblems,72x72/emotes,72x72/mimetypes,72x72/places,72x72/status,96x96/actions,96x96/apps,96x96/categories,96x96/devices,96x96/emblems,96x96/emotes,96x96/mimetypes,96x96/places,96x96/status,128x128/actions,128x128/apps,128x128/categories,128x128/devices,128x128/emblems,128x128/emotes,128x128/mimetypes,128x128/places,128x128/status,scalable/actions,scalable/apps,scalable/categories,scalable/devices,scalable/emblems,scalable/emotes,scalable/mimetypes,scalable/places,scalable/status + +[16x16/actions] +Size=16 +Context=Actions +Type=Fixed + +[16x16/apps] +Size=16 +Context=Applications +Type=Fixed + +[16x16/categories] +Size=16 +Context=Categories +Type=Fixed + +[16x16/devices] +Size=16 +Context=Devices +Type=Fixed + +[16x16/emblems] +Size=16 +Context=Emblems +Type=Fixed + +[16x16/emotes] +Size=16 +Context=Emotes +Type=Fixed + +[16x16/mimetypes] +Size=16 +Context=MimeTypes +Type=Fixed + +[16x16/places] +Size=16 +Context=Places +Type=Fixed + +[16x16/status] +Size=16 +Context=Status +Type=Fixed + +[22x22/actions] +Size=22 +Context=Actions +Type=Fixed + +[22x22/apps] +Size=22 +Context=Applications +Type=Fixed + +[22x22/categories] +Size=22 +Context=Categories +Type=Fixed + +[22x22/devices] +Size=22 +Context=Devices +Type=Fixed + +[22x22/emblems] +Size=22 +Context=Emblems +Type=Fixed + +[22x22/emotes] +Size=22 +Context=Emotes +Type=Fixed + +[22x22/mimetypes] +Size=22 +Context=MimeTypes +Type=Fixed + +[22x22/places] +Size=22 +Context=Places +Type=Fixed + +[22x22/status] +Size=22 +Context=Status +Type=Fixed + +[24x24/actions] +Size=24 +Context=Actions +Type=Fixed + +[24x24/apps] +Size=24 +Context=Applications +Type=Fixed + +[24x24/categories] +Size=24 +Context=Categories +Type=Fixed + +[24x24/devices] +Size=24 +Context=Devices +Type=Fixed + +[24x24/emblems] +Size=24 +Context=Emblems +Type=Fixed + +[24x24/emotes] +Size=24 +Context=Emotes +Type=Fixed + +[24x24/mimetypes] +Size=24 +Context=MimeTypes +Type=Fixed + +[24x24/places] +Size=24 +Context=Places +Type=Fixed + +[24x24/status] +Size=24 +Context=Status +Type=Fixed + +[32x32/actions] +Size=32 +Context=Actions +Type=Fixed + +[32x32/apps] +Size=32 +Context=Applications +Type=Fixed + +[32x32/categories] +Size=32 +Context=Categories +Type=Fixed + +[32x32/devices] +Size=32 +Context=Devices +Type=Fixed + +[32x32/emblems] +Size=32 +Context=Emblems +Type=Fixed + +[32x32/emotes] +Size=32 +Context=Emotes +Type=Fixed + +[32x32/mimetypes] +Size=32 +Context=MimeTypes +Type=Fixed + +[32x32/places] +Size=32 +Context=Places +Type=Fixed + +[32x32/status] +Size=32 +Context=Status +Type=Fixed + +[48x48/actions] +Size=48 +Context=Actions +Type=Fixed + +[48x48/apps] +Size=48 +Context=Applications +Type=Fixed + +[48x48/categories] +Size=48 +Context=Categories +Type=Fixed + +[48x48/devices] +Size=48 +Context=Devices +Type=Fixed + +[48x48/emblems] +Size=48 +Context=Emblems +Type=Fixed + +[48x48/emotes] +Size=48 +Context=Emotes +Type=Fixed + +[48x48/mimetypes] +Size=48 +Context=MimeTypes +Type=Fixed + +[48x48/places] +Size=48 +Context=Places +Type=Fixed + +[48x48/status] +Size=48 +Context=Status +Type=Fixed + +[64x64/actions] +Size=64 +Context=Actions +Type=Fixed + +[64x64/apps] +Size=64 +Context=Applications +Type=Fixed + +[64x64/categories] +Size=64 +Context=Categories +Type=Fixed + +[64x64/devices] +Size=64 +Context=Devices +Type=Fixed + +[64x64/emblems] +Size=64 +Context=Emblems +Type=Fixed + +[64x64/emotes] +Size=64 +Context=Emotes +Type=Fixed + +[64x64/mimetypes] +Size=64 +Context=MimeTypes +Type=Fixed + +[64x64/places] +Size=64 +Context=Places +Type=Fixed + +[64x64/status] +Size=64 +Context=Status +Type=Fixed + +[72x72/actions] +Size=72 +Context=Actions +Type=Fixed + +[72x72/apps] +Size=72 +Context=Applications +Type=Fixed + +[72x72/categories] +Size=72 +Context=Categories +Type=Fixed + +[72x72/devices] +Size=72 +Context=Devices +Type=Fixed + +[72x72/emblems] +Size=72 +Context=Emblems +Type=Fixed + +[72x72/emotes] +Size=72 +Context=Emotes +Type=Fixed + +[72x72/mimetypes] +Size=72 +Context=MimeTypes +Type=Fixed + +[72x72/places] +Size=72 +Context=Places +Type=Fixed + +[72x72/status] +Size=72 +Context=Status +Type=Fixed + +[96x96/actions] +Size=96 +Context=Actions +Type=Fixed + +[96x96/apps] +Size=96 +Context=Applications +Type=Fixed + +[96x96/categories] +Size=96 +Context=Categories +Type=Fixed + +[96x96/devices] +Size=96 +Context=Devices +Type=Fixed + +[96x96/emblems] +Size=96 +Context=Emblems +Type=Fixed + +[96x96/emotes] +Size=96 +Context=Emotes +Type=Fixed + +[96x96/mimetypes] +Size=96 +Context=MimeTypes +Type=Fixed + +[96x96/places] +Size=96 +Context=Places +Type=Fixed + +[96x96/status] +Size=96 +Context=Status +Type=Fixed + +[128x128/actions] +Size=128 +Context=Actions +Type=Fixed + +[128x128/apps] +Size=128 +Context=Applications +Type=Fixed + +[128x128/categories] +Size=128 +Context=Categories +Type=Fixed + +[128x128/devices] +Size=128 +Context=Devices +Type=Fixed + +[128x128/emblems] +Size=128 +Context=Emblems +Type=Fixed + +[128x128/emotes] +Size=128 +Context=Emotes +Type=Fixed + +[128x128/mimetypes] +Size=128 +Context=MimeTypes +Type=Fixed + +[128x128/places] +Size=128 +Context=Places +Type=Fixed + +[128x128/status] +Size=128 +Context=Status +Type=Fixed + +[scalable/actions] +Size=48 +Context=Actions +Type=Scalable +MinSize=32 +MaxSize=256 + +[scalable/apps] +Size=48 +Context=Applications +Type=Scalable +MinSize=32 +MaxSize=256 + +[scalable/categories] +Size=48 +Context=Categories +Type=Scalable +MinSize=32 +MaxSize=256 + +[scalable/devices] +Size=48 +Context=Devices +Type=Scalable +MinSize=32 +MaxSize=256 + +[scalable/emblems] +Size=48 +Context=Emblems +Type=Scalable +MinSize=32 +MaxSize=256 + +[scalable/emotes] +Size=48 +Context=Emotes +Type=Scalable +Minsize=32 +MaxSize=256 + +[scalable/mimetypes] +Size=48 +Context=MimeTypes +Type=Scalable +MinSize=32 +MaxSize=256 + +[scalable/places] +Size=48 +Context=Places +Type=Scalable +MinSize=32 +MaxSize=256 + +[scalable/status] +Size=48 +Context=Status +Type=Scalable +MinSize=32 +MaxSize=256 diff --git a/tests/auto/qicon/icons/themeparent/scalable/actions/address-book-new.svg b/tests/auto/qicon/icons/themeparent/scalable/actions/address-book-new.svg new file mode 100644 index 000000000..600a82c1b --- /dev/null +++ b/tests/auto/qicon/icons/themeparent/scalable/actions/address-book-new.svg @@ -0,0 +1,389 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + Addess Book - New + + + + Jakub Steiner + + + http://jimmac.musichall.cz + + + address + contact + book + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/auto/qicon/icons/themeparent/scalable/actions/appointment-new.svg b/tests/auto/qicon/icons/themeparent/scalable/actions/appointment-new.svg new file mode 100644 index 000000000..4cb14f82f --- /dev/null +++ b/tests/auto/qicon/icons/themeparent/scalable/actions/appointment-new.svg @@ -0,0 +1,425 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + Jakub Steiner + + + http://jimmac.musichall.cz + + New Appointment + + + appointment + new + meeting + rvsp + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/auto/qicon/tst_qicon.cpp b/tests/auto/qicon/tst_qicon.cpp index a266c1646..545ca0986 100644 --- a/tests/auto/qicon/tst_qicon.cpp +++ b/tests/auto/qicon/tst_qicon.cpp @@ -74,6 +74,7 @@ private slots: void availableSizes(); void streamAvailableSizes_data(); void streamAvailableSizes(); + void fromTheme(); void task184901_badCache(); void task223279_inconsistentAddFile(); @@ -605,6 +606,72 @@ void tst_QIcon::task184901_badCache() QVERIFY( icon.pixmap(32, QIcon::Normal).toImage() == icon.pixmap(32, QIcon::Disabled).toImage() ); } +void tst_QIcon::fromTheme() +{ + const QString prefix = QLatin1String(SRCDIR) + QLatin1String("/"); + QString searchPath = prefix + QLatin1String("/icons"); + QIcon::setThemeSearchPaths(QStringList() << searchPath); + QVERIFY(QIcon::themeSearchPaths().size() == 1); + QCOMPARE(searchPath, QIcon::themeSearchPaths()[0]); + + QString themeName("testtheme"); + QIcon::setThemeName(themeName); + QCOMPARE(QIcon::themeName(), themeName); + + // Test normal icon + QIcon appointmentIcon = QIcon::fromTheme("appointment-new"); + QVERIFY(!appointmentIcon.isNull()); + QVERIFY(!appointmentIcon.availableSizes(QIcon::Normal, QIcon::Off).isEmpty()); + QVERIFY(appointmentIcon.availableSizes().contains(QSize(16, 16))); + QVERIFY(appointmentIcon.availableSizes().contains(QSize(32, 32))); + QVERIFY(appointmentIcon.availableSizes().contains(QSize(22, 22))); + + // Test icon from parent theme + QIcon abIcon = QIcon::fromTheme("address-book-new"); + QVERIFY(!abIcon.isNull()); + QVERIFY(QIcon::hasThemeIcon("address-book-new")); + QVERIFY(!abIcon.availableSizes().isEmpty()); + + // Test non existing icon + QIcon noIcon = QIcon::fromTheme("broken-icon"); + QVERIFY(noIcon.isNull()); + QVERIFY(!QIcon::hasThemeIcon("broken-icon")); + + // Test non existing icon with fallback + noIcon = QIcon::fromTheme("broken-icon", abIcon); + QVERIFY(noIcon.cacheKey() == abIcon.cacheKey()); + + // Test svg-only icon + noIcon = QIcon::fromTheme("svg-icon", abIcon); + QVERIFY(!noIcon.availableSizes().isEmpty()); + + QByteArray ba; + // write to QByteArray + { + QBuffer buffer(&ba); + buffer.open(QIODevice::WriteOnly); + QDataStream stream(&buffer); + stream << abIcon; + } + + // read from QByteArray + { + QBuffer buffer(&ba); + buffer.open(QIODevice::ReadOnly); + QDataStream stream(&buffer); + QIcon i; + stream >> i; + QCOMPARE(i.isNull(), abIcon.isNull()); + QCOMPARE(i.availableSizes(), abIcon.availableSizes()); + } + + // Make sure setting the theme name clears the state + QIcon::setThemeName(""); + abIcon = QIcon::fromTheme("address-book-new"); + QVERIFY(abIcon.isNull()); +} + + void tst_QIcon::task223279_inconsistentAddFile() { QIcon icon1; diff --git a/tools/assistant/compat/mainwindow.cpp b/tools/assistant/compat/mainwindow.cpp index 670b1440b..9d308dfa0 100644 --- a/tools/assistant/compat/mainwindow.cpp +++ b/tools/assistant/compat/mainwindow.cpp @@ -140,6 +140,16 @@ MainWindow::MainWindow() ui.actionZoomIn->setIcon(QIcon(MacIconPath + QLatin1String("/zoomin.png"))); ui.actionSyncToc->setIcon(QIcon(MacIconPath + QLatin1String("/synctoc.png"))); ui.actionHelpWhatsThis->setIcon(QIcon(MacIconPath + QLatin1String("/whatsthis.png"))); +#elif defined(Q_WS_X11) + ui.actionGoNext->setIcon(QIcon::fromTheme("go-next" , ui.actionGoNext->icon())); + ui.actionGoPrevious->setIcon(QIcon::fromTheme("go-previous" , ui.actionGoPrevious->icon())); + ui.actionGoHome->setIcon(QIcon::fromTheme("user-home" , ui.actionGoHome->icon())); + ui.actionEditCopy->setIcon(QIcon::fromTheme("edit-copy" , ui.actionEditCopy->icon())); + ui.actionEditFind->setIcon(QIcon::fromTheme("edit-find" , ui.actionEditFind->icon())); + ui.actionFilePrint->setIcon(QIcon::fromTheme("document-print" , ui.actionFilePrint->icon())); + ui.actionZoomOut->setIcon(QIcon::fromTheme("zoom-out" , ui.actionZoomOut->icon())); + ui.actionZoomIn->setIcon(QIcon::fromTheme("zoom-in" , ui.actionZoomIn->icon())); + ui.actionSyncToc->setIcon(QIcon::fromTheme("view-refresh" , ui.actionSyncToc->icon())); #endif } diff --git a/tools/assistant/tools/assistant/mainwindow.cpp b/tools/assistant/tools/assistant/mainwindow.cpp index bc73b80d6..a0d4fbfcc 100644 --- a/tools/assistant/tools/assistant/mainwindow.cpp +++ b/tools/assistant/tools/assistant/mainwindow.cpp @@ -545,6 +545,19 @@ void MainWindow::setupActions() m_aboutAction = menu->addAction(tr("About..."), this, SLOT(showAboutDialog())); m_aboutAction->setMenuRole(QAction::AboutRole); +#ifdef Q_WS_X11 + m_backAction->setIcon(QIcon::fromTheme("go-previous" , m_backAction->icon())); + m_nextAction->setIcon(QIcon::fromTheme("go-next" , m_nextAction->icon())); + m_zoomInAction->setIcon(QIcon::fromTheme("zoom-in" , m_zoomInAction->icon())); + m_zoomOutAction->setIcon(QIcon::fromTheme("zoom-out" , m_zoomOutAction->icon())); + m_resetZoomAction->setIcon(QIcon::fromTheme("zoom-original" , m_resetZoomAction->icon())); + m_syncAction->setIcon(QIcon::fromTheme("view-refresh" , m_syncAction->icon())); + m_copyAction->setIcon(QIcon::fromTheme("edit-copy" , m_copyAction->icon())); + m_findAction->setIcon(QIcon::fromTheme("edit-find" , m_findAction->icon())); + m_homeAction->setIcon(QIcon::fromTheme("go-home" , m_homeAction->icon())); + m_printAction->setIcon(QIcon::fromTheme("document-print" , m_printAction->icon())); +#endif + QToolBar *navigationBar = addToolBar(tr("Navigation Toolbar")); navigationBar->setObjectName(QLatin1String("NavigationToolBar")); navigationBar->addAction(m_backAction); diff --git a/tools/designer/src/components/buddyeditor/buddyeditor_plugin.cpp b/tools/designer/src/components/buddyeditor/buddyeditor_plugin.cpp index ff0c3c688..cf838a248 100644 --- a/tools/designer/src/components/buddyeditor/buddyeditor_plugin.cpp +++ b/tools/designer/src/components/buddyeditor/buddyeditor_plugin.cpp @@ -72,8 +72,9 @@ void BuddyEditorPlugin::initialize(QDesignerFormEditorInterface *core) m_action = new QAction(tr("Edit Buddies"), this); m_action->setObjectName(QLatin1String("__qt_edit_buddies_action")); - m_action->setIcon(QIcon(core->resourceLocation() + QLatin1String("/buddytool.png"))); - m_action->setIcon(QIcon(core->resourceLocation() + QLatin1String("/buddytool.png"))); + QIcon buddyIcon = QIcon::fromTheme("designer-edit-buddy", + QIcon(core->resourceLocation() + QLatin1String("/buddytool.png"))); + m_action->setIcon(buddyIcon); m_action->setEnabled(false); setParent(core); diff --git a/tools/designer/src/components/formeditor/formwindowmanager.cpp b/tools/designer/src/components/formeditor/formwindowmanager.cpp index 993bae905..a2a0a4053 100644 --- a/tools/designer/src/components/formeditor/formwindowmanager.cpp +++ b/tools/designer/src/components/formeditor/formwindowmanager.cpp @@ -443,7 +443,8 @@ void FormWindowManager::setupActions() m_actionVerticalLayout->setEnabled(false); connect(m_actionVerticalLayout, SIGNAL(triggered()), this, SLOT(createLayout())); - QAction *actionFormLayout = new QAction(createIconSet(QLatin1String("editform.png")), tr("Lay Out in a &Form Layout"), this); + QIcon formIcon = QIcon::fromTheme("designer-form-layout", createIconSet(QLatin1String("editform.png"))); + QAction *actionFormLayout = new QAction(formIcon, tr("Lay Out in a &Form Layout"), this); actionFormLayout->setObjectName(QLatin1String("__qt_form_layout_action")); actionFormLayout->setShortcut(Qt::CTRL + Qt::Key_6); actionFormLayout->setStatusTip(tr("Lays out the selected widgets in a form layout")); @@ -510,15 +511,30 @@ void FormWindowManager::setupActions() m_actionUndo = m_undoGroup->createUndoAction(this); m_actionUndo->setEnabled(false); - m_actionUndo->setIcon(createIconSet(QLatin1String("undo.png"))); + + m_actionUndo->setIcon(QIcon::fromTheme("edit-undo", createIconSet(QLatin1String("undo.png")))); m_actionRedo = m_undoGroup->createRedoAction(this); m_actionRedo->setEnabled(false); - m_actionRedo->setIcon(createIconSet(QLatin1String("redo.png"))); + m_actionRedo->setIcon(QIcon::fromTheme("edit-redo", createIconSet(QLatin1String("redo.png")))); m_actionShowFormWindowSettingsDialog = new QAction(tr("Form &Settings..."), this); m_actionShowFormWindowSettingsDialog->setObjectName(QLatin1String("__qt_form_settings_action")); connect(m_actionShowFormWindowSettingsDialog, SIGNAL(triggered()), this, SLOT(slotActionShowFormWindowSettingsDialog())); m_actionShowFormWindowSettingsDialog->setEnabled(false); + + + m_actionCopy->setIcon(QIcon::fromTheme("edit-copy", m_actionCopy->icon())); + m_actionCut->setIcon(QIcon::fromTheme("edit-cut", m_actionCut->icon())); + m_actionPaste->setIcon(QIcon::fromTheme("edit-paste", m_actionPaste->icon())); + + // These do not currently exist, but will allow theme authors to fill in the gaps + m_actionBreakLayout->setIcon(QIcon::fromTheme("designer-break-layout", m_actionBreakLayout->icon())); + m_actionGridLayout->setIcon(QIcon::fromTheme("designer-grid-layout", m_actionGridLayout->icon())); + m_actionHorizontalLayout->setIcon(QIcon::fromTheme("designer-horizontal-layout", m_actionHorizontalLayout->icon())); + m_actionVerticalLayout->setIcon(QIcon::fromTheme("designer-vertical-layout", m_actionVerticalLayout->icon())); + m_actionSplitHorizontal->setIcon(QIcon::fromTheme("designer-split-horizontal", m_actionSplitHorizontal->icon())); + m_actionSplitVertical->setIcon(QIcon::fromTheme("designer-split-vertical", m_actionSplitVertical->icon())); + m_actionAdjustSize->setIcon(QIcon::fromTheme("designer-adjust-size", m_actionAdjustSize->icon())); } void FormWindowManager::slotActionCutActivated() diff --git a/tools/designer/src/components/signalsloteditor/signalsloteditor_plugin.cpp b/tools/designer/src/components/signalsloteditor/signalsloteditor_plugin.cpp index e664ae7cf..a1130410f 100644 --- a/tools/designer/src/components/signalsloteditor/signalsloteditor_plugin.cpp +++ b/tools/designer/src/components/signalsloteditor/signalsloteditor_plugin.cpp @@ -72,7 +72,8 @@ void SignalSlotEditorPlugin::initialize(QDesignerFormEditorInterface *core) m_action = new QAction(tr("Edit Signals/Slots"), this); m_action->setObjectName(QLatin1String("__qt_edit_signals_slots_action")); m_action->setShortcut(tr("F4")); - QIcon icon(QIcon(core->resourceLocation() + QLatin1String("/signalslottool.png"))); + QIcon icon = QIcon::fromTheme("designer-edit-signals", + QIcon(core->resourceLocation() + QLatin1String("/signalslottool.png"))); m_action->setIcon(icon); m_action->setEnabled(false); diff --git a/tools/designer/src/components/tabordereditor/tabordereditor_plugin.cpp b/tools/designer/src/components/tabordereditor/tabordereditor_plugin.cpp index 9b051c9b9..ddddd083f 100644 --- a/tools/designer/src/components/tabordereditor/tabordereditor_plugin.cpp +++ b/tools/designer/src/components/tabordereditor/tabordereditor_plugin.cpp @@ -72,7 +72,9 @@ void TabOrderEditorPlugin::initialize(QDesignerFormEditorInterface *core) m_action = new QAction(tr("Edit Tab Order"), this); m_action->setObjectName(QLatin1String("_qt_edit_tab_order_action")); - m_action->setIcon(QIcon(core->resourceLocation() + QLatin1String("/tabordertool.png"))); + QIcon icon = QIcon::fromTheme("designer-edit-tabs", + QIcon(core->resourceLocation() + QLatin1String("/tabordertool.png"))); + m_action->setIcon(icon); m_action->setEnabled(false); setParent(core); diff --git a/tools/designer/src/designer/qdesigner_actions.cpp b/tools/designer/src/designer/qdesigner_actions.cpp index c671386f8..567a13ea9 100644 --- a/tools/designer/src/designer/qdesigner_actions.cpp +++ b/tools/designer/src/designer/qdesigner_actions.cpp @@ -200,6 +200,10 @@ QDesignerActions::QDesignerActions(QDesignerWorkbench *workbench) #endif m_previewManager(0) { + m_newFormAction->setIcon(QIcon::fromTheme("document-new", m_newFormAction->icon())); + m_openFormAction->setIcon(QIcon::fromTheme("document-open", m_openFormAction->icon())); + m_saveFormAction->setIcon(QIcon::fromTheme("document-save", m_saveFormAction->icon())); + Q_ASSERT(m_core != 0); qdesigner_internal::QDesignerFormWindowManager *ifwm = qobject_cast(m_core->formWindowManager()); Q_ASSERT(ifwm); @@ -323,7 +327,8 @@ QDesignerActions::QDesignerActions(QDesignerWorkbench *workbench) shortcuts.append(QKeySequence(Qt::Key_Escape)); #endif m_editWidgetsAction->setShortcuts(shortcuts); - m_editWidgetsAction->setIcon(QIcon(m_core->resourceLocation() + QLatin1String("/widgettool.png"))); + QIcon fallback(m_core->resourceLocation() + QLatin1String("/widgettool.png")); + m_editWidgetsAction->setIcon(QIcon::fromTheme("designer-edit-widget", fallback)); connect(m_editWidgetsAction, SIGNAL(triggered()), this, SLOT(editWidgetsSlot())); m_editWidgetsAction->setChecked(true); m_editWidgetsAction->setEnabled(false); diff --git a/tools/designer/src/lib/shared/actioneditor.cpp b/tools/designer/src/lib/shared/actioneditor.cpp index 1a236d6bd..a931b8aaf 100644 --- a/tools/designer/src/lib/shared/actioneditor.cpp +++ b/tools/designer/src/lib/shared/actioneditor.cpp @@ -147,7 +147,8 @@ ActionEditor::ActionEditor(QDesignerFormEditorInterface *core, QWidget *parent, toolbar->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); l->addWidget(toolbar); // edit actions - m_actionNew->setIcon(createIconSet(QLatin1String("filenew.png"))); + QIcon documentNewIcon = QIcon::fromTheme("document-new", createIconSet(QLatin1String("filenew.png"))); + m_actionNew->setIcon(documentNewIcon); m_actionNew->setEnabled(false); connect(m_actionNew, SIGNAL(triggered()), this, SLOT(slotNewAction())); toolbar->addAction(m_actionNew); @@ -156,15 +157,18 @@ ActionEditor::ActionEditor(QDesignerFormEditorInterface *core, QWidget *parent, m_actionCut->setEnabled(false); connect(m_actionCut, SIGNAL(triggered()), this, SLOT(slotCut())); - m_actionCut->setIcon(createIconSet(QLatin1String("editcut.png"))); + QIcon editCutIcon = QIcon::fromTheme("edit-cut", createIconSet(QLatin1String("editcut.png"))); + m_actionCut->setIcon(editCutIcon); m_actionCopy->setEnabled(false); connect(m_actionCopy, SIGNAL(triggered()), this, SLOT(slotCopy())); - m_actionCopy->setIcon(createIconSet(QLatin1String("editcopy.png"))); + QIcon editCopyIcon = QIcon::fromTheme("edit-copy", createIconSet(QLatin1String("editcopy.png"))); + m_actionCopy->setIcon(editCopyIcon); toolbar->addAction(m_actionCopy); connect(m_actionPaste, SIGNAL(triggered()), this, SLOT(slotPaste())); - m_actionPaste->setIcon(createIconSet(QLatin1String("editpaste.png"))); + QIcon editPasteIcon = QIcon::fromTheme("edit-paste", createIconSet(QLatin1String("editpaste.png"))); + m_actionPaste->setIcon(editPasteIcon); toolbar->addAction(m_actionPaste); m_actionEdit->setEnabled(false); @@ -172,7 +176,8 @@ ActionEditor::ActionEditor(QDesignerFormEditorInterface *core, QWidget *parent, connect(m_actionNavigateToSlot, SIGNAL(triggered()), this, SLOT(navigateToSlotCurrentAction())); - m_actionDelete->setIcon(createIconSet(QLatin1String("editdelete.png"))); + QIcon editDeleteIcon = QIcon::fromTheme("edit-delete", createIconSet(QLatin1String("editdelete.png"))); + m_actionDelete->setIcon(editDeleteIcon); m_actionDelete->setEnabled(false); connect(m_actionDelete, SIGNAL(triggered()), this, SLOT(slotDelete())); toolbar->addAction(m_actionDelete); @@ -243,7 +248,8 @@ QToolButton *ActionEditor::createConfigureMenuButton(const QString &t, QMenu **p { QToolButton *configureButton = new QToolButton; QAction *configureAction = new QAction(t, configureButton); - configureAction->setIcon(createIconSet(QLatin1String("configure.png"))); + QIcon configureIcon = QIcon::fromTheme("document-properties", createIconSet(QLatin1String("configure.png"))); + configureAction->setIcon(configureIcon); QMenu *configureMenu = new QMenu; configureAction->setMenu(configureMenu); configureButton->setDefaultAction(configureAction); diff --git a/tools/designer/src/lib/shared/qtresourceview.cpp b/tools/designer/src/lib/shared/qtresourceview.cpp index 40be3e60e..f55f7ae7b 100644 --- a/tools/designer/src/lib/shared/qtresourceview.cpp +++ b/tools/designer/src/lib/shared/qtresourceview.cpp @@ -582,17 +582,21 @@ QtResourceView::QtResourceView(QDesignerFormEditorInterface *core, QWidget *pare { d_ptr->q_ptr = this; - d_ptr->m_editResourcesAction = new QAction(qdesigner_internal::createIconSet(QLatin1String("edit.png")), tr("Edit Resources..."), this); + QIcon editIcon = QIcon::fromTheme("document-properties", qdesigner_internal::createIconSet(QLatin1String("edit.png"))); + d_ptr->m_editResourcesAction = new QAction(editIcon, tr("Edit Resources..."), this); d_ptr->m_toolBar->addAction(d_ptr->m_editResourcesAction); connect(d_ptr->m_editResourcesAction, SIGNAL(triggered()), this, SLOT(slotEditResources())); d_ptr->m_editResourcesAction->setEnabled(false); - d_ptr->m_reloadResourcesAction = new QAction(qdesigner_internal::createIconSet(QLatin1String("reload.png")), tr("Reload"), this); + QIcon refreshIcon = QIcon::fromTheme("view-refresh", qdesigner_internal::createIconSet(QLatin1String("reload.png"))); + d_ptr->m_reloadResourcesAction = new QAction(refreshIcon, tr("Reload"), this); + d_ptr->m_toolBar->addAction(d_ptr->m_reloadResourcesAction); connect(d_ptr->m_reloadResourcesAction, SIGNAL(triggered()), this, SLOT(slotReloadResources())); d_ptr->m_reloadResourcesAction->setEnabled(false); - d_ptr->m_copyResourcePathAction = new QAction(qdesigner_internal::createIconSet(QLatin1String("editcopy.png")), tr("Copy Path"), this); + QIcon copyIcon = QIcon::fromTheme("edit-copy", qdesigner_internal::createIconSet(QLatin1String("editcopy.png"))); + d_ptr->m_copyResourcePathAction = new QAction(copyIcon, tr("Copy Path"), this); connect(d_ptr->m_copyResourcePathAction, SIGNAL(triggered()), this, SLOT(slotCopyResourcePath())); d_ptr->m_copyResourcePathAction->setEnabled(false); -- cgit v1.2.3 From f9605d3f396043e5b893470acaeb4c726361e9dc Mon Sep 17 00:00:00 2001 From: Jens Bache-Wiig Date: Mon, 10 Aug 2009 18:19:53 +0200 Subject: Make QGtkStyle react properly to font changes in GNOME We only reacted to font changes before when the whole theme changed. Two things had to be fixed to support this. We need to check if the font changed in QGtkStyle::updateTheme and we need to make sure that QApplication does not reset these settings for us. Reviewed-by: joao --- src/gui/kernel/qapplication_x11.cpp | 36 ++++++++++++++++++++---------------- src/gui/styles/gtksymbols.cpp | 6 +++++- src/gui/styles/qgtkstyle.cpp | 2 +- 3 files changed, 26 insertions(+), 18 deletions(-) diff --git a/src/gui/kernel/qapplication_x11.cpp b/src/gui/kernel/qapplication_x11.cpp index 221101a82..470b43313 100644 --- a/src/gui/kernel/qapplication_x11.cpp +++ b/src/gui/kernel/qapplication_x11.cpp @@ -871,28 +871,32 @@ bool QApplicationPrivate::x11_apply_settings() } // ### Fix properly for 4.6 - if (!(QApplicationPrivate::app_style && QApplicationPrivate::app_style->inherits("QGtkStyle"))) { + bool usingGtkSettings = QApplicationPrivate::app_style && QApplicationPrivate::app_style->inherits("QGtkStyle"); + if (!usingGtkSettings) { if (groupCount == QPalette::NColorGroups) QApplicationPrivate::setSystemPalette(pal); } if (!appFont) { - QFont font(QApplication::font()); - QString fontDescription; - // Override Qt font if KDE4 settings can be used - if (X11->desktopEnvironment == DE_KDE && X11->desktopVersion >= 4) { - QSettings kdeSettings(QKde::kdeHome() + QLatin1String("/share/config/kdeglobals"), QSettings::IniFormat); - fontDescription = kdeSettings.value(QLatin1String("font")).toString(); - if (fontDescription.isEmpty()) { - // KDE stores fonts without quotes - fontDescription = kdeSettings.value(QLatin1String("font")).toStringList().join(QLatin1String(",")); + // ### Fix properly for 4.6 + if (!usingGtkSettings) { + QFont font(QApplication::font()); + QString fontDescription; + // Override Qt font if KDE4 settings can be used + if (X11->desktopVersion == 4) { + QSettings kdeSettings(QKde::kdeHome() + QLatin1String("/share/config/kdeglobals"), QSettings::IniFormat); + fontDescription = kdeSettings.value(QLatin1String("font")).toString(); + if (fontDescription.isEmpty()) { + // KDE stores fonts without quotes + fontDescription = kdeSettings.value(QLatin1String("font")).toStringList().join(QLatin1String(",")); + } + } + if (fontDescription.isEmpty()) + fontDescription = settings.value(QLatin1String("font")).toString(); + if (!fontDescription .isEmpty()) { + font.fromString(fontDescription ); + QApplicationPrivate::setSystemFont(font); } - } - if (fontDescription.isEmpty()) - fontDescription = settings.value(QLatin1String("font")).toString(); - if (!fontDescription .isEmpty()) { - font.fromString(fontDescription ); - QApplicationPrivate::setSystemFont(font); } } diff --git a/src/gui/styles/gtksymbols.cpp b/src/gui/styles/gtksymbols.cpp index c8b4fda47..2d8d6e282 100644 --- a/src/gui/styles/gtksymbols.cpp +++ b/src/gui/styles/gtksymbols.cpp @@ -547,9 +547,13 @@ void QGtkStyleUpdateScheduler::updateTheme() { static QString oldTheme(QLS("qt_not_set")); QPixmapCache::clear(); + + QFont font = QGtk::getThemeFont(); + if (QApplication::font() != font) + qApp->setFont(font); + if (oldTheme != getThemeName()) { oldTheme = getThemeName(); - qApp->setFont(QGtk::getThemeFont()); QPalette newPalette = qApp->style()->standardPalette(); QApplicationPrivate::setSystemPalette(newPalette); QApplication::setPalette(newPalette); diff --git a/src/gui/styles/qgtkstyle.cpp b/src/gui/styles/qgtkstyle.cpp index f6d8c889d..5f562305f 100644 --- a/src/gui/styles/qgtkstyle.cpp +++ b/src/gui/styles/qgtkstyle.cpp @@ -1,4 +1,4 @@ -/******* ********************************************************************* +/**************************************************************************** ** ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** Contact: Nokia Corporation (qt-info@nokia.com) -- cgit v1.2.3 From 4096911423fcd52c59d83f153b3a83ae99312a70 Mon Sep 17 00:00:00 2001 From: Benjamin Poulain Date: Mon, 10 Aug 2009 19:23:04 +0200 Subject: Add a Widget for manual testing of the tablet API The QTabletWidget shows the informations provided by the last QTabletEvent. --- tests/manual/qtabletevent/main.cpp | 9 ++ tests/manual/qtabletevent/qtabletevent.pro | 13 +++ tests/manual/qtabletevent/tabletwidget.cpp | 150 +++++++++++++++++++++++++++++ tests/manual/qtabletevent/tabletwidget.h | 32 ++++++ 4 files changed, 204 insertions(+) create mode 100644 tests/manual/qtabletevent/main.cpp create mode 100644 tests/manual/qtabletevent/qtabletevent.pro create mode 100644 tests/manual/qtabletevent/tabletwidget.cpp create mode 100644 tests/manual/qtabletevent/tabletwidget.h diff --git a/tests/manual/qtabletevent/main.cpp b/tests/manual/qtabletevent/main.cpp new file mode 100644 index 000000000..4014d580c --- /dev/null +++ b/tests/manual/qtabletevent/main.cpp @@ -0,0 +1,9 @@ +#include +#include "tabletwidget.h" + +int main(int argc, char **argv) { + QApplication app(argc, argv); + TabletWidget tabletWidget; + tabletWidget.showMaximized(); + return app.exec(); +} diff --git a/tests/manual/qtabletevent/qtabletevent.pro b/tests/manual/qtabletevent/qtabletevent.pro new file mode 100644 index 000000000..e0ed54900 --- /dev/null +++ b/tests/manual/qtabletevent/qtabletevent.pro @@ -0,0 +1,13 @@ +###################################################################### +# Automatically generated by qmake (2.01a) Mon Aug 10 17:02:09 2009 +###################################################################### + +TEMPLATE = app +TARGET = +DEPENDPATH += . +INCLUDEPATH += . + +# Input +SOURCES += main.cpp\ + tabletwidget.cpp +HEADERS += tabletwidget.h diff --git a/tests/manual/qtabletevent/tabletwidget.cpp b/tests/manual/qtabletevent/tabletwidget.cpp new file mode 100644 index 000000000..4d6a36524 --- /dev/null +++ b/tests/manual/qtabletevent/tabletwidget.cpp @@ -0,0 +1,150 @@ +#include "tabletwidget.h" +#include +#include + +TabletWidget::TabletWidget() +{ + QPalette newPalette = palette(); + newPalette.setColor(QPalette::Window, Qt::white); + setPalette(newPalette); + qApp->installEventFilter(this); + resetAttributes(); +} + +bool TabletWidget::eventFilter(QObject *, QEvent *ev) +{ + switch (ev->type()) { + case QEvent::TabletEnterProximity: + case QEvent::TabletLeaveProximity: + case QEvent::TabletMove: + case QEvent::TabletPress: + case QEvent::TabletRelease: + { + QTabletEvent *event = static_cast(ev); + mType = event->type(); + mPos = event->pos(); + mGPos = event->globalPos(); + mHiResGlobalPos = event->hiResGlobalPos(); + mDev = event->device(); + mPointerType = event->pointerType(); + mUnique = event->uniqueId(); + mXT = event->xTilt(); + mYT = event->yTilt(); + mZ = event->z(); + mPress = event->pressure(); + mTangential = event->tangentialPressure(); + mRot = event->rotation(); + if (isVisible()) + update(); + break; + } + case QEvent::MouseMove: + { + resetAttributes(); + QMouseEvent *event = static_cast(ev); + mType = event->type(); + mPos = event->pos(); + mGPos = event->globalPos(); + } + default: + break; + } + return false; +} + +void TabletWidget::paintEvent(QPaintEvent *event) +{ + QPainter painter(this); + + QStringList eventInfo; + + QString typeString("Event type: "); + switch (mType) { + case QEvent::TabletEnterProximity: + typeString += "QEvent::TabletEnterProximity"; + break; + case QEvent::TabletLeaveProximity: + typeString += "QEvent::TabletLeaveProximity"; + break; + case QEvent::TabletMove: + typeString += "QEvent::TabletMove"; + break; + case QEvent::TabletPress: + typeString += "QEvent::TabletPress"; + break; + case QEvent::TabletRelease: + typeString += "QEvent::TabletRelease"; + break; + case QEvent::MouseMove: + typeString += "QEvent::MouseMove"; + break; + } + eventInfo << typeString; + + eventInfo << QString("Global position: %1 %2").arg(QString::number(mGPos.x()), QString::number(mGPos.y())); + eventInfo << QString("Local position: %1 %2").arg(QString::number(mPos.x()), QString::number(mPos.y())); + if (mType == QEvent::TabletEnterProximity || mType == QEvent::TabletLeaveProximity + || mType == QEvent::TabletMove || mType == QEvent::TabletPress + || mType == QEvent::TabletRelease) { + + eventInfo << QString("Hight res global position: %1 %2").arg(QString::number(mHiResGlobalPos.x()), QString::number(mHiResGlobalPos.y())); + + QString pointerType("Pointer type: "); + switch (mPointerType) { + case QTabletEvent::UnknownPointer: + pointerType += "QTabletEvent::UnknownPointer"; + break; + case QTabletEvent::Pen: + pointerType += "QTabletEvent::Pen"; + break; + case QTabletEvent::Cursor: + pointerType += "QTabletEvent::Cursor"; + break; + case QTabletEvent::Eraser: + pointerType += "QTabletEvent::Eraser"; + break; + } + eventInfo << pointerType; + + + QString deviceString = "Device type: "; + switch (mDev) { + case QTabletEvent::NoDevice: + deviceString += "QTabletEvent::NoDevice"; + break; + case QTabletEvent::Puck: + deviceString += "QTabletEvent::Puck"; + break; + case QTabletEvent::Stylus: + deviceString += "QTabletEvent::Stylus"; + break; + case QTabletEvent::Airbrush: + deviceString += "QTabletEvent::Airbrush"; + break; + case QTabletEvent::FourDMouse: + deviceString += "QTabletEvent::FourDMouse"; + break; + case QTabletEvent::RotationStylus: + deviceString += "QTabletEvent::RotationStylus"; + break; + } + eventInfo << deviceString; + + eventInfo << QString("Pressure: %1").arg(QString::number(mPress)); + eventInfo << QString("Tangential pressure: %1").arg(QString::number(mTangential)); + eventInfo << QString("Rotation: %1").arg(QString::number(mRot)); + eventInfo << QString("xTilt: %1").arg(QString::number(mXT)); + eventInfo << QString("yTilt: %1").arg(QString::number(mYT)); + eventInfo << QString("z: %1").arg(QString::number(mZ)); + + eventInfo << QString("Unique Id: %1").arg(QString::number(mUnique)); + } + + painter.drawText(rect(), eventInfo.join("\n")); +} + +void TabletWidget::tabletEvent(QTabletEvent *event) +{ + event->accept(); +} + diff --git a/tests/manual/qtabletevent/tabletwidget.h b/tests/manual/qtabletevent/tabletwidget.h new file mode 100644 index 000000000..b0efef218 --- /dev/null +++ b/tests/manual/qtabletevent/tabletwidget.h @@ -0,0 +1,32 @@ +#ifndef TABLETWIDGET_H +#define TABLETWIDGET_H + +#include +#include + +// a widget showing the information of the last tablet event +class TabletWidget : public QWidget +{ +public: + TabletWidget(); +protected: + bool eventFilter(QObject *obj, QEvent *ev); + void tabletEvent(QTabletEvent *event); + void paintEvent(QPaintEvent *event); +private: + void resetAttributes() { + mType = mDev = mPointerType = mXT = mYT = mZ = 0; + mPress = mTangential = mRot = 0.0; + mPos = mGPos = QPoint(); + mHiResGlobalPos = QPointF(); + mUnique = 0; + } + int mType; + QPoint mPos, mGPos; + QPointF mHiResGlobalPos; + int mDev, mPointerType, mXT, mYT, mZ; + qreal mPress, mTangential, mRot; + qint64 mUnique; +}; + +#endif // TABLETWIDGET_H -- cgit v1.2.3 From dd9d869300d34725bc480d827f91b3103c84f045 Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Mon, 10 Aug 2009 19:50:01 +0200 Subject: fixing the Windows CE build after adding gesture support We must guard the code with QT_WINCE_GESTURES. Reviewed-by: TrustMe --- src/gui/kernel/qapplication_win.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/gui/kernel/qapplication_win.cpp b/src/gui/kernel/qapplication_win.cpp index bb910b70e..a0142e164 100644 --- a/src/gui/kernel/qapplication_win.cpp +++ b/src/gui/kernel/qapplication_win.cpp @@ -816,13 +816,13 @@ void qt_init(QApplicationPrivate *priv, int) priv->GetGestureInfo = 0; priv->GetGestureExtraArgs = 0; -#ifdef Q_WS_WINCE_WM +#if defined(Q_WS_WINCE_WM) && defined(QT_WINCE_GESTURES) priv->GetGestureInfo = (PtrGetGestureInfo) &TKGetGestureInfo; priv->GetGestureExtraArgs = (PtrGetGestureExtraArgs) &TKGetGestureExtraArguments; priv->CloseGestureInfoHandle = (PtrCloseGestureInfoHandle) 0; priv->SetGestureConfig = (PtrSetGestureConfig) 0; priv->GetGestureConfig = (PtrGetGestureConfig) 0; -#else +#elif !defined(Q_WS_WINCE) priv->GetGestureInfo = (PtrGetGestureInfo)QLibrary::resolve(QLatin1String("user32"), "GetGestureInfo"); @@ -1252,7 +1252,10 @@ void QApplication::beep() static void alert_widget(QWidget *widget, int duration) { -#ifndef Q_OS_WINCE +#ifdef Q_OS_WINCE + Q_UNUSED(widget); + Q_UNUSED(duration); +#else bool stopFlash = duration < 0; if (widget && (!widget->isActiveWindow() || stopFlash)) { @@ -3729,10 +3732,14 @@ bool QETWidget::translateGestureEvent(const MSG &msg) gi.cbSize = sizeof(GESTUREINFO); QApplicationPrivate *qAppPriv = QApplicationPrivate::instance(); -#ifdef Q_WS_WINCE_WM +#if defined(Q_WS_WINCE_WM) && defined(QT_WINCE_GESTURES) +#undef GID_ZOOM #define GID_ZOOM 0xf000 +#undef GID_ROTATE #define GID_ROTATE 0xf001 +#undef GID_TWOFINGERTAP #define GID_TWOFINGERTAP 0xf002 +#undef GID_ROLLOVER #define GID_ROLLOVER 0xf003 #endif BOOL bResult = false; -- cgit v1.2.3 From 36c93eca351218ce43a0c6346209d364737b6b84 Mon Sep 17 00:00:00 2001 From: Gabriel de Dietrich Date: Mon, 10 Aug 2009 20:46:16 +0200 Subject: Better implementation for commit d13418effc5f00474541ae513a30c9a42c2a1cb3. The previous version could run in an endless loop with infinite models. Reviewed-by: olivier --- src/gui/itemviews/qitemselectionmodel.cpp | 60 +++++++++++++--------- src/gui/itemviews/qitemselectionmodel_p.h | 2 - .../tst_qitemselectionmodel.cpp | 30 +++++++++++ 3 files changed, 66 insertions(+), 26 deletions(-) diff --git a/src/gui/itemviews/qitemselectionmodel.cpp b/src/gui/itemviews/qitemselectionmodel.cpp index 0f35ac1df..06c345f0e 100644 --- a/src/gui/itemviews/qitemselectionmodel.cpp +++ b/src/gui/itemviews/qitemselectionmodel.cpp @@ -590,31 +590,43 @@ void QItemSelectionModelPrivate::_q_rowsAboutToBeRemoved(const QModelIndex &pare emit q->currentColumnChanged(currentIndex, old); } - // update selectionsx - QModelIndex tl = model->index(start, 0, parent); - QModelIndex br = model->index(end, model->columnCount(parent) - 1, parent); - recursiveDeselect(QItemSelectionRange(tl, br)); - finalize(); -} - -void QItemSelectionModelPrivate::recursiveDeselect(const QItemSelectionRange &range) -{ - Q_Q(QItemSelectionModel); - - QItemSelection sel(range.topLeft(), range.bottomRight()); - q->select(sel, QItemSelectionModel::Deselect); - - QModelIndexList idxList = range.indexes(); - QModelIndexList::const_iterator it = idxList.begin(); - for (; it != idxList.end(); ++it) - { - if (!model->hasChildren(*it)) - continue; - - const QModelIndex &firstChild = it->child(0,0); - const QModelIndex &lastChild = it->child(model->rowCount(*it) - 1, model->columnCount(*it) - 1); - recursiveDeselect(QItemSelectionRange(firstChild, lastChild)); + QItemSelection deselected; + QItemSelection::iterator it = currentSelection.begin(); + while (it != currentSelection.end()) { + if (it->topLeft().parent() != parent) { // Check parents until reaching root or contained in range + QModelIndex itParent = it->topLeft().parent(); + while (itParent.isValid() && itParent.parent() != parent) + itParent = itParent.parent(); + + if (parent.isValid() && start <= itParent.row() && itParent.row() <= end) { + deselected.append(*it); + it = currentSelection.erase(it); + } else { + ++it; + } + } else if (start <= it->bottom() && it->bottom() <= end // Full inclusion + && start <= it->top() && it->top() <= end) { + deselected.append(*it); + it = currentSelection.erase(it); + } else if (start <= it->top() && it->top() <= end) { // Top intersection + deselected.append(QItemSelectionRange(it->topLeft(), model->index(end, it->left(), it->parent()))); + it = currentSelection.insert(it, QItemSelectionRange(model->index(end + 1, it->left(), it->parent()), + it->bottomRight())); + it = currentSelection.erase(++it); + } else if (start <= it->bottom() && it->bottom() <= end) { // Bottom intersection + deselected.append(QItemSelectionRange(model->index(start, it->right(), it->parent()), it->bottomRight())); + it = currentSelection.insert(it, QItemSelectionRange(it->topLeft(), + model->index(start - 1, it->right(), it->parent()))); + it = currentSelection.erase(++it); + } else { + if (it->top() < start && end < it->bottom()) // Middle intersection (do nothing) + deselected.append(QItemSelectionRange(model->index(start, it->right(), it->parent()), + model->index(end, it->left(), it->parent()))); + ++it; + } } + + emit q->selectionChanged(QItemSelection(), deselected); } /*! diff --git a/src/gui/itemviews/qitemselectionmodel_p.h b/src/gui/itemviews/qitemselectionmodel_p.h index 8176d4c0e..18ad506dc 100644 --- a/src/gui/itemviews/qitemselectionmodel_p.h +++ b/src/gui/itemviews/qitemselectionmodel_p.h @@ -77,8 +77,6 @@ public: void _q_layoutAboutToBeChanged(); void _q_layoutChanged(); - void recursiveDeselect(const QItemSelectionRange &range); - inline void remove(QList &r) { QList::const_iterator it = r.constBegin(); diff --git a/tests/auto/qitemselectionmodel/tst_qitemselectionmodel.cpp b/tests/auto/qitemselectionmodel/tst_qitemselectionmodel.cpp index 05e23f196..ec21f79eb 100644 --- a/tests/auto/qitemselectionmodel/tst_qitemselectionmodel.cpp +++ b/tests/auto/qitemselectionmodel/tst_qitemselectionmodel.cpp @@ -2209,6 +2209,36 @@ void tst_QItemSelectionModel::task232634_childrenDeselectionSignal() QSignalSpy deselectSpy(&selectionModel, SIGNAL(selectionChanged(const QItemSelection& , const QItemSelection&))); model.removeRows(0, 1, root); QVERIFY(deselectSpy.count() == 1); + + // More testing stress for the patch. + model.clear(); + selectionModel.clear(); + + parentItem = model.invisibleRootItem(); + for (int i = 0; i < 2; ++i) { + QStandardItem *item = new QStandardItem(QString("item %0").arg(i)); + parentItem->appendRow(item); + } + for (int i = 0; i < 2; ++i) { + parentItem = model.invisibleRootItem()->child(i, 0); + for (int j = 0; j < 2; ++j) { + QStandardItem *item = new QStandardItem(QString("item %0.%1").arg(i).arg(j)); + parentItem->appendRow(item); + } + } + + sel = model.index(0, 0).child(0, 0); + selectionModel.select(sel, QItemSelectionModel::Select); + QModelIndex sel2 = model.index(1, 0).child(0, 0); + selectionModel.select(sel2, QItemSelectionModel::Select); + + QVERIFY(selectionModel.selection().contains(sel)); + QVERIFY(selectionModel.selection().contains(sel2)); + deselectSpy.clear(); + model.removeRow(0, model.index(0, 0)); + QVERIFY(deselectSpy.count() == 1); + QVERIFY(!selectionModel.selection().contains(sel)); + QVERIFY(selectionModel.selection().contains(sel2)); } QTEST_MAIN(tst_QItemSelectionModel) -- cgit v1.2.3 From a675f83543d9a8bb61cb5f5227c6793ae343cc80 Mon Sep 17 00:00:00 2001 From: Volker Hilsheimer Date: Mon, 10 Aug 2009 21:51:31 +0200 Subject: Doc: Fix links and qdoc warnings. --- src/gui/image/qicon.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/gui/image/qicon.cpp b/src/gui/image/qicon.cpp index 7a435140e..b7759e46d 100644 --- a/src/gui/image/qicon.cpp +++ b/src/gui/image/qicon.cpp @@ -870,7 +870,7 @@ QList QIcon::availableSizes(Mode mode, State state) const /*! \since 4.6 - Sets the search paths for icon themes. + Sets the search paths for icon themes to \a paths. \sa themeSearchPaths(), fromTheme() */ void QIcon::setThemeSearchPaths(const QStringList &paths) @@ -893,7 +893,7 @@ void QIcon::setThemeSearchPaths(const QStringList &paths) On Mac the default search path will search in the [Contents/Resources/icons] part of the application bundle. - \sa setThemeSearchPaths(), fromName() + \sa setThemeSearchPaths(), fromTheme() */ QStringList QIcon::themeSearchPaths() { @@ -923,7 +923,7 @@ void QIcon::setThemeName(const QString &path) On X11, the current icon theme depends on your desktop settings. On other platforms it is not set by default. - \sa themeSearchPaths(), themeIcon(), fromTheme(), hasThemeIcon() + \sa themeSearchPaths(), fromTheme(), hasThemeIcon() */ QString QIcon::themeName() { -- cgit v1.2.3 From 6c3c9d812a730d5bc1bcd6261befe077a65be594 Mon Sep 17 00:00:00 2001 From: Bill King Date: Tue, 11 Aug 2009 08:23:30 +1000 Subject: Fixes coverity warning of uninit variable. --- src/sql/drivers/psql/qsql_psql.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sql/drivers/psql/qsql_psql.cpp b/src/sql/drivers/psql/qsql_psql.cpp index 4fd0c11f4..fccc62232 100644 --- a/src/sql/drivers/psql/qsql_psql.cpp +++ b/src/sql/drivers/psql/qsql_psql.cpp @@ -158,7 +158,7 @@ void QPSQLDriverPrivate::appendTables(QStringList &tl, QSqlQuery &t, QChar type) class QPSQLResultPrivate { public: - QPSQLResultPrivate(QPSQLResult *qq): q(qq), driver(0), result(0), currentSize(-1) {} + QPSQLResultPrivate(QPSQLResult *qq): q(qq), driver(0), result(0), currentSize(-1), preparedQueriesEnabled(false) {} QPSQLResult *q; const QPSQLDriverPrivate *driver; -- cgit v1.2.3