From 933e74473a23c0090eaaae9c6122a0e0d192df15 Mon Sep 17 00:00:00 2001 From: Caio Marcelo de Oliveira Filho Date: Tue, 22 Sep 2009 16:24:07 -0300 Subject: QGraphicsAnchorLayout: add autotests for QSizePolicy::ExpandFlag Add autotests that use the ExpandFlag via QSizePolicy::Expanding policy. Those tests cover the simple cases and behaviours with sequential and parallel anchor setups. Signed-off-by: Caio Marcelo de Oliveira Filho Reviewed-by: Jesus Sanchez-Palencia --- .../tst_qgraphicsanchorlayout.cpp | 214 +++++++++++++++++++++ 1 file changed, 214 insertions(+) diff --git a/tests/auto/qgraphicsanchorlayout/tst_qgraphicsanchorlayout.cpp b/tests/auto/qgraphicsanchorlayout/tst_qgraphicsanchorlayout.cpp index 9f13aca..e898edb 100644 --- a/tests/auto/qgraphicsanchorlayout/tst_qgraphicsanchorlayout.cpp +++ b/tests/auto/qgraphicsanchorlayout/tst_qgraphicsanchorlayout.cpp @@ -69,6 +69,9 @@ private slots: void delete_anchor(); void conflicts(); void sizePolicy(); + void expandingSequence(); + void expandingSequenceFairDistribution(); + void expandingParallel(); }; class RectWidget : public QGraphicsWidget @@ -586,6 +589,20 @@ void tst_QGraphicsAnchorLayout::snake() QCOMPARE(b->geometry(), QRectF(90.0, 100.0, 10.0, 100.0)); QCOMPARE(c->geometry(), QRectF(90.0, 200.0, 100.0, 100.0)); QCOMPARE(p.size(), layoutMaximumSize); + + QVERIFY(layoutHasConflict(l) == false); + + // Test QSizePolicy::ExpandFlag, it shouldn't change the extreme + // points of the layout... + b->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); + + QSizeF newLayoutMinimumSize = l->effectiveSizeHint(Qt::MinimumSize); + QSizeF newLayoutMaximumSize = l->effectiveSizeHint(Qt::MaximumSize); + QSizeF newLayoutPreferredSize = l->effectiveSizeHint(Qt::PreferredSize); + + QCOMPARE(layoutMinimumSize, newLayoutMinimumSize); + QCOMPARE(layoutMaximumSize, newLayoutMaximumSize); + QCOMPARE(layoutPreferredSize, newLayoutPreferredSize); } void tst_QGraphicsAnchorLayout::snakeOppositeDirections() @@ -1308,5 +1325,202 @@ void tst_QGraphicsAnchorLayout::conflicts() delete p; } +void tst_QGraphicsAnchorLayout::expandingSequence() +{ + QSizeF min(10, 10); + QSizeF pref(50, 10); + QSizeF max(100, 10); + + QGraphicsWidget *a = createItem(min, pref, max, "a"); + QGraphicsWidget *b = createItem(min, pref, max, "b"); + + b->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); + + QGraphicsAnchorLayout *l = new QGraphicsAnchorLayout; + l->setContentsMargins(0, 0, 0, 0); + + // horizontal + setAnchor(l, l, Qt::AnchorLeft, a, Qt::AnchorLeft, 0); + setAnchor(l, a, Qt::AnchorRight, b, Qt::AnchorLeft, 0); + setAnchor(l, b, Qt::AnchorRight, l, Qt::AnchorRight, 0); + + // vertical + l->addAnchors(l, a, Qt::Vertical); + l->addAnchors(l, b, Qt::Vertical); + + QCOMPARE(l->count(), 2); + + QGraphicsWidget p; + p.setLayout(l); + + QSizeF layoutMinimumSize = l->effectiveSizeHint(Qt::MinimumSize); + QCOMPARE(layoutMinimumSize.width(), qreal(20)); + + QSizeF layoutExpandedSize(pref.width() + max.width(), layoutMinimumSize.height()); + p.resize(layoutExpandedSize); + + QEXPECT_FAIL("", "Support for QSizePolicy::ExpandFlag not yet available", Abort); + QCOMPARE(a->geometry().size(), pref); + QCOMPARE(b->geometry().size(), max); + + QSizeF layoutMaximumSize = l->effectiveSizeHint(Qt::MaximumSize); + QCOMPARE(layoutMaximumSize.width(), qreal(200)); +} + +void tst_QGraphicsAnchorLayout::expandingSequenceFairDistribution() +{ + QSizeF min(10, 10); + QSizeF pref(50, 10); + QSizeF max(100, 10); + + QGraphicsWidget *a = createItem(min, pref, max, "a"); + QGraphicsWidget *b = createItem(min, pref, max, "b"); + QGraphicsWidget *c = createItem(min, pref, max, "c"); + QGraphicsWidget *d = createItem(min, pref, max, "d"); + + b->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); + d->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); + + QGraphicsAnchorLayout *l = new QGraphicsAnchorLayout; + l->setContentsMargins(0, 0, 0, 0); + + // horizontal + setAnchor(l, l, Qt::AnchorLeft, a, Qt::AnchorLeft, 0); + setAnchor(l, a, Qt::AnchorRight, b, Qt::AnchorLeft, 0); + setAnchor(l, b, Qt::AnchorRight, c, Qt::AnchorLeft, 0); + setAnchor(l, c, Qt::AnchorRight, d, Qt::AnchorLeft, 0); + setAnchor(l, d, Qt::AnchorRight, l, Qt::AnchorRight, 0); + + // vertical + l->addAnchors(l, a, Qt::Vertical); + l->addAnchors(l, b, Qt::Vertical); + l->addAnchors(l, c, Qt::Vertical); + l->addAnchors(l, d, Qt::Vertical); + + QCOMPARE(l->count(), 4); + + QGraphicsWidget p; + p.setLayout(l); + + QSizeF layoutMinimumSize = l->effectiveSizeHint(Qt::MinimumSize); + QCOMPARE(layoutMinimumSize.width(), qreal(40)); + + QSizeF layoutPartialExpandedSize((2 * pref.width()) + (2 * (pref.width() + 10)), + layoutMinimumSize.height()); + p.resize(layoutPartialExpandedSize); + + QEXPECT_FAIL("", "Support for QSizePolicy::ExpandFlag not yet available", Abort); + QCOMPARE(a->geometry().size(), pref); + QCOMPARE(b->geometry().size(), pref + QSizeF(10, 0)); + QCOMPARE(c->geometry().size(), pref); + QCOMPARE(d->geometry().size(), pref + QSizeF(10, 0)); + + QSizeF layoutExpandedSize((2 * pref.width()) + (2 * max.width()), + layoutMinimumSize.height()); + p.resize(layoutExpandedSize); + + QCOMPARE(a->geometry().size(), pref); + QCOMPARE(b->geometry().size(), max); + QCOMPARE(c->geometry().size(), pref); + QCOMPARE(d->geometry().size(), max); + + QSizeF layoutMaximumSize = l->effectiveSizeHint(Qt::MaximumSize); + QCOMPARE(layoutMaximumSize.width(), qreal(400)); + + // Now we change D to have more "room for growth" from its preferred size + // to its maximum size. We expect a proportional fair distribution. Note that + // this seems to not conform with what QGraphicsLinearLayout does. + d->setMaximumSize(QSizeF(150, 10)); + + QSizeF newLayoutExpandedSize((2 * pref.width()) + (max.width() + 150), + layoutMinimumSize.height()); + p.resize(newLayoutExpandedSize); + + QCOMPARE(a->geometry().size(), pref); + QCOMPARE(b->geometry().size(), max); + QCOMPARE(c->geometry().size(), pref); + QCOMPARE(d->geometry().size(), QSizeF(150, 10)); + + QSizeF newLayoutPartialExpandedSize((4 * pref.width()) + 75, + layoutMinimumSize.height()); + + QCOMPARE(a->geometry().size(), pref); + QCOMPARE(b->geometry().size(), pref + QSizeF(25, 0)); + QCOMPARE(c->geometry().size(), pref); + QCOMPARE(d->geometry().size(), pref + QSizeF(50, 0)); +} + +void tst_QGraphicsAnchorLayout::expandingParallel() +{ + QSizeF min(10, 10); + QSizeF pref(50, 10); + QSizeF max(100, 50); + + QGraphicsWidget *a = createItem(min, pref, max, "a"); + QGraphicsWidget *b = createItem(min, pref, max, "b"); + QGraphicsWidget *c = createItem(min, pref, max, "c"); + + b->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); + + QGraphicsAnchorLayout *l = new QGraphicsAnchorLayout; + l->setContentsMargins(0, 0, 0, 0); + + // horizontal + setAnchor(l, l, Qt::AnchorLeft, a, Qt::AnchorLeft, 0); + setAnchor(l, l, Qt::AnchorLeft, b, Qt::AnchorLeft, 0); + + setAnchor(l, a, Qt::AnchorRight, c, Qt::AnchorLeft, 0); + setAnchor(l, b, Qt::AnchorRight, c, Qt::AnchorLeft, 0); + + setAnchor(l, c, Qt::AnchorRight, l, Qt::AnchorRight, 0); + + // vertical + l->addAnchors(l, c, Qt::Vertical); + setAnchor(l, l, Qt::AnchorTop, a, Qt::AnchorTop, 0); + setAnchor(l, a, Qt::AnchorBottom, c, Qt::AnchorVerticalCenter, 0); + setAnchor(l, b, Qt::AnchorTop, c, Qt::AnchorVerticalCenter, 0); + setAnchor(l, b, Qt::AnchorBottom, l, Qt::AnchorBottom, 0); + + QCOMPARE(l->count(), 3); + + QGraphicsWidget p; + p.setLayout(l); + + QSizeF layoutMinimumSize = l->effectiveSizeHint(Qt::MinimumSize); + QCOMPARE(layoutMinimumSize.width(), qreal(20)); + + QSizeF layoutExpandedSize(pref.width() + max.width(), layoutMinimumSize.height()); + p.resize(layoutExpandedSize); + + QEXPECT_FAIL("", "Support for QSizePolicy::ExpandFlag not yet available", Abort); + QCOMPARE(a->geometry().size(), max); + QCOMPARE(b->geometry().size(), max); + QCOMPARE(c->geometry().size(), pref); + + QSizeF layoutMaximumSize = l->effectiveSizeHint(Qt::MaximumSize); + QCOMPARE(layoutMaximumSize.width(), qreal(200)); + + // + // Change the parallel connection to a paralell connection of b with a center... + // + QGraphicsAnchor *anchor = l->anchor(b, Qt::AnchorRight, c, Qt::AnchorLeft); + delete anchor; + setAnchor(l, b, Qt::AnchorRight, a, Qt::AnchorHorizontalCenter, 0); + a->setMaximumSize(max + QSizeF(100, 0)); + + QSizeF newLayoutMinimumSize = l->effectiveSizeHint(Qt::MinimumSize); + QCOMPARE(newLayoutMinimumSize.width(), qreal(30)); + + QSizeF newLayoutExpandedSize(pref.width() + max.width(), layoutMinimumSize.height()); + p.resize(newLayoutExpandedSize); + + QCOMPARE(a->geometry().size(), max); + QCOMPARE(b->geometry().size(), max); + QCOMPARE(c->geometry().size(), pref); + + QSizeF newLayoutMaximumSize = l->effectiveSizeHint(Qt::MaximumSize); + QCOMPARE(newLayoutMaximumSize.width(), qreal(300)); +} + QTEST_MAIN(tst_QGraphicsAnchorLayout) #include "tst_qgraphicsanchorlayout.moc" -- cgit v0.12 From bfc1a75616e1c96a018349084fae844d7efbc177 Mon Sep 17 00:00:00 2001 From: "Eduardo M. Fleury" Date: Tue, 22 Sep 2009 14:20:10 -0300 Subject: QGraphicsAnchorLayout: Add data structures for Expanding size policy Adding required members for the upcoming support of the QSizePolicy::Expand flag. In this state, running with simplification will probably not work. Signed-off-by: Eduardo M. Fleury Reviewed-by: Artur Duque de Souza --- src/gui/graphicsview/qgraphicsanchorlayout_p.cpp | 44 +++++++++++++++++++----- src/gui/graphicsview/qgraphicsanchorlayout_p.h | 20 ++++++++--- 2 files changed, 51 insertions(+), 13 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp b/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp index f75118b..fc3bc8a 100644 --- a/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp +++ b/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp @@ -94,7 +94,9 @@ qreal QGraphicsAnchorPrivate::spacing() const void AnchorData::refreshSizeHints(qreal effectiveSpacing) { - if (!isLayoutAnchor && from->m_item == to->m_item) { + isExpanding = 0; + + if (!isLayoutAnchor && (from->m_item == to->m_item)) { QGraphicsLayoutItem *item = from->m_item; const QGraphicsAnchorLayoutPrivate::Orientation orient = QGraphicsAnchorLayoutPrivate::edgeOrientation(from->m_edge); @@ -138,6 +140,9 @@ void AnchorData::refreshSizeHints(qreal effectiveSpacing) if (policy & QSizePolicy::IgnoreFlag) prefSize = minSize; + if (policy & QSizePolicy::ExpandFlag) + isExpanding = 1; + bool hasCenter = (from->m_edge == centerEdge || to->m_edge == centerEdge); if (hasCenter) { @@ -155,6 +160,7 @@ void AnchorData::refreshSizeHints(qreal effectiveSpacing) // recalculate and override the values we set here. sizeAtMinimum = prefSize; sizeAtPreferred = prefSize; + sizeAtExpanding = prefSize; sizeAtMaximum = prefSize; } else if (!hasSize) { @@ -165,6 +171,7 @@ void AnchorData::refreshSizeHints(qreal effectiveSpacing) sizeAtMinimum = prefSize; sizeAtPreferred = prefSize; + sizeAtExpanding = prefSize; sizeAtMaximum = prefSize; } } @@ -357,6 +364,12 @@ QGraphicsAnchorLayoutPrivate::QGraphicsAnchorLayoutPrivate() : calculateGraphCacheDirty(1) { for (int i = 0; i < NOrientations; ++i) { + for (int j = 0; j < 3; ++j) { + sizeHints[i][j] = -1; + } + sizeAtExpanding[i] = -1; + interpolationProgress[i] = -1; + spacings[i] = -1; graphSimplified[i] = false; graphHasConflicts[i] = false; @@ -1649,6 +1662,10 @@ void QGraphicsAnchorLayoutPrivate::calculateGraphs( sizeHints[orientation][Qt::PreferredSize] = pref; sizeHints[orientation][Qt::MaximumSize] = max; + // XXX implement Expanding simplex + for (int i = 0; i < trunkVariables.count(); ++i) + trunkVariables.at(i)->sizeAtExpanding = trunkVariables.at(i)->sizeAtPreferred; + sizeAtExpanding[orientation] = pref; } } else { #if 0 @@ -1664,6 +1681,7 @@ void QGraphicsAnchorLayoutPrivate::calculateGraphs( AnchorData *ad = trunkPath.positives.toList()[0]; ad->sizeAtMinimum = ad->minSize; ad->sizeAtPreferred = ad->prefSize; + ad->sizeAtExpanding = ad->prefSize; ad->sizeAtMaximum = ad->maxSize; // Propagate @@ -1672,6 +1690,7 @@ void QGraphicsAnchorLayoutPrivate::calculateGraphs( sizeHints[orientation][Qt::MinimumSize] = ad->sizeAtMinimum; sizeHints[orientation][Qt::PreferredSize] = ad->sizeAtPreferred; sizeHints[orientation][Qt::MaximumSize] = ad->sizeAtMaximum; + sizeAtExpanding[orientation] = ad->sizeAtPreferred; } // Delete the constraints, we won't use them anymore. @@ -1701,6 +1720,7 @@ void QGraphicsAnchorLayoutPrivate::calculateGraphs( AnchorData *ad = partVariables[j]; Q_ASSERT(ad); ad->sizeAtMinimum = ad->sizeAtPreferred; + ad->sizeAtExpanding = ad->sizeAtPreferred; ad->sizeAtMaximum = ad->sizeAtPreferred; ad->updateChildrenSizes(); } @@ -2058,9 +2078,13 @@ void QGraphicsAnchorLayoutPrivate::setupEdgesInterpolation( interpolationInterval[orientation] = MinToPreferred; lower = sizeHints[orientation][Qt::MinimumSize]; upper = sizeHints[orientation][Qt::PreferredSize]; - } else { - interpolationInterval[orientation] = PreferredToMax; + } else if (current < sizeAtExpanding[orientation]) { + interpolationInterval[orientation] = PreferredToExpanding; lower = sizeHints[orientation][Qt::PreferredSize]; + upper = sizeAtExpanding[orientation]; + } else { + interpolationInterval[orientation] = ExpandingToMax; + lower = sizeAtExpanding[orientation]; upper = sizeHints[orientation][Qt::MaximumSize]; } @@ -2075,11 +2099,12 @@ void QGraphicsAnchorLayoutPrivate::setupEdgesInterpolation( \internal Calculate the current Edge size based on the current Layout size and the - size the edge is supposed to have when: + size the edge is supposed to have when the layout is at its: - - the layout is at its minimum size. - - the layout is at its preferred size. - - the layout is at its maximum size. + - minimum size, + - preferred size, + - size when all expanding anchors are expanded, + - maximum size. These three key values are calculated in advance using linear programming (more expensive) or the simplification algorithm, then @@ -2099,8 +2124,11 @@ void QGraphicsAnchorLayoutPrivate::interpolateEdge(AnchorVertex *base, if (interpolationInterval[orientation] == MinToPreferred) { lower = edge->sizeAtMinimum; upper = edge->sizeAtPreferred; - } else { + } else if (interpolationInterval[orientation] == PreferredToExpanding) { lower = edge->sizeAtPreferred; + upper = edge->sizeAtExpanding; + } else { + lower = edge->sizeAtExpanding; upper = edge->sizeAtMaximum; } diff --git a/src/gui/graphicsview/qgraphicsanchorlayout_p.h b/src/gui/graphicsview/qgraphicsanchorlayout_p.h index c86bfa3..4c6c2aa 100644 --- a/src/gui/graphicsview/qgraphicsanchorlayout_p.h +++ b/src/gui/graphicsview/qgraphicsanchorlayout_p.h @@ -153,7 +153,8 @@ struct AnchorData : public QSimplexVariable { : QSimplexVariable(), from(0), to(0), minSize(minimumSize), prefSize(preferredSize), maxSize(maximumSize), sizeAtMinimum(preferredSize), - sizeAtPreferred(preferredSize), sizeAtMaximum(preferredSize), + sizeAtPreferred(preferredSize), sizeAtExpanding(preferredSize), + sizeAtMaximum(preferredSize), graphicsAnchor(0), skipInPreferred(0), type(Normal), hasSize(true), isLayoutAnchor(false) {} @@ -161,7 +162,8 @@ struct AnchorData : public QSimplexVariable { AnchorData(qreal size) : QSimplexVariable(), from(0), to(0), minSize(size), prefSize(size), maxSize(size), - sizeAtMinimum(size), sizeAtPreferred(size), sizeAtMaximum(size), + sizeAtMinimum(size), sizeAtPreferred(size), sizeAtExpanding(size), + sizeAtMaximum(size), graphicsAnchor(0), skipInPreferred(0), type(Normal), hasSize(true), isLayoutAnchor(false) {} @@ -169,7 +171,8 @@ struct AnchorData : public QSimplexVariable { AnchorData() : QSimplexVariable(), from(0), to(0), minSize(0), prefSize(0), maxSize(0), - sizeAtMinimum(0), sizeAtPreferred(0), sizeAtMaximum(0), + sizeAtMinimum(0), sizeAtPreferred(0), sizeAtExpanding(0), + sizeAtMaximum(0), graphicsAnchor(0), skipInPreferred(0), type(Normal), hasSize(false), isLayoutAnchor(false) {} @@ -192,6 +195,7 @@ struct AnchorData : public QSimplexVariable { maxSize = size; sizeAtMinimum = size; sizeAtPreferred = size; + sizeAtExpanding = size; sizeAtMaximum = size; hasSize = true; } @@ -218,6 +222,7 @@ struct AnchorData : public QSimplexVariable { // calculated by the Simplex solver based on the current layout setup. qreal sizeAtMinimum; qreal sizeAtPreferred; + qreal sizeAtExpanding; qreal sizeAtMaximum; QGraphicsAnchor *graphicsAnchor; @@ -225,12 +230,15 @@ struct AnchorData : public QSimplexVariable { uint type : 2; // either Normal, Sequential or Parallel uint hasSize : 1; // if false, get size from style. uint isLayoutAnchor : 1; // if this anchor is connected to a layout 'edge' + uint isExpanding : 1; // if true, expands before other anchors + protected: AnchorData(Type type, qreal size = 0) : QSimplexVariable(), from(0), to(0), minSize(size), prefSize(size), maxSize(size), sizeAtMinimum(size), - sizeAtPreferred(size), sizeAtMaximum(size), + sizeAtPreferred(size), sizeAtExpanding(size), + sizeAtMaximum(size), graphicsAnchor(0), skipInPreferred(0), type(type), hasSize(true), isLayoutAnchor(false) {} @@ -355,7 +363,8 @@ public: // Interval represents which interpolation interval are we operating in. enum Interval { MinToPreferred = 0, - PreferredToMax + PreferredToExpanding, + ExpandingToMax }; // Several structures internal to the layout are duplicated to handle @@ -496,6 +505,7 @@ public: qreal spacings[NOrientations]; // Size hints from simplex engine qreal sizeHints[2][3]; + qreal sizeAtExpanding[2]; // Items QVector items; -- cgit v0.12 From 1728f846d9fb53a699782005d6478c0f23f9b82e Mon Sep 17 00:00:00 2001 From: "Eduardo M. Fleury" Date: Wed, 23 Sep 2009 16:02:35 -0300 Subject: QGraphicsAnchorLayout: Enabling Simplex support for Expanding size policy To support the expanding size policy we had to change the way the setup process work. Previously we used to calculate three key-frames using the simplex solver: - sizeAtMinimum: the value an anchor should be in when the layout is at its minimum size. Calculated using simplex solver to minimize the layout size. - sizeAtPreferred: the value an anchor should be in when the layout is at its preferred size. Calculated using simplex solver to minimize the deviation from the items preferred sizes. - sizeAtMaximum: the value an anchor should be in when the layout is at its maximum size. Calculated using simplex solver to maximize the layout size. That worked fine but didn't diferentiate standard items from the "expanding" ones. In other words, all items would grow from their sizeAtPreferred to their sizeAtMaximum at the same rate. To support the idea of "expanding" items, ie. items that should grow faster than the others, we added a fourth state, between preferred and maximum. Now we have the following interpolation order: sizeAtMinimum -> sizeAtPreferred -> sizeAtExpanding -> sizeAtMaximum. The definition of the "expanding" state is that all "expanding" items should have grown all the way to their "sizeAtMaximum" values whereas non expanding items should have kept their preferred sizes. The only exception is that non-expanding items are allowed to grow if that is necessary to allow the "expanding" items to reach their sizeAtMaximum. So, the visual result is that if the layout is resized from its preferred size to its maximum size, the expanding items will grow first and then, in a second phase, the other items will grow. This commit adds QGALPrivate::solveExpanding() and calls it from calculateGraphs(). Signed-off-by: Eduardo M. Fleury Reviewed-by: Artur Duque de Souza --- src/gui/graphicsview/qgraphicsanchorlayout_p.cpp | 98 +++++++++++++++++++++--- src/gui/graphicsview/qgraphicsanchorlayout_p.h | 1 + 2 files changed, 88 insertions(+), 11 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp b/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp index fc3bc8a..93ccf83 100644 --- a/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp +++ b/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp @@ -1635,11 +1635,18 @@ void QGraphicsAnchorLayoutPrivate::calculateGraphs( qreal min, max; feasible = solveMinMax(trunkConstraints, trunkPath, &min, &max); - // Solve for preferred. The objective function is calculated from the constraints - // and variables internally. - feasible &= solvePreferred(trunkConstraints); - if (feasible) { + // Solve for preferred. The objective function is calculated from the constraints + // and variables internally. + solvePreferred(trunkConstraints); + + // remove sizeHintConstraints from trunkConstraints + trunkConstraints = parts[0]; + + // Solve for expanding. The objective function and the constraints from items + // are calculated internally. + solveExpanding(trunkConstraints); + // Propagate the new sizes down the simplified graph, ie. tell the // group anchors to set their children anchors sizes. @@ -1649,23 +1656,23 @@ void QGraphicsAnchorLayoutPrivate::calculateGraphs( for (int i = 0; i < trunkVariables.count(); ++i) trunkVariables.at(i)->updateChildrenSizes(); - // Calculate and set the preferred size for the layout from the edge sizes that - // were calculated above. + // Calculate and set the preferred and expanding sizes for the layout, + // from the edge sizes that were calculated above. qreal pref(0.0); + qreal expanding(0.0); foreach (const AnchorData *ad, trunkPath.positives) { pref += ad->sizeAtPreferred; + expanding += ad->sizeAtExpanding; } foreach (const AnchorData *ad, trunkPath.negatives) { pref -= ad->sizeAtPreferred; + expanding -= ad->sizeAtExpanding; } + sizeHints[orientation][Qt::MinimumSize] = min; sizeHints[orientation][Qt::PreferredSize] = pref; sizeHints[orientation][Qt::MaximumSize] = max; - - // XXX implement Expanding simplex - for (int i = 0; i < trunkVariables.count(); ++i) - trunkVariables.at(i)->sizeAtExpanding = trunkVariables.at(i)->sizeAtPreferred; - sizeAtExpanding[orientation] = pref; + sizeAtExpanding[orientation] = expanding; } } else { #if 0 @@ -2315,6 +2322,75 @@ bool QGraphicsAnchorLayoutPrivate::solvePreferred(QList co return feasible; } +void QGraphicsAnchorLayoutPrivate::solveExpanding(QList constraints) +{ + QList variables = getVariables(constraints); + QList itemConstraints; + QSimplexConstraint *objective = new QSimplexConstraint; + + // Use all items that belong to trunk to: + // - add solveExpanding-specific item constraints + // - create the objective function + for (int i = 0; i < variables.size(); ++i) { + AnchorData *ad = variables[i]; + if (ad->isExpanding) { + // Add constraint to lock expanding anchor in its sizeAtMaximum + QSimplexConstraint *itemC = new QSimplexConstraint; + itemC->ratio = QSimplexConstraint::Equal; + itemC->variables.insert(ad, 1.0); + itemC->constant = ad->sizeAtMaximum; + itemConstraints << itemC; + } else { + // Add constraints to lock anchor between their sizeAtPreferred and sizeAtMaximum + QSimplexConstraint *itemC = new QSimplexConstraint; + itemC->ratio = QSimplexConstraint::MoreOrEqual; + itemC->variables.insert(ad, 1.0); + itemC->constant = qMin(ad->sizeAtPreferred, ad->sizeAtMaximum); + itemConstraints << itemC; + + itemC = new QSimplexConstraint; + itemC->ratio = QSimplexConstraint::LessOrEqual; + itemC->variables.insert(ad, 1.0); + itemC->constant = qMax(ad->sizeAtPreferred, ad->sizeAtMaximum); + itemConstraints << itemC; + + // Add anchor to objective function + if (ad->sizeAtPreferred < ad->sizeAtMaximum) { + // Try to shrink this variable towards its sizeAtPreferred value + objective->variables.insert(ad, 1.0); + } else { + // Try to grow this variable towards its sizeAtPreferred value + objective->variables.insert(ad, -1.0); + } + } + } + + // Solve + if (objective->variables.size() == variables.size()) { + // If no anchors are expanding, we don't need to run the simplex + // Set all variables to their preferred size + for (int i = 0; i < variables.size(); ++i) { + variables[i]->sizeAtExpanding = variables[i]->sizeAtPreferred; + } + } else { + // Run simplex + QSimplex simplex; + bool feasible = simplex.setConstraints(constraints + itemConstraints); + Q_ASSERT(feasible); + + simplex.setObjective(objective); + simplex.solveMin(); + + // Collect results + for (int i = 0; i < variables.size(); ++i) { + variables[i]->sizeAtExpanding = variables[i]->result; + } + } + + delete objective; + qDeleteAll(itemConstraints); +} + /*! \internal Returns true if there are no arrangement that satisfies all constraints. diff --git a/src/gui/graphicsview/qgraphicsanchorlayout_p.h b/src/gui/graphicsview/qgraphicsanchorlayout_p.h index 4c6c2aa..47df786 100644 --- a/src/gui/graphicsview/qgraphicsanchorlayout_p.h +++ b/src/gui/graphicsview/qgraphicsanchorlayout_p.h @@ -495,6 +495,7 @@ public: bool solveMinMax(QList constraints, GraphPath path, qreal *min, qreal *max); bool solvePreferred(QList constraints); + void solveExpanding(QList constraints); bool hasConflicts() const; #ifdef QT_DEBUG -- cgit v0.12 From e210bea72ef65f99babb4c6f5bd442184c671d3b Mon Sep 17 00:00:00 2001 From: "Eduardo M. Fleury" Date: Thu, 24 Sep 2009 11:16:16 -0300 Subject: QGraphicsAnchorLayout Tests: Enable expanding tests Removing QEXPECT_FAIL and making minor corrections on expected values. Signed-off-by: Eduardo M. Fleury Reviewed-by: Artur Duque de Souza --- .../qgraphicsanchorlayout/tst_qgraphicsanchorlayout.cpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/tests/auto/qgraphicsanchorlayout/tst_qgraphicsanchorlayout.cpp b/tests/auto/qgraphicsanchorlayout/tst_qgraphicsanchorlayout.cpp index e898edb..4ad48c7 100644 --- a/tests/auto/qgraphicsanchorlayout/tst_qgraphicsanchorlayout.cpp +++ b/tests/auto/qgraphicsanchorlayout/tst_qgraphicsanchorlayout.cpp @@ -1359,7 +1359,6 @@ void tst_QGraphicsAnchorLayout::expandingSequence() QSizeF layoutExpandedSize(pref.width() + max.width(), layoutMinimumSize.height()); p.resize(layoutExpandedSize); - QEXPECT_FAIL("", "Support for QSizePolicy::ExpandFlag not yet available", Abort); QCOMPARE(a->geometry().size(), pref); QCOMPARE(b->geometry().size(), max); @@ -1409,7 +1408,6 @@ void tst_QGraphicsAnchorLayout::expandingSequenceFairDistribution() layoutMinimumSize.height()); p.resize(layoutPartialExpandedSize); - QEXPECT_FAIL("", "Support for QSizePolicy::ExpandFlag not yet available", Abort); QCOMPARE(a->geometry().size(), pref); QCOMPARE(b->geometry().size(), pref + QSizeF(10, 0)); QCOMPARE(c->geometry().size(), pref); @@ -1443,6 +1441,7 @@ void tst_QGraphicsAnchorLayout::expandingSequenceFairDistribution() QSizeF newLayoutPartialExpandedSize((4 * pref.width()) + 75, layoutMinimumSize.height()); + p.resize(newLayoutPartialExpandedSize); QCOMPARE(a->geometry().size(), pref); QCOMPARE(b->geometry().size(), pref + QSizeF(25, 0)); @@ -1454,11 +1453,12 @@ void tst_QGraphicsAnchorLayout::expandingParallel() { QSizeF min(10, 10); QSizeF pref(50, 10); - QSizeF max(100, 50); + QSizeF max(100, 10); + QSizeF max2(100, 50); QGraphicsWidget *a = createItem(min, pref, max, "a"); QGraphicsWidget *b = createItem(min, pref, max, "b"); - QGraphicsWidget *c = createItem(min, pref, max, "c"); + QGraphicsWidget *c = createItem(min, pref, max2, "c"); b->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); @@ -1492,10 +1492,9 @@ void tst_QGraphicsAnchorLayout::expandingParallel() QSizeF layoutExpandedSize(pref.width() + max.width(), layoutMinimumSize.height()); p.resize(layoutExpandedSize); - QEXPECT_FAIL("", "Support for QSizePolicy::ExpandFlag not yet available", Abort); QCOMPARE(a->geometry().size(), max); QCOMPARE(b->geometry().size(), max); - QCOMPARE(c->geometry().size(), pref); + QCOMPARE(c->geometry().size(), QSizeF(pref.width(), 20)); QSizeF layoutMaximumSize = l->effectiveSizeHint(Qt::MaximumSize); QCOMPARE(layoutMaximumSize.width(), qreal(200)); @@ -1511,12 +1510,12 @@ void tst_QGraphicsAnchorLayout::expandingParallel() QSizeF newLayoutMinimumSize = l->effectiveSizeHint(Qt::MinimumSize); QCOMPARE(newLayoutMinimumSize.width(), qreal(30)); - QSizeF newLayoutExpandedSize(pref.width() + max.width(), layoutMinimumSize.height()); + QSizeF newLayoutExpandedSize = layoutExpandedSize + QSizeF(100, 0); p.resize(newLayoutExpandedSize); - QCOMPARE(a->geometry().size(), max); + QCOMPARE(a->geometry().size(), max + QSizeF(100, 0)); QCOMPARE(b->geometry().size(), max); - QCOMPARE(c->geometry().size(), pref); + QCOMPARE(c->geometry().size(), QSizeF(pref.width(), 20)); QSizeF newLayoutMaximumSize = l->effectiveSizeHint(Qt::MaximumSize); QCOMPARE(newLayoutMaximumSize.width(), qreal(300)); -- cgit v0.12 From 5dd77be3acfb53b44d7d6b0015af0c33124ab84a Mon Sep 17 00:00:00 2001 From: Caio Marcelo de Oliveira Filho Date: Thu, 24 Sep 2009 17:09:16 -0300 Subject: QGraphicsAnchorLayout: cleaning up AnchorData Use just one constructor for AnchorData and tweak the struct when necessary. Also use the function refreshSizeHints() for Normal anchors to get the item information instead of passing to the constructor. This has the advantage that we don't need to replicate the code for checking and updating the size hint and size policies. Note that the code before only considered the size policies after the first refreshSizeHints() -- which we know will be called after the simplification, so the assumption seems to be correct, but we don't depend on that anymore.. Signed-off-by: Caio Marcelo de Oliveira Filho Reviewed-by: Eduardo M. Fleury --- src/gui/graphicsview/qgraphicsanchorlayout_p.cpp | 89 ++++++++++++------------ src/gui/graphicsview/qgraphicsanchorlayout_p.h | 53 ++++---------- 2 files changed, 59 insertions(+), 83 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp b/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp index 93ccf83..dc8d211 100644 --- a/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp +++ b/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp @@ -94,8 +94,6 @@ qreal QGraphicsAnchorPrivate::spacing() const void AnchorData::refreshSizeHints(qreal effectiveSpacing) { - isExpanding = 0; - if (!isLayoutAnchor && (from->m_item == to->m_item)) { QGraphicsLayoutItem *item = from->m_item; @@ -140,9 +138,6 @@ void AnchorData::refreshSizeHints(qreal effectiveSpacing) if (policy & QSizePolicy::IgnoreFlag) prefSize = minSize; - if (policy & QSizePolicy::ExpandFlag) - isExpanding = 1; - bool hasCenter = (from->m_edge == centerEdge || to->m_edge == centerEdge); if (hasCenter) { @@ -151,6 +146,14 @@ void AnchorData::refreshSizeHints(qreal effectiveSpacing) maxSize /= 2; } + if (policy & QSizePolicy::ExpandFlag) { + isExpanding = 1; + expSize = maxSize; + } else { + isExpanding = 0; + expSize = prefSize; + } + // Set the anchor effective sizes to preferred. // // Note: The idea here is that all items should remain at their @@ -167,8 +170,11 @@ void AnchorData::refreshSizeHints(qreal effectiveSpacing) // Anchor has no size defined, use given default information minSize = effectiveSpacing; prefSize = effectiveSpacing; + expSize = effectiveSpacing; maxSize = effectiveSpacing; + isExpanding = 0; + sizeAtMinimum = prefSize; sizeAtPreferred = prefSize; sizeAtExpanding = prefSize; @@ -830,9 +836,10 @@ void QGraphicsAnchorLayoutPrivate::createLayoutEdges() QGraphicsLayoutItem *layout = q; // Horizontal - AnchorData *data = new AnchorData(0, 0, QWIDGETSIZE_MAX); + AnchorData *data = new AnchorData; addAnchor_helper(layout, Qt::AnchorLeft, layout, - Qt::AnchorRight, data); + Qt::AnchorRight, data); + data->maxSize = QWIDGETSIZE_MAX; data->skipInPreferred = 1; // Set the Layout Left edge as the root of the horizontal graph. @@ -840,9 +847,10 @@ void QGraphicsAnchorLayoutPrivate::createLayoutEdges() graph[Horizontal].setRootVertex(v); // Vertical - data = new AnchorData(0, 0, QWIDGETSIZE_MAX); + data = new AnchorData; addAnchor_helper(layout, Qt::AnchorTop, layout, - Qt::AnchorBottom, data); + Qt::AnchorBottom, data); + data->maxSize = QWIDGETSIZE_MAX; data->skipInPreferred = 1; // Set the Layout Top edge as the root of the vertical graph. @@ -869,19 +877,15 @@ void QGraphicsAnchorLayoutPrivate::createItemEdges(QGraphicsLayoutItem *item) items.append(item); - QSizeF minSize = item->effectiveSizeHint(Qt::MinimumSize); - QSizeF prefSize = item->effectiveSizeHint(Qt::PreferredSize); - QSizeF maxSize = item->effectiveSizeHint(Qt::MaximumSize); - - // Horizontal - AnchorData *data = new AnchorData(minSize.width(), prefSize.width(), maxSize.width()); - addAnchor_helper(item, Qt::AnchorLeft, item, - Qt::AnchorRight, data); + // Create horizontal and vertical internal anchors for the item and + // refresh its size hint / policy values. + AnchorData *data = new AnchorData; + addAnchor_helper(item, Qt::AnchorLeft, item, Qt::AnchorRight, data); + data->refreshSizeHints(0); // 0 = effectiveSpacing, will not be used - // Vertical - data = new AnchorData(minSize.height(), prefSize.height(), maxSize.height()); - addAnchor_helper(item, Qt::AnchorTop, item, - Qt::AnchorBottom, data); + data = new AnchorData; + addAnchor_helper(item, Qt::AnchorTop, item, Qt::AnchorBottom, data); + data->refreshSizeHints(0); // 0 = effectiveSpacing, will not be used } /*! @@ -934,20 +938,17 @@ void QGraphicsAnchorLayoutPrivate::createCenterAnchors( Q_ASSERT(first && last); // Create new anchors - AnchorData *oldData = graph[orientation].edgeData(first, last); - - qreal minimumSize = oldData->minSize / 2; - qreal preferredSize = oldData->prefSize / 2; - qreal maximumSize = oldData->maxSize / 2; - QSimplexConstraint *c = new QSimplexConstraint; - AnchorData *data = new AnchorData(minimumSize, preferredSize, maximumSize); + + AnchorData *data = new AnchorData; c->variables.insert(data, 1.0); addAnchor_helper(item, firstEdge, item, centerEdge, data); + data->refreshSizeHints(0); - data = new AnchorData(minimumSize, preferredSize, maximumSize); + data = new AnchorData; c->variables.insert(data, -1.0); addAnchor_helper(item, centerEdge, item, lastEdge, data); + data->refreshSizeHints(0); itemCenterConstraints[orientation].append(c); @@ -1008,14 +1009,9 @@ void QGraphicsAnchorLayoutPrivate::removeCenterAnchors( if (substitute) { // Create the new anchor that should substitute the left-center-right anchors. - AnchorData *oldData = g.edgeData(first, center); - - qreal minimumSize = oldData->minSize * 2; - qreal preferredSize = oldData->prefSize * 2; - qreal maximumSize = oldData->maxSize * 2; - - AnchorData *data = new AnchorData(minimumSize, preferredSize, maximumSize); + AnchorData *data = new AnchorData; addAnchor_helper(item, firstEdge, item, lastEdge, data); + data->refreshSizeHints(0); // Remove old anchors removeAnchor_helper(first, center); @@ -1133,7 +1129,7 @@ QGraphicsAnchor *QGraphicsAnchorLayoutPrivate::addAnchor(QGraphicsLayoutItem *fi // Use heuristics to find out what the user meant with this anchor. correctEdgeDirection(firstItem, firstEdge, secondItem, secondEdge); - AnchorData *data; + AnchorData *data = new AnchorData; if (!spacing) { // If firstItem or secondItem is the layout itself, the spacing will default to 0. // Otherwise, the following matrix is used (questionmark means that the spacing @@ -1143,22 +1139,25 @@ QGraphicsAnchor *QGraphicsAnchorLayoutPrivate::addAnchor(QGraphicsLayoutItem *fi // Left 0 0 ? // HCenter 0 0 0 // Right ? 0 0 - if (firstItem != q - && secondItem != q - && pickEdge(firstEdge, Horizontal) != Qt::AnchorHorizontalCenter - && oppositeEdge(firstEdge) == secondEdge) { - data = new AnchorData; // ask the style later + if (firstItem == q + || secondItem == q + || pickEdge(firstEdge, Horizontal) == Qt::AnchorHorizontalCenter + || oppositeEdge(firstEdge) != secondEdge) { + data->setFixedSize(0); } else { - data = new AnchorData(0); // spacing should be 0 + data->unsetSize(); } addAnchor_helper(firstItem, firstEdge, secondItem, secondEdge, data); + } else if (*spacing >= 0) { - data = new AnchorData(*spacing); + data->setFixedSize(*spacing); addAnchor_helper(firstItem, firstEdge, secondItem, secondEdge, data); + } else { - data = new AnchorData(-*spacing); + data->setFixedSize(-*spacing); addAnchor_helper(secondItem, secondEdge, firstItem, firstEdge, data); } + return acquireGraphicsAnchor(data); } diff --git a/src/gui/graphicsview/qgraphicsanchorlayout_p.h b/src/gui/graphicsview/qgraphicsanchorlayout_p.h index 47df786..047be39 100644 --- a/src/gui/graphicsview/qgraphicsanchorlayout_p.h +++ b/src/gui/graphicsview/qgraphicsanchorlayout_p.h @@ -149,33 +149,15 @@ struct AnchorData : public QSimplexVariable { Sequential, Parallel }; - AnchorData(qreal minimumSize, qreal preferredSize, qreal maximumSize) - : QSimplexVariable(), from(0), to(0), - minSize(minimumSize), prefSize(preferredSize), - maxSize(maximumSize), sizeAtMinimum(preferredSize), - sizeAtPreferred(preferredSize), sizeAtExpanding(preferredSize), - sizeAtMaximum(preferredSize), - graphicsAnchor(0), - skipInPreferred(0), type(Normal), hasSize(true), - isLayoutAnchor(false) {} - - AnchorData(qreal size) - : QSimplexVariable(), from(0), to(0), - minSize(size), prefSize(size), maxSize(size), - sizeAtMinimum(size), sizeAtPreferred(size), sizeAtExpanding(size), - sizeAtMaximum(size), - graphicsAnchor(0), - skipInPreferred(0), type(Normal), hasSize(true), - isLayoutAnchor(false) {} AnchorData() : QSimplexVariable(), from(0), to(0), - minSize(0), prefSize(0), maxSize(0), - sizeAtMinimum(0), sizeAtPreferred(0), sizeAtExpanding(0), - sizeAtMaximum(0), - graphicsAnchor(0), - skipInPreferred(0), type(Normal), hasSize(false), - isLayoutAnchor(false) {} + minSize(0), prefSize(0), expSize(0), maxSize(0), + sizeAtMinimum(0), sizeAtPreferred(0), + sizeAtExpanding(0), sizeAtMaximum(0), + graphicsAnchor(0), skipInPreferred(0), + type(Normal), hasSize(true), isLayoutAnchor(false), + isExpanding(false) {} virtual void updateChildrenSizes() {} virtual void refreshSizeHints(qreal effectiveSpacing); @@ -192,6 +174,7 @@ struct AnchorData : public QSimplexVariable { { minSize = size; prefSize = size; + expSize = size; maxSize = size; sizeAtMinimum = size; sizeAtPreferred = size; @@ -215,6 +198,7 @@ struct AnchorData : public QSimplexVariable { // size. qreal minSize; qreal prefSize; + qreal expSize; qreal maxSize; // These attributes define which sizes should that anchor be in when the @@ -231,17 +215,6 @@ struct AnchorData : public QSimplexVariable { uint hasSize : 1; // if false, get size from style. uint isLayoutAnchor : 1; // if this anchor is connected to a layout 'edge' uint isExpanding : 1; // if true, expands before other anchors - -protected: - AnchorData(Type type, qreal size = 0) - : QSimplexVariable(), from(0), to(0), - minSize(size), prefSize(size), - maxSize(size), sizeAtMinimum(size), - sizeAtPreferred(size), sizeAtExpanding(size), - sizeAtMaximum(size), - graphicsAnchor(0), - skipInPreferred(0), type(type), hasSize(true), - isLayoutAnchor(false) {} }; #ifdef QT_DEBUG @@ -253,8 +226,10 @@ inline QString AnchorData::toString() const struct SequentialAnchorData : public AnchorData { - SequentialAnchorData() : AnchorData(AnchorData::Sequential) + SequentialAnchorData() : AnchorData() { + type = AnchorData::Sequential; + hasSize = true; #ifdef QT_DEBUG name = QLatin1String("SequentialAnchorData"); #endif @@ -278,9 +253,11 @@ struct SequentialAnchorData : public AnchorData struct ParallelAnchorData : public AnchorData { ParallelAnchorData(AnchorData *first, AnchorData *second) - : AnchorData(AnchorData::Parallel), - firstEdge(first), secondEdge(second) + : AnchorData(), firstEdge(first), secondEdge(second) { + type = AnchorData::Parallel; + hasSize = true; + // ### Those asserts force that both child anchors have the same direction, // but can't we simplify a pair of anchors in opposite directions? Q_ASSERT(first->from == second->from); -- cgit v0.12 From bcd08ab82b5df13f7687a504f868cb8b6ff8b75e Mon Sep 17 00:00:00 2001 From: Caio Marcelo de Oliveira Filho Date: Fri, 25 Sep 2009 16:13:18 -0300 Subject: QGraphicsAnchorLayout: avoid code duplication when initializing complex anchors Now we can use refreshSizeHints_helper() to initialize complex anchors (parallel and sequential). This avoids duplication of code in the function simplifySequentialChunk(). This commit also 'disable' ExpandFlag temporarily, stabilizing the tests for the simplification. The next commit should re-enable it implementing the necessary code for simplification as well. Signed-off-by: Caio Marcelo de Oliveira Filho Reviewed-by: Eduardo M. Fleury --- src/gui/graphicsview/qgraphicsanchorlayout_p.cpp | 102 +++++++++++------------ src/gui/graphicsview/qgraphicsanchorlayout_p.h | 4 + 2 files changed, 54 insertions(+), 52 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp b/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp index dc8d211..dd46722 100644 --- a/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp +++ b/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp @@ -146,13 +146,15 @@ void AnchorData::refreshSizeHints(qreal effectiveSpacing) maxSize /= 2; } - if (policy & QSizePolicy::ExpandFlag) { - isExpanding = 1; - expSize = maxSize; - } else { - isExpanding = 0; - expSize = prefSize; - } + // ### + expSize = prefSize; + // if (policy & QSizePolicy::ExpandFlag) { + // isExpanding = 1; + // expSize = maxSize; + // } else { + // isExpanding = 0; + // expSize = prefSize; + // } // Set the anchor effective sizes to preferred. // @@ -187,6 +189,7 @@ void ParallelAnchorData::updateChildrenSizes() firstEdge->sizeAtMinimum = secondEdge->sizeAtMinimum = sizeAtMinimum; firstEdge->sizeAtPreferred = secondEdge->sizeAtPreferred = sizeAtPreferred; firstEdge->sizeAtMaximum = secondEdge->sizeAtMaximum = sizeAtMaximum; + firstEdge->sizeAtExpanding = secondEdge->sizeAtExpanding = sizeAtPreferred; firstEdge->updateChildrenSizes(); secondEdge->updateChildrenSizes(); @@ -194,9 +197,16 @@ void ParallelAnchorData::updateChildrenSizes() void ParallelAnchorData::refreshSizeHints(qreal effectiveSpacing) { - // First refresh children information - firstEdge->refreshSizeHints(effectiveSpacing); - secondEdge->refreshSizeHints(effectiveSpacing); + refreshSizeHints_helper(effectiveSpacing); +} + +void ParallelAnchorData::refreshSizeHints_helper(qreal effectiveSpacing, + bool refreshChildren) +{ + if (refreshChildren) { + firstEdge->refreshSizeHints(effectiveSpacing); + secondEdge->refreshSizeHints(effectiveSpacing); + } // ### should we warn if the parallel connection is invalid? // e.g. 1-2-3 with 10-20-30, the minimum of the latter is @@ -208,9 +218,13 @@ void ParallelAnchorData::refreshSizeHints(qreal effectiveSpacing) prefSize = qMax(firstEdge->prefSize, secondEdge->prefSize); prefSize = qMin(prefSize, maxSize); + // ### + expSize = prefSize; + // See comment in AnchorData::refreshSizeHints() about sizeAt* values sizeAtMinimum = prefSize; sizeAtPreferred = prefSize; + sizeAtExpanding = prefSize; sizeAtMaximum = prefSize; } @@ -277,30 +291,46 @@ void SequentialAnchorData::updateChildrenSizes() bandSize = maxFactor > 0 ? e->maxSize - e->prefSize : e->prefSize - e->minSize; e->sizeAtMaximum = e->prefSize + bandSize * maxFactor; + // ### + e->sizeAtExpanding = e->sizeAtPreferred; + e->updateChildrenSizes(); } } void SequentialAnchorData::refreshSizeHints(qreal effectiveSpacing) { + refreshSizeHints_helper(effectiveSpacing); +} + +void SequentialAnchorData::refreshSizeHints_helper(qreal effectiveSpacing, + bool refreshChildren) +{ minSize = 0; prefSize = 0; + expSize = 0; maxSize = 0; for (int i = 0; i < m_edges.count(); ++i) { AnchorData *edge = m_edges.at(i); - // First refresh children information - edge->refreshSizeHints(effectiveSpacing); + // If it's the case refresh children information first + if (refreshChildren) + edge->refreshSizeHints(effectiveSpacing); minSize += edge->minSize; prefSize += edge->prefSize; + expSize += edge->expSize; maxSize += edge->maxSize; } + // ### + expSize = prefSize; + // See comment in AnchorData::refreshSizeHints() about sizeAt* values sizeAtMinimum = prefSize; sizeAtPreferred = prefSize; + sizeAtExpanding = prefSize; sizeAtMaximum = prefSize; } @@ -441,39 +471,21 @@ static bool simplifySequentialChunk(Graph *graph, qDebug("simplifying [%s] to [%s - %s]", qPrintable(strPath), qPrintable(before->toString()), qPrintable(after->toString())); #endif - qreal min = 0; - qreal pref = 0; - qreal max = 0; - SequentialAnchorData *sequence = new SequentialAnchorData; AnchorVertex *prev = before; AnchorData *data; for (i = 0; i <= vertices.count(); ++i) { AnchorVertex *next = (i < vertices.count()) ? vertices.at(i) : after; data = graph->takeEdge(prev, next); - min += data->minSize; - pref += data->prefSize; - max = checkAdd(max, data->maxSize); sequence->m_edges.append(data); prev = next; } - - // insert new - sequence->minSize = min; - sequence->prefSize = pref; - sequence->maxSize = max; - - // Unless these values are overhidden by the simplex solver later-on, - // anchors will keep their own preferred size. - sequence->sizeAtMinimum = pref; - sequence->sizeAtPreferred = pref; - sequence->sizeAtMaximum = pref; - sequence->setVertices(vertices); - sequence->from = before; sequence->to = after; + sequence->refreshSizeHints_helper(0, false); + // data here is the last edge in the sequence // ### this seems to be here for supporting reverse order sequences, // but doesnt seem to be used right now @@ -488,25 +500,11 @@ static bool simplifySequentialChunk(Graph *graph, AnchorData *newAnchor = sequence; if (AnchorData *oldAnchor = graph->takeEdge(before, after)) { - newAnchor = new ParallelAnchorData(oldAnchor, sequence); - - newAnchor->isLayoutAnchor = (oldAnchor->isLayoutAnchor + ParallelAnchorData *parallel = new ParallelAnchorData(oldAnchor, sequence); + parallel->isLayoutAnchor = (oldAnchor->isLayoutAnchor || sequence->isLayoutAnchor); - - min = qMax(oldAnchor->minSize, sequence->minSize); - max = qMin(oldAnchor->maxSize, sequence->maxSize); - - pref = qMax(oldAnchor->prefSize, sequence->prefSize); - pref = qMin(pref, max); - - newAnchor->minSize = min; - newAnchor->prefSize = pref; - newAnchor->maxSize = max; - - // Same as above, by default, keep preferred size. - newAnchor->sizeAtMinimum = pref; - newAnchor->sizeAtPreferred = pref; - newAnchor->sizeAtMaximum = pref; + parallel->refreshSizeHints_helper(0, false); + newAnchor = parallel; } graph->createEdge(before, after, newAnchor); @@ -1687,7 +1685,7 @@ void QGraphicsAnchorLayoutPrivate::calculateGraphs( AnchorData *ad = trunkPath.positives.toList()[0]; ad->sizeAtMinimum = ad->minSize; ad->sizeAtPreferred = ad->prefSize; - ad->sizeAtExpanding = ad->prefSize; + ad->sizeAtExpanding = ad->expSize; ad->sizeAtMaximum = ad->maxSize; // Propagate @@ -1696,7 +1694,7 @@ void QGraphicsAnchorLayoutPrivate::calculateGraphs( sizeHints[orientation][Qt::MinimumSize] = ad->sizeAtMinimum; sizeHints[orientation][Qt::PreferredSize] = ad->sizeAtPreferred; sizeHints[orientation][Qt::MaximumSize] = ad->sizeAtMaximum; - sizeAtExpanding[orientation] = ad->sizeAtPreferred; + sizeAtExpanding[orientation] = ad->sizeAtExpanding; } // Delete the constraints, we won't use them anymore. diff --git a/src/gui/graphicsview/qgraphicsanchorlayout_p.h b/src/gui/graphicsview/qgraphicsanchorlayout_p.h index 047be39..8f67b2c 100644 --- a/src/gui/graphicsview/qgraphicsanchorlayout_p.h +++ b/src/gui/graphicsview/qgraphicsanchorlayout_p.h @@ -238,6 +238,8 @@ struct SequentialAnchorData : public AnchorData virtual void updateChildrenSizes(); virtual void refreshSizeHints(qreal effectiveSpacing); + void refreshSizeHints_helper(qreal effectiveSpacing, bool refreshChildren = true); + void setVertices(const QVector &vertices) { m_children = vertices; @@ -272,6 +274,8 @@ struct ParallelAnchorData : public AnchorData virtual void updateChildrenSizes(); virtual void refreshSizeHints(qreal effectiveSpacing); + void refreshSizeHints_helper(qreal effectiveSpacing, bool refreshChildren = true); + AnchorData* firstEdge; AnchorData* secondEdge; }; -- cgit v0.12 From ad69bb73754534f61658a83e85dadb75e603c90a Mon Sep 17 00:00:00 2001 From: "Eduardo M. Fleury" Date: Fri, 25 Sep 2009 19:02:21 -0300 Subject: QGraphicsAnchorLayout: Update solveExpanding to handle simplified graphs The previous implementation of solveExpanding would assume that anchors were either completely expanding (would grow to their sizeAtMaximum) or non-expanding (would try to remain at their sizeAtPreferred). What happens however is that with simplification enabled, we may have anchors that are "partially" expanding. An example is a sequential anchor that groups together two leaf anchors where only one of them is expanding. In this case, the expected size of that group anchor would be the sum of the max size of the expanding child plus the preferred size of the non-expanding child. To handle the above case we added the "expSize" variable. It holds the expected value at Expanding for each anchor. Based on this, and the already calculated values of sizeAtMaximum and sizeAtPreferred, the solver calculates the actual sizeAtExpanding for them. Signed-off-by: Eduardo M. Fleury Reviewed-by: Caio Marcelo de Oliveira Filho --- src/gui/graphicsview/qgraphicsanchorlayout_p.cpp | 84 ++++++++++++++++++++---- 1 file changed, 72 insertions(+), 12 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp b/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp index dd46722..cf1429c 100644 --- a/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp +++ b/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp @@ -2319,40 +2319,97 @@ bool QGraphicsAnchorLayoutPrivate::solvePreferred(QList co return feasible; } +/*! Calculate the "expanding" keyframe + + This new keyframe sits between the already existing sizeAtPreferred and + sizeAtMaximum keyframes. Its goal is to modify the interpolation between + the latter as to respect the "expanding" size policy of some anchors. + + Previously all items would be subject to a linear interpolation between + sizeAtPreferred and sizeAtMaximum values. This will change now, the + expanding anchors will change their size before the others. To calculate + this keyframe we use the following logic: + + 1) Ask each anchor for their desired expanding size (ad->expSize), this + value depends on the anchor expanding property in the following way: + + - Expanding anchors want to grow towards their maximum size + - Non-expanding anchors want to remain at their preferred size. + - Composite anchors want to grow towards somewhere between their + preferred sizes. (*) + + 2) Clamp their desired values to the value they assume in the neighbour + keyframes (sizeAtPreferred and sizeAtExpanding) + + 3) Run simplex with a setup that ensures the following: + + a. Anchors will change their value from their sizeAtPreferred towards + their sizeAtMaximum as much as required to ensure that ALL anchors + reach their respective "desired" expanding sizes. + + b. No anchors will change their value beyond what is NEEDED to satisfy + the requirement above. + + The final result is that, at the "expanding" keyframe expanding anchors + will grow and take with them all anchors that are parallel to them. + However, non-expanding anchors will remain at their preferred size unless + they are forced to grow by a parallel expanding anchor. + + Note: For anchors where the sizeAtPreferred is bigger than sizeAtPreferred, + the visual effect when the layout grows from its preferred size is + the following: Expanding anchors will keep their size while non + expanding ones will shrink. Only after non-expanding anchors have + shrinked all the way, the expanding anchors will start to shrink too. +*/ void QGraphicsAnchorLayoutPrivate::solveExpanding(QList constraints) { QList variables = getVariables(constraints); QList itemConstraints; QSimplexConstraint *objective = new QSimplexConstraint; + bool hasExpanding = false; - // Use all items that belong to trunk to: - // - add solveExpanding-specific item constraints - // - create the objective function + // Construct the simplex constraints and objective for (int i = 0; i < variables.size(); ++i) { + // For each anchor AnchorData *ad = variables[i]; - if (ad->isExpanding) { - // Add constraint to lock expanding anchor in its sizeAtMaximum + + // Clamp the desired expanding size + qreal upperBoundary = qMax(ad->sizeAtPreferred, ad->sizeAtMaximum); + qreal lowerBoundary = qMin(ad->sizeAtPreferred, ad->sizeAtMaximum); + qreal boundedExpSize = qBound(lowerBoundary, ad->expSize, upperBoundary); + + // Expanding anchors are those that want to move from their preferred size + if (boundedExpSize != ad->sizeAtPreferred) + hasExpanding = true; + + // Lock anchor between boundedExpSize and sizeAtMaximum (ensure 3.a) + if (boundedExpSize == ad->sizeAtMaximum) { + // The interval has only one possible value, we can use an "Equal" + // constraint and don't need to add this variable to the objective. QSimplexConstraint *itemC = new QSimplexConstraint; itemC->ratio = QSimplexConstraint::Equal; itemC->variables.insert(ad, 1.0); - itemC->constant = ad->sizeAtMaximum; + itemC->constant = boundedExpSize; itemConstraints << itemC; } else { - // Add constraints to lock anchor between their sizeAtPreferred and sizeAtMaximum + // Add MoreOrEqual and LessOrEqual constraints. QSimplexConstraint *itemC = new QSimplexConstraint; itemC->ratio = QSimplexConstraint::MoreOrEqual; itemC->variables.insert(ad, 1.0); - itemC->constant = qMin(ad->sizeAtPreferred, ad->sizeAtMaximum); + itemC->constant = qMin(boundedExpSize, ad->sizeAtMaximum); itemConstraints << itemC; itemC = new QSimplexConstraint; itemC->ratio = QSimplexConstraint::LessOrEqual; itemC->variables.insert(ad, 1.0); - itemC->constant = qMax(ad->sizeAtPreferred, ad->sizeAtMaximum); + itemC->constant = qMax(boundedExpSize, ad->sizeAtMaximum); itemConstraints << itemC; - // Add anchor to objective function - if (ad->sizeAtPreferred < ad->sizeAtMaximum) { + // Create objective to avoid the anchos from moving away from + // the preferred size more than the needed amount. (ensure 3.b) + // The objective function is the distance between sizeAtPreferred + // and sizeAtExpanding, it will be minimized. + if (ad->sizeAtExpanding < ad->sizeAtMaximum) { // Try to shrink this variable towards its sizeAtPreferred value objective->variables.insert(ad, 1.0); } else { @@ -2363,7 +2420,7 @@ void QGraphicsAnchorLayoutPrivate::solveExpanding(QList co } // Solve - if (objective->variables.size() == variables.size()) { + if (hasExpanding == false) { // If no anchors are expanding, we don't need to run the simplex // Set all variables to their preferred size for (int i = 0; i < variables.size(); ++i) { @@ -2372,9 +2429,12 @@ void QGraphicsAnchorLayoutPrivate::solveExpanding(QList co } else { // Run simplex QSimplex simplex; + + // Satisfy expanding (3.a) bool feasible = simplex.setConstraints(constraints + itemConstraints); Q_ASSERT(feasible); + // Reduce damage (3.b) simplex.setObjective(objective); simplex.solveMin(); -- cgit v0.12 From ba66cc0bde91e1143ac0a34f249f98e4573a5737 Mon Sep 17 00:00:00 2001 From: "Eduardo M. Fleury" Date: Mon, 28 Sep 2009 11:49:42 -0300 Subject: QSimplex: Remove overly conservative assertion This assertion started failing after the addition of expanding state. After some investigation we felt that the assertion itself was too strong and would fail in some valid cases. The new assertion is formally right as it tests whether the simplex solver was able to satisfy the simplex constraints, _exactly_ what it is expected to do. Signed-off-by: Eduardo M. Fleury Reviewed-by: Caio Marcelo de Oliveira Filho --- src/gui/graphicsview/qsimplex_p.cpp | 24 ++++++------------------ src/gui/graphicsview/qsimplex_p.h | 26 +++++++++++++++++++++++++- 2 files changed, 31 insertions(+), 19 deletions(-) diff --git a/src/gui/graphicsview/qsimplex_p.cpp b/src/gui/graphicsview/qsimplex_p.cpp index 00fc204..95003d2 100644 --- a/src/gui/graphicsview/qsimplex_p.cpp +++ b/src/gui/graphicsview/qsimplex_p.cpp @@ -285,24 +285,6 @@ bool QSimplex::setConstraints(const QList newConstraints) // anymore. clearColumns(firstArtificial, columns - 2); - #ifdef QT_DEBUG - // Ensure that at the end of the simplex each row should either: - // - Have a positive value on the column associated to its variable, or - // - Have zero values in all columns. - // - // This avoids a regression where restrictions would be lost - // due to randomness in the pivotRowForColumn method. - for (int i = 1; i < rows; ++i) { - int variableIndex = valueAt(i, 0); - if (valueAt(i, variableIndex) > 0) - continue; - - for (int j = 1; j < columns; ++j) { - Q_ASSERT(valueAt(i, j) == 0); - } - } - #endif - return true; } @@ -537,6 +519,12 @@ qreal QSimplex::solver(solverFactor factor) solveMaxHelper(); collectResults(); + #ifdef QT_DEBUG + for (int i = 0; i < constraints.size(); ++i) { + Q_ASSERT(constraints[i]->isSatisfied()); + } + #endif + return factor * valueAt(0, columns - 1); } diff --git a/src/gui/graphicsview/qsimplex_p.h b/src/gui/graphicsview/qsimplex_p.h index 54b080d..b517cb9 100644 --- a/src/gui/graphicsview/qsimplex_p.h +++ b/src/gui/graphicsview/qsimplex_p.h @@ -94,8 +94,32 @@ struct QSimplexConstraint QPair helper; QSimplexVariable * artificial; -}; + #ifdef QT_DEBUG + bool isSatisfied() { + qreal leftHandSide(0); + + QHash::const_iterator iter; + for (iter = variables.constBegin(); iter != variables.constEnd(); ++iter) { + leftHandSide += iter.value() * iter.key()->result; + } + + Q_ASSERT(constant > 0 || qFuzzyCompare(1, 1 + constant)); + + if (qFuzzyCompare(1000 + leftHandSide, 1000 + constant)) + return true; + + switch (ratio) { + case LessOrEqual: + return leftHandSide < constant; + case MoreOrEqual: + return leftHandSide > constant; + default: + return false; + } + } + #endif +}; class QSimplex { -- cgit v0.12 From 0536b996759ef367e784310f472089eec583213f Mon Sep 17 00:00:00 2001 From: Caio Marcelo de Oliveira Filho Date: Fri, 25 Sep 2009 19:35:25 -0300 Subject: QGraphicsAnchorLayout: Add support for expanding SizePolicy with simplification Updating "refreshSizeHints" and "updateChildrenSizes" methods for standard, parallel and sequential anchors, in order to support the expanding SizePolicy flag. This adds the logic required to calculate equivalent expected/nominal expanding size (AnchorData::expSize) as well as the logic to propagate the effective size when in the expanding state (AnchorData::sizeAtExpected). Signed-off-by: Caio Marcelo de Oliveira Filho Reviewed-by: Eduardo M. Fleury --- src/gui/graphicsview/qgraphicsanchorlayout_p.cpp | 59 ++++++++++++++---------- src/gui/graphicsview/qgraphicsanchorlayout_p.h | 4 +- 2 files changed, 36 insertions(+), 27 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp b/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp index cf1429c..20ff03b 100644 --- a/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp +++ b/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp @@ -146,15 +146,11 @@ void AnchorData::refreshSizeHints(qreal effectiveSpacing) maxSize /= 2; } - // ### - expSize = prefSize; - // if (policy & QSizePolicy::ExpandFlag) { - // isExpanding = 1; - // expSize = maxSize; - // } else { - // isExpanding = 0; - // expSize = prefSize; - // } + if (policy & QSizePolicy::ExpandFlag) { + expSize = maxSize; + } else { + expSize = prefSize; + } // Set the anchor effective sizes to preferred. // @@ -175,8 +171,6 @@ void AnchorData::refreshSizeHints(qreal effectiveSpacing) expSize = effectiveSpacing; maxSize = effectiveSpacing; - isExpanding = 0; - sizeAtMinimum = prefSize; sizeAtPreferred = prefSize; sizeAtExpanding = prefSize; @@ -188,8 +182,8 @@ void ParallelAnchorData::updateChildrenSizes() { firstEdge->sizeAtMinimum = secondEdge->sizeAtMinimum = sizeAtMinimum; firstEdge->sizeAtPreferred = secondEdge->sizeAtPreferred = sizeAtPreferred; + firstEdge->sizeAtExpanding = secondEdge->sizeAtExpanding = sizeAtExpanding; firstEdge->sizeAtMaximum = secondEdge->sizeAtMaximum = sizeAtMaximum; - firstEdge->sizeAtExpanding = secondEdge->sizeAtExpanding = sizeAtPreferred; firstEdge->updateChildrenSizes(); secondEdge->updateChildrenSizes(); @@ -215,11 +209,11 @@ void ParallelAnchorData::refreshSizeHints_helper(qreal effectiveSpacing, minSize = qMax(firstEdge->minSize, secondEdge->minSize); maxSize = qMin(firstEdge->maxSize, secondEdge->maxSize); - prefSize = qMax(firstEdge->prefSize, secondEdge->prefSize); - prefSize = qMin(prefSize, maxSize); + expSize = qMax(firstEdge->expSize, secondEdge->expSize); + expSize = qMin(expSize, maxSize); - // ### - expSize = prefSize; + prefSize = qMax(firstEdge->prefSize, secondEdge->prefSize); + prefSize = qMin(prefSize, expSize); // See comment in AnchorData::refreshSizeHints() about sizeAt* values sizeAtMinimum = prefSize; @@ -260,6 +254,21 @@ static qreal getFactor(qreal value, qreal min, qreal pref, qreal max) } } +static qreal getExpandingFactor(const qreal &expSize, const qreal &sizeAtPreferred, + const qreal &sizeAtExpanding, const qreal &sizeAtMaximum) +{ + const qreal lower = qMin(sizeAtPreferred, sizeAtMaximum); + const qreal upper = qMax(sizeAtPreferred, sizeAtMaximum); + const qreal boundedExpSize = qBound(lower, expSize, upper); + + const qreal bandSize = sizeAtMaximum - boundedExpSize; + if (bandSize == 0) { + return 0; + } else { + return (sizeAtExpanding - boundedExpSize) / bandSize; + } +} + void SequentialAnchorData::updateChildrenSizes() { // ### REMOVE ME @@ -269,15 +278,18 @@ void SequentialAnchorData::updateChildrenSizes() Q_ASSERT(sizeAtMinimum < maxSize || qFuzzyCompare(sizeAtMinimum, maxSize)); Q_ASSERT(sizeAtPreferred > minSize || qFuzzyCompare(sizeAtPreferred, minSize)); Q_ASSERT(sizeAtPreferred < maxSize || qFuzzyCompare(sizeAtPreferred, maxSize)); + Q_ASSERT(sizeAtExpanding > minSize || qFuzzyCompare(sizeAtExpanding, minSize)); + Q_ASSERT(sizeAtExpanding < maxSize || qFuzzyCompare(sizeAtExpanding, maxSize)); Q_ASSERT(sizeAtMaximum > minSize || qFuzzyCompare(sizeAtMaximum, minSize)); Q_ASSERT(sizeAtMaximum < maxSize || qFuzzyCompare(sizeAtMaximum, maxSize)); // Band here refers if the value is in the Minimum To Preferred // band (the lower band) or the Preferred To Maximum (the upper band). - qreal minFactor = getFactor(sizeAtMinimum, minSize, prefSize, maxSize); - qreal prefFactor = getFactor(sizeAtPreferred, minSize, prefSize, maxSize); - qreal maxFactor = getFactor(sizeAtMaximum, minSize, prefSize, maxSize); + const qreal minFactor = getFactor(sizeAtMinimum, minSize, prefSize, maxSize); + const qreal prefFactor = getFactor(sizeAtPreferred, minSize, prefSize, maxSize); + const qreal maxFactor = getFactor(sizeAtMaximum, minSize, prefSize, maxSize); + const qreal expFactor = getExpandingFactor(expSize, sizeAtPreferred, sizeAtExpanding, sizeAtMaximum); for (int i = 0; i < m_edges.count(); ++i) { AnchorData *e = m_edges.at(i); @@ -291,8 +303,10 @@ void SequentialAnchorData::updateChildrenSizes() bandSize = maxFactor > 0 ? e->maxSize - e->prefSize : e->prefSize - e->minSize; e->sizeAtMaximum = e->prefSize + bandSize * maxFactor; - // ### - e->sizeAtExpanding = e->sizeAtPreferred; + const qreal lower = qMin(e->sizeAtPreferred, e->sizeAtMaximum); + const qreal upper = qMax(e->sizeAtPreferred, e->sizeAtMaximum); + const qreal edgeBoundedExpSize = qBound(lower, e->expSize, upper); + e->sizeAtExpanding = edgeBoundedExpSize + expFactor * (e->sizeAtMaximum - edgeBoundedExpSize); e->updateChildrenSizes(); } @@ -324,9 +338,6 @@ void SequentialAnchorData::refreshSizeHints_helper(qreal effectiveSpacing, maxSize += edge->maxSize; } - // ### - expSize = prefSize; - // See comment in AnchorData::refreshSizeHints() about sizeAt* values sizeAtMinimum = prefSize; sizeAtPreferred = prefSize; diff --git a/src/gui/graphicsview/qgraphicsanchorlayout_p.h b/src/gui/graphicsview/qgraphicsanchorlayout_p.h index 8f67b2c..aac4f96 100644 --- a/src/gui/graphicsview/qgraphicsanchorlayout_p.h +++ b/src/gui/graphicsview/qgraphicsanchorlayout_p.h @@ -156,8 +156,7 @@ struct AnchorData : public QSimplexVariable { sizeAtMinimum(0), sizeAtPreferred(0), sizeAtExpanding(0), sizeAtMaximum(0), graphicsAnchor(0), skipInPreferred(0), - type(Normal), hasSize(true), isLayoutAnchor(false), - isExpanding(false) {} + type(Normal), hasSize(true), isLayoutAnchor(false) {} virtual void updateChildrenSizes() {} virtual void refreshSizeHints(qreal effectiveSpacing); @@ -214,7 +213,6 @@ struct AnchorData : public QSimplexVariable { uint type : 2; // either Normal, Sequential or Parallel uint hasSize : 1; // if false, get size from style. uint isLayoutAnchor : 1; // if this anchor is connected to a layout 'edge' - uint isExpanding : 1; // if true, expands before other anchors }; #ifdef QT_DEBUG -- cgit v0.12 From 89ea5d0cc0b00a1d4e8f3e700b86f168cf4437ed Mon Sep 17 00:00:00 2001 From: "Eduardo M. Fleury" Date: Wed, 30 Sep 2009 12:25:34 -0300 Subject: QGraphicsAnchorLayout: Fix creation of internal layout anchors Since the AnchorData cleanup commit (c974aca8) all anchor initialization is being done by refreshSizeHints. However that method was not able to properly initialize the internal layout anchors. This commit refactors that method both to add the functionality and improve readability. Signed-off-by: Eduardo M. Fleury Reviewed-by: Caio Marcelo de Oliveira Filho --- src/gui/graphicsview/qgraphicsanchorlayout_p.cpp | 145 ++++++++++++--------- .../tst_qgraphicsanchorlayout.cpp | 2 +- 2 files changed, 84 insertions(+), 63 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp b/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp index 20ff03b..8139b2b 100644 --- a/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp +++ b/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp @@ -92,90 +92,111 @@ qreal QGraphicsAnchorPrivate::spacing() const } +static void sizeHintsFromItem(QGraphicsLayoutItem *item, + const QGraphicsAnchorLayoutPrivate::Orientation orient, + qreal *minSize, qreal *prefSize, + qreal *expSize, qreal *maxSize) +{ + QSizePolicy::Policy policy; + qreal minSizeHint; + qreal prefSizeHint; + qreal maxSizeHint; + + if (orient == QGraphicsAnchorLayoutPrivate::Horizontal) { + policy = item->sizePolicy().horizontalPolicy(); + minSizeHint = item->effectiveSizeHint(Qt::MinimumSize).width(); + prefSizeHint = item->effectiveSizeHint(Qt::PreferredSize).width(); + maxSizeHint = item->effectiveSizeHint(Qt::MaximumSize).width(); + } else { + policy = item->sizePolicy().verticalPolicy(); + minSizeHint = item->effectiveSizeHint(Qt::MinimumSize).height(); + prefSizeHint = item->effectiveSizeHint(Qt::PreferredSize).height(); + maxSizeHint = item->effectiveSizeHint(Qt::MaximumSize).height(); + } + + // minSize, prefSize and maxSize are initialized + // with item's preferred Size: this is QSizePolicy::Fixed. + // + // Then we check each flag to find the resultant QSizePolicy, + // according to the following table: + // + // constant value + // QSizePolicy::Fixed 0 + // QSizePolicy::Minimum GrowFlag + // QSizePolicy::Maximum ShrinkFlag + // QSizePolicy::Preferred GrowFlag | ShrinkFlag + // QSizePolicy::Ignored GrowFlag | ShrinkFlag | IgnoreFlag + + if (policy & QSizePolicy::ShrinkFlag) + *minSize = minSizeHint; + else + *minSize = prefSizeHint; + + if (policy & QSizePolicy::GrowFlag) + *maxSize = maxSizeHint; + else + *maxSize = prefSizeHint; + + // Note that these two initializations are affected by the previous flags + if (policy & QSizePolicy::IgnoreFlag) + *prefSize = *maxSize; + else + *prefSize = prefSizeHint; + + if (policy & QSizePolicy::ExpandFlag) + *expSize = *maxSize; + else + *expSize = *prefSize; +} + void AnchorData::refreshSizeHints(qreal effectiveSpacing) { - if (!isLayoutAnchor && (from->m_item == to->m_item)) { - QGraphicsLayoutItem *item = from->m_item; + const bool isInternalAnchor = from->m_item == to->m_item; - const QGraphicsAnchorLayoutPrivate::Orientation orient = QGraphicsAnchorLayoutPrivate::edgeOrientation(from->m_edge); - const Qt::AnchorPoint centerEdge = QGraphicsAnchorLayoutPrivate::pickEdge(Qt::AnchorHorizontalCenter, orient); + if (isInternalAnchor) { + const QGraphicsAnchorLayoutPrivate::Orientation orient = + QGraphicsAnchorLayoutPrivate::edgeOrientation(from->m_edge); - QSizePolicy::Policy policy; - qreal minSizeHint, prefSizeHint, maxSizeHint; - if (orient == QGraphicsAnchorLayoutPrivate::Horizontal) { - policy = item->sizePolicy().horizontalPolicy(); - minSizeHint = item->effectiveSizeHint(Qt::MinimumSize).width(); - prefSizeHint = item->effectiveSizeHint(Qt::PreferredSize).width(); - maxSizeHint = item->effectiveSizeHint(Qt::MaximumSize).width(); + if (isLayoutAnchor) { + minSize = 0; + prefSize = 0; + expSize = 0; + maxSize = QWIDGETSIZE_MAX; } else { - policy = item->sizePolicy().verticalPolicy(); - minSizeHint = item->effectiveSizeHint(Qt::MinimumSize).height(); - prefSizeHint = item->effectiveSizeHint(Qt::PreferredSize).height(); - maxSizeHint = item->effectiveSizeHint(Qt::MaximumSize).height(); + QGraphicsLayoutItem *item = from->m_item; + sizeHintsFromItem(item, orient, &minSize, &prefSize, &expSize, &maxSize); } - // minSize, prefSize and maxSize are initialized - // with item's preferred Size: this is QSizePolicy::Fixed. - // - // Then we check each flag to find the resultant QSizePolicy, - // according to the following table: - // - // constant value - // QSizePolicy::Fixed 0 - // QSizePolicy::Minimum GrowFlag - // QSizePolicy::Maximum ShrinkFlag - // QSizePolicy::Preferred GrowFlag | ShrinkFlag - // QSizePolicy::Ignored GrowFlag | ShrinkFlag | IgnoreFlag - prefSize = prefSizeHint; - minSize = prefSize; - maxSize = prefSize; - - if (policy & QSizePolicy::GrowFlag) - maxSize = maxSizeHint; - - if (policy & QSizePolicy::ShrinkFlag) - minSize = minSizeHint; - - if (policy & QSizePolicy::IgnoreFlag) - prefSize = minSize; + const Qt::AnchorPoint centerEdge = + QGraphicsAnchorLayoutPrivate::pickEdge(Qt::AnchorHorizontalCenter, orient); bool hasCenter = (from->m_edge == centerEdge || to->m_edge == centerEdge); if (hasCenter) { minSize /= 2; prefSize /= 2; + expSize /= 2; maxSize /= 2; } - if (policy & QSizePolicy::ExpandFlag) { - expSize = maxSize; - } else { - expSize = prefSize; - } - - // Set the anchor effective sizes to preferred. - // - // Note: The idea here is that all items should remain at their - // preferred size unless where that's impossible. In cases where - // the item is subject to restrictions (anchored to the layout - // edges, for instance), the simplex solver will be run to - // recalculate and override the values we set here. - sizeAtMinimum = prefSize; - sizeAtPreferred = prefSize; - sizeAtExpanding = prefSize; - sizeAtMaximum = prefSize; - } else if (!hasSize) { // Anchor has no size defined, use given default information minSize = effectiveSpacing; prefSize = effectiveSpacing; expSize = effectiveSpacing; maxSize = effectiveSpacing; - - sizeAtMinimum = prefSize; - sizeAtPreferred = prefSize; - sizeAtExpanding = prefSize; - sizeAtMaximum = prefSize; } + + // Set the anchor effective sizes to preferred. + // + // Note: The idea here is that all items should remain at their + // preferred size unless where that's impossible. In cases where + // the item is subject to restrictions (anchored to the layout + // edges, for instance), the simplex solver will be run to + // recalculate and override the values we set here. + sizeAtMinimum = prefSize; + sizeAtPreferred = prefSize; + sizeAtExpanding = prefSize; + sizeAtMaximum = prefSize; } void ParallelAnchorData::updateChildrenSizes() diff --git a/tests/auto/qgraphicsanchorlayout/tst_qgraphicsanchorlayout.cpp b/tests/auto/qgraphicsanchorlayout/tst_qgraphicsanchorlayout.cpp index 4ad48c7..91e5bb3 100644 --- a/tests/auto/qgraphicsanchorlayout/tst_qgraphicsanchorlayout.cpp +++ b/tests/auto/qgraphicsanchorlayout/tst_qgraphicsanchorlayout.cpp @@ -1271,7 +1271,7 @@ void tst_QGraphicsAnchorLayout::sizePolicy() w1->adjustSize(); QCOMPARE(l->effectiveSizeHint(Qt::MinimumSize), QSizeF(0, 0)); - QCOMPARE(l->effectiveSizeHint(Qt::PreferredSize), QSizeF(0, 0)); + QCOMPARE(l->effectiveSizeHint(Qt::PreferredSize), QSizeF(100, 100)); QCOMPARE(l->effectiveSizeHint(Qt::MaximumSize), QSizeF(100, 100)); delete p; -- cgit v0.12 From 0d1e86fdfb7958a1affb93c7760c22fca9a0fcb2 Mon Sep 17 00:00:00 2001 From: Jesus Sanchez-Palencia Date: Fri, 25 Sep 2009 18:53:15 -0300 Subject: QGraphicsAnchorLayout: Adding a Float Conflict test case Now we don't support floating items and so we should consider that the layout has a conflict when handling this situation. Signed-off-by: Jesus Sanchez-Palencia Reviewed-by: Caio Marcelo de Oliveira Filho --- .../tst_qgraphicsanchorlayout.cpp | 69 ++++++++++++++++++++++ .../tst_qgraphicsanchorlayout1.cpp | 4 +- 2 files changed, 72 insertions(+), 1 deletion(-) diff --git a/tests/auto/qgraphicsanchorlayout/tst_qgraphicsanchorlayout.cpp b/tests/auto/qgraphicsanchorlayout/tst_qgraphicsanchorlayout.cpp index 91e5bb3..b076631 100644 --- a/tests/auto/qgraphicsanchorlayout/tst_qgraphicsanchorlayout.cpp +++ b/tests/auto/qgraphicsanchorlayout/tst_qgraphicsanchorlayout.cpp @@ -72,6 +72,7 @@ private slots: void expandingSequence(); void expandingSequenceFairDistribution(); void expandingParallel(); + void floatConflict(); }; class RectWidget : public QGraphicsWidget @@ -158,7 +159,17 @@ void tst_QGraphicsAnchorLayout::simple() QGraphicsAnchorLayout *l = new QGraphicsAnchorLayout; l->setContentsMargins(0, 0, 0, 0); + + // Horizontal + l->addAnchor(w1, Qt::AnchorLeft, l, Qt::AnchorLeft); l->addAnchor(w1, Qt::AnchorRight, w2, Qt::AnchorLeft); + l->addAnchor(w2, Qt::AnchorRight, l, Qt::AnchorRight); + + // Vertical + l->addAnchor(w1, Qt::AnchorTop, l, Qt::AnchorTop); + l->addAnchor(w2, Qt::AnchorTop, l, Qt::AnchorTop); + l->addAnchor(w1, Qt::AnchorBottom, l, Qt::AnchorBottom); + l->addAnchor(w2, Qt::AnchorBottom, l, Qt::AnchorBottom); QGraphicsWidget p; p.setLayout(l); @@ -1152,12 +1163,22 @@ void tst_QGraphicsAnchorLayout::delete_anchor() QGraphicsAnchorLayout *l = new QGraphicsAnchorLayout; l->setSpacing(0); l->setContentsMargins(0, 0, 0, 0); + + // Horizontal l->addAnchor(l, Qt::AnchorLeft, w1, Qt::AnchorLeft); l->addAnchor(w1, Qt::AnchorRight, w2, Qt::AnchorLeft); l->addAnchor(w2, Qt::AnchorRight, l, Qt::AnchorRight); l->addAnchor(w1, Qt::AnchorRight, w3, Qt::AnchorLeft); l->addAnchor(w3, Qt::AnchorRight, l, Qt::AnchorRight); + // Vertical + l->addAnchor(w1, Qt::AnchorTop, l, Qt::AnchorTop); + l->addAnchor(w1, Qt::AnchorBottom, l, Qt::AnchorBottom); + l->addAnchor(w2, Qt::AnchorTop, l, Qt::AnchorTop); + l->addAnchor(w2, Qt::AnchorBottom, l, Qt::AnchorBottom); + l->addAnchor(w3, Qt::AnchorTop, l, Qt::AnchorTop); + l->addAnchor(w3, Qt::AnchorBottom, l, Qt::AnchorBottom); + QGraphicsAnchor *anchor = l->anchor(w3, Qt::AnchorRight, l, Qt::AnchorRight); anchor->setSpacing(10); @@ -1521,5 +1542,53 @@ void tst_QGraphicsAnchorLayout::expandingParallel() QCOMPARE(newLayoutMaximumSize.width(), qreal(300)); } +void tst_QGraphicsAnchorLayout::floatConflict() +{ + QGraphicsWidget *a = createItem(QSizeF(80,10), QSizeF(90,10), QSizeF(100,10), "a"); + QGraphicsWidget *b = createItem(QSizeF(80,10), QSizeF(90,10), QSizeF(100,10), "b"); + + QGraphicsAnchorLayout *l; + QGraphicsWidget *p = new QGraphicsWidget(0, Qt::Window); + + l = new QGraphicsAnchorLayout; + l->setContentsMargins(0, 0, 0, 0); + + p->setLayout(l); + + // horizontal + // with this anchor we have two floating items + setAnchor(l, a, Qt::AnchorRight, b, Qt::AnchorLeft); + + // Just checking if the layout is handling well the removal of floating items + delete l->anchor(a, Qt::AnchorRight, b, Qt::AnchorLeft); + QCOMPARE(l->count(), 0); + QCOMPARE(layoutHasConflict(l), false); + + // setting back the same anchor + setAnchor(l, a, Qt::AnchorRight, b, Qt::AnchorLeft); + + // We don't support floating items but they should be counted as if they are in the layout + QCOMPARE(l->count(), 2); + // Although, we have an invalid situation + QCOMPARE(layoutHasConflict(l), true); + + // Semi-floats are supported + setAnchor(l, a, Qt::AnchorLeft, l, Qt::AnchorLeft); + QCOMPARE(l->count(), 2); + + // Vertically the layout has floating items. Therefore, we have a conflict + QCOMPARE(layoutHasConflict(l), true); + + // No more floating items + setAnchor(l, b, Qt::AnchorRight, l, Qt::AnchorRight); + setAnchor(l, a, Qt::AnchorTop, l, Qt::AnchorTop); + setAnchor(l, a, Qt::AnchorBottom, l, Qt::AnchorBottom); + setAnchor(l, b, Qt::AnchorTop, l, Qt::AnchorTop); + setAnchor(l, b, Qt::AnchorBottom, l, Qt::AnchorBottom); + QCOMPARE(layoutHasConflict(l), false); + + delete p; +} + QTEST_MAIN(tst_QGraphicsAnchorLayout) #include "tst_qgraphicsanchorlayout.moc" diff --git a/tests/auto/qgraphicsanchorlayout1/tst_qgraphicsanchorlayout1.cpp b/tests/auto/qgraphicsanchorlayout1/tst_qgraphicsanchorlayout1.cpp index a521b78..caf078e 100644 --- a/tests/auto/qgraphicsanchorlayout1/tst_qgraphicsanchorlayout1.cpp +++ b/tests/auto/qgraphicsanchorlayout1/tst_qgraphicsanchorlayout1.cpp @@ -530,16 +530,18 @@ void tst_QGraphicsAnchorLayout1::testIsValid() TestWidget *widget1 = new TestWidget(); TestWidget *widget2 = new TestWidget(); + // Vertically the layout has floating items. Therefore, we have a conflict layout->setAnchor(layout, Qt::AnchorLeft, widget1, Qt::AnchorLeft, 0.1); layout->setAnchor(layout, Qt::AnchorRight, widget1, Qt::AnchorRight, -0.1); + // Horizontally the layout has floating items. Therefore, we have a conflict layout->setAnchor(layout, Qt::AnchorTop, widget2, Qt::AnchorTop, 0.1); layout->setAnchor(layout, Qt::AnchorBottom, widget2, Qt::AnchorBottom, -0.1); widget->setLayout(layout); widget->setGeometry(QRectF(0,0,100,100)); - QCOMPARE(layout->isValid(), true); + QCOMPARE(layout->isValid(), false); delete widget; } } -- cgit v0.12 From 18da388497b5f3cbc77298a70bc83f037f06c013 Mon Sep 17 00:00:00 2001 From: Jesus Sanchez-Palencia Date: Tue, 29 Sep 2009 14:02:27 -0300 Subject: QGraphicsAnchorLayoutPrivate: Handling floating items as an invalid layout situation We make use of the anchor visited on findPaths() to keep track of how many items are visited when walking on the graph. We can use this information of how many items are reachable (non-float) in order to check if we have floating items (not reachable from any graph vertex). If so, we have a situation not supported by now. Signed-off-by: Jesus Sanchez-Palencia Reviewed-by: Caio Marcelo de Oliveira Filho --- src/gui/graphicsview/qgraphicsanchorlayout_p.cpp | 51 +++++++++++++++++++++++- src/gui/graphicsview/qgraphicsanchorlayout_p.h | 3 ++ 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp b/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp index 8139b2b..e760642 100644 --- a/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp +++ b/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp @@ -1841,6 +1841,11 @@ void QGraphicsAnchorLayoutPrivate::findPaths(Orientation orientation) queue.enqueue(qMakePair(pair.second, v)); } } + + // We will walk through every reachable items (non-float) and mark them + // by keeping their references on m_nonFloatItems. With this we can easily + // identify non-float and float items. + identifyNonFloatItems(visited, orientation); } /*! @@ -1999,6 +2004,46 @@ QGraphicsAnchorLayoutPrivate::getGraphParts(Orientation orientation) } /*! + \internal + + Use all visited Anchors on findPaths() so we can identify non-float Items. +*/ +void QGraphicsAnchorLayoutPrivate::identifyNonFloatItems(QSet visited, Orientation orientation) +{ + m_nonFloatItems[orientation].clear(); + + foreach (const AnchorData *ad, visited) + identifyNonFloatItems_helper(ad, orientation); +} + +/*! + \internal + + Given an anchor, if it is an internal anchor and Normal we must mark it's item as non-float. + If the anchor is Sequential or Parallel, we must iterate on its children recursively until we reach + internal anchors (items). +*/ +void QGraphicsAnchorLayoutPrivate::identifyNonFloatItems_helper(const AnchorData *ad, Orientation orientation) +{ + Q_Q(QGraphicsAnchorLayout); + + switch(ad->type) { + case AnchorData::Normal: + if (ad->from->m_item == ad->to->m_item && ad->to->m_item != q) + m_nonFloatItems[orientation].insert(ad->to->m_item); + break; + case AnchorData::Sequential: + foreach (const AnchorData *d, static_cast(ad)->m_edges) + identifyNonFloatItems_helper(d, orientation); + break; + case AnchorData::Parallel: + identifyNonFloatItems_helper(static_cast(ad)->firstEdge, orientation); + identifyNonFloatItems_helper(static_cast(ad)->secondEdge, orientation); + break; + } +} + +/*! \internal Use the current vertices distance to calculate and set the geometry of @@ -2491,7 +2536,11 @@ bool QGraphicsAnchorLayoutPrivate::hasConflicts() const { QGraphicsAnchorLayoutPrivate *that = const_cast(this); that->calculateGraphs(); - return graphHasConflicts[0] || graphHasConflicts[1]; + + bool floatConflict = (m_nonFloatItems[0].size() < items.size()) + || (m_nonFloatItems[1].size() < items.size()); + + return graphHasConflicts[0] || graphHasConflicts[1] || floatConflict; } #ifdef QT_DEBUG diff --git a/src/gui/graphicsview/qgraphicsanchorlayout_p.h b/src/gui/graphicsview/qgraphicsanchorlayout_p.h index aac4f96..1a74d85 100644 --- a/src/gui/graphicsview/qgraphicsanchorlayout_p.h +++ b/src/gui/graphicsview/qgraphicsanchorlayout_p.h @@ -445,6 +445,8 @@ public: void constraintsFromPaths(Orientation orientation); QList constraintsFromSizeHints(const QList &anchors); QList > getGraphParts(Orientation orientation); + void identifyNonFloatItems(QSet visited, Orientation orientation); + void identifyNonFloatItems_helper(const AnchorData *ad, Orientation orientation); inline AnchorVertex *internalVertex(const QPair &itemEdge) const { @@ -511,6 +513,7 @@ public: // ### bool graphSimplified[2]; bool graphHasConflicts[2]; + QSet m_nonFloatItems[2]; uint calculateGraphCacheDirty : 1; }; -- cgit v0.12 From 6367a702b13a440557d4e0a405ae6d34ef0b778f Mon Sep 17 00:00:00 2001 From: Jesus Sanchez-Palencia Date: Tue, 29 Sep 2009 15:22:26 -0300 Subject: QGraphicsAnchorLayoutPrivate: Fixing initial geometry values for new layout items Now every item starts with its geometry on ((0,0), preferredSize()). By doing this we guarantee that every item will have a known initial value, which can be specially useful on float cases for instance. Signed-off-by: Jesus Sanchez-Palencia Reviewed-by: Caio Marcelo de Oliveira Filho --- src/gui/graphicsview/qgraphicsanchorlayout_p.cpp | 37 ++++++++++++++++-------- 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp b/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp index e760642..87f5aa0 100644 --- a/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp +++ b/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp @@ -2068,22 +2068,35 @@ void QGraphicsAnchorLayoutPrivate::setItemsGeometries(const QRectF &geom) right = geom.right() - right; foreach (QGraphicsLayoutItem *item, items) { - firstH = internalVertex(item, Qt::AnchorLeft); - secondH = internalVertex(item, Qt::AnchorRight); - firstV = internalVertex(item, Qt::AnchorTop); - secondV = internalVertex(item, Qt::AnchorBottom); - QRectF newGeom; - newGeom.setTop(top + firstV->distance); - newGeom.setBottom(top + secondV->distance); + QSizeF itemPreferredSize = item->effectiveSizeHint(Qt::PreferredSize); + if (m_nonFloatItems[Horizontal].contains(item)) { + firstH = internalVertex(item, Qt::AnchorLeft); + secondH = internalVertex(item, Qt::AnchorRight); + + if (visualDir == Qt::LeftToRight) { + newGeom.setLeft(left + firstH->distance); + newGeom.setRight(left + secondH->distance); + } else { + newGeom.setLeft(right - secondH->distance); + newGeom.setRight(right - firstH->distance); + } + } else { + newGeom.setLeft(0); + newGeom.setRight(itemPreferredSize.width()); + } + + if (m_nonFloatItems[Vertical].contains(item)) { + firstV = internalVertex(item, Qt::AnchorTop); + secondV = internalVertex(item, Qt::AnchorBottom); - if (visualDir == Qt::LeftToRight) { - newGeom.setLeft(left + firstH->distance); - newGeom.setRight(left + secondH->distance); + newGeom.setTop(top + firstV->distance); + newGeom.setBottom(top + secondV->distance); } else { - newGeom.setLeft(right - secondH->distance); - newGeom.setRight(right - firstH->distance); + newGeom.setTop(0); + newGeom.setBottom(itemPreferredSize.height()); } + item->setGeometry(newGeom); } } -- cgit v0.12 From 709cc9140407280aa5c871d4650c123002dfdd19 Mon Sep 17 00:00:00 2001 From: "Eduardo M. Fleury" Date: Thu, 1 Oct 2009 15:04:20 -0300 Subject: QGraphicsAnchorLayout: Enable "float" Orbit test Now supported after float patches. Signed-off-by: Eduardo M. Fleury Reviewed-by: Jesus Sanchez-Palencia --- tests/auto/qgraphicsanchorlayout1/tst_qgraphicsanchorlayout1.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/auto/qgraphicsanchorlayout1/tst_qgraphicsanchorlayout1.cpp b/tests/auto/qgraphicsanchorlayout1/tst_qgraphicsanchorlayout1.cpp index caf078e..148b2c8 100644 --- a/tests/auto/qgraphicsanchorlayout1/tst_qgraphicsanchorlayout1.cpp +++ b/tests/auto/qgraphicsanchorlayout1/tst_qgraphicsanchorlayout1.cpp @@ -1415,9 +1415,6 @@ void tst_QGraphicsAnchorLayout1::testMixedSpacing_data() QTest::newRow("One widget, unsolvable") << QSizeF(10, 10) << theData << theResult; } - // ### BUG. We are not handling "floating" elements properly. Ie. elements that - // have no anchors in a given orientation. - if (0) // Two widgets, one has fixed size { BasicLayoutTestDataList theData; -- cgit v0.12 From d6d0b2ef5223b4a40e8907104eb1d9e827507a42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan-Arve=20S=C3=A6ther?= Date: Wed, 7 Oct 2009 10:51:26 +0200 Subject: Cosmetic fixes to the previous patches. There is only one change in the actual code here, and it simply removes an unnecessary initialization of hasSize in the ctors of the composite anchors. --- src/gui/graphicsview/qgraphicsanchorlayout_p.cpp | 68 +++++++++++++----------- src/gui/graphicsview/qgraphicsanchorlayout_p.h | 2 - src/gui/graphicsview/qsimplex_p.cpp | 4 +- src/gui/graphicsview/qsimplex_p.h | 4 +- 4 files changed, 40 insertions(+), 38 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp b/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp index 87f5aa0..34071cc 100644 --- a/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp +++ b/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp @@ -2409,47 +2409,51 @@ bool QGraphicsAnchorLayoutPrivate::solvePreferred(QList co return feasible; } -/*! Calculate the "expanding" keyframe +/*! + \internal + Calculate the "expanding" keyframe - This new keyframe sits between the already existing sizeAtPreferred and - sizeAtMaximum keyframes. Its goal is to modify the interpolation between - the latter as to respect the "expanding" size policy of some anchors. + This new keyframe sits between the already existing sizeAtPreferred and + sizeAtMaximum keyframes. Its goal is to modify the interpolation between + the latter as to respect the "expanding" size policy of some anchors. - Previously all items would be subject to a linear interpolation between - sizeAtPreferred and sizeAtMaximum values. This will change now, the - expanding anchors will change their size before the others. To calculate - this keyframe we use the following logic: + Previously all items would be subject to a linear interpolation between + sizeAtPreferred and sizeAtMaximum values. This will change now, the + expanding anchors will change their size before the others. To calculate + this keyframe we use the following logic: - 1) Ask each anchor for their desired expanding size (ad->expSize), this - value depends on the anchor expanding property in the following way: + 1) Ask each anchor for their desired expanding size (ad->expSize), this + value depends on the anchor expanding property in the following way: - - Expanding anchors want to grow towards their maximum size - - Non-expanding anchors want to remain at their preferred size. - - Composite anchors want to grow towards somewhere between their - preferred sizes. (*) + - Expanding normal anchors want to grow towards their maximum size + - Non-expanding normal anchors want to remain at their preferred size. + - Sequential anchors wants to grow towards a size that is calculated by: + summarizing it's child anchors, where it will use preferred size for non-expanding anchors + and maximum size for expanding anchors. + - Parallel anchors want to grow towards the smallest maximum size of all the expanding anchors. - 2) Clamp their desired values to the value they assume in the neighbour - keyframes (sizeAtPreferred and sizeAtExpanding) + 2) Clamp their desired values to the value they assume in the neighbour + keyframes (sizeAtPreferred and sizeAtExpanding) - 3) Run simplex with a setup that ensures the following: + 3) Run simplex with a setup that ensures the following: - a. Anchors will change their value from their sizeAtPreferred towards - their sizeAtMaximum as much as required to ensure that ALL anchors - reach their respective "desired" expanding sizes. + a. Anchors will change their value from their sizeAtPreferred towards + their sizeAtMaximum as much as required to ensure that ALL anchors + reach their respective "desired" expanding sizes. - b. No anchors will change their value beyond what is NEEDED to satisfy - the requirement above. + b. No anchors will change their value beyond what is NEEDED to satisfy + the requirement above. - The final result is that, at the "expanding" keyframe expanding anchors - will grow and take with them all anchors that are parallel to them. - However, non-expanding anchors will remain at their preferred size unless - they are forced to grow by a parallel expanding anchor. + The final result is that, at the "expanding" keyframe expanding anchors + will grow and take with them all anchors that are parallel to them. + However, non-expanding anchors will remain at their preferred size unless + they are forced to grow by a parallel expanding anchor. - Note: For anchors where the sizeAtPreferred is bigger than sizeAtPreferred, - the visual effect when the layout grows from its preferred size is - the following: Expanding anchors will keep their size while non - expanding ones will shrink. Only after non-expanding anchors have - shrinked all the way, the expanding anchors will start to shrink too. + Note: For anchors where the sizeAtPreferred is bigger than sizeAtMaximum, + the visual effect when the layout grows from its preferred size is + the following: Expanding anchors will keep their size while non + expanding ones will shrink. Only after non-expanding anchors have + shrinked all the way, the expanding anchors will start to shrink too. */ void QGraphicsAnchorLayoutPrivate::solveExpanding(QList constraints) { @@ -2495,7 +2499,7 @@ void QGraphicsAnchorLayoutPrivate::solveExpanding(QList co itemC->constant = qMax(boundedExpSize, ad->sizeAtMaximum); itemConstraints << itemC; - // Create objective to avoid the anchos from moving away from + // Create objective to avoid the anchors from moving away from // the preferred size more than the needed amount. (ensure 3.b) // The objective function is the distance between sizeAtPreferred // and sizeAtExpanding, it will be minimized. diff --git a/src/gui/graphicsview/qgraphicsanchorlayout_p.h b/src/gui/graphicsview/qgraphicsanchorlayout_p.h index 1a74d85..24b25de 100644 --- a/src/gui/graphicsview/qgraphicsanchorlayout_p.h +++ b/src/gui/graphicsview/qgraphicsanchorlayout_p.h @@ -227,7 +227,6 @@ struct SequentialAnchorData : public AnchorData SequentialAnchorData() : AnchorData() { type = AnchorData::Sequential; - hasSize = true; #ifdef QT_DEBUG name = QLatin1String("SequentialAnchorData"); #endif @@ -256,7 +255,6 @@ struct ParallelAnchorData : public AnchorData : AnchorData(), firstEdge(first), secondEdge(second) { type = AnchorData::Parallel; - hasSize = true; // ### Those asserts force that both child anchors have the same direction, // but can't we simplify a pair of anchors in opposite directions? diff --git a/src/gui/graphicsview/qsimplex_p.cpp b/src/gui/graphicsview/qsimplex_p.cpp index 95003d2..b8f8fb4 100644 --- a/src/gui/graphicsview/qsimplex_p.cpp +++ b/src/gui/graphicsview/qsimplex_p.cpp @@ -519,11 +519,11 @@ qreal QSimplex::solver(solverFactor factor) solveMaxHelper(); collectResults(); - #ifdef QT_DEBUG +#ifdef QT_DEBUG for (int i = 0; i < constraints.size(); ++i) { Q_ASSERT(constraints[i]->isSatisfied()); } - #endif +#endif return factor * valueAt(0, columns - 1); } diff --git a/src/gui/graphicsview/qsimplex_p.h b/src/gui/graphicsview/qsimplex_p.h index b517cb9..51991a9 100644 --- a/src/gui/graphicsview/qsimplex_p.h +++ b/src/gui/graphicsview/qsimplex_p.h @@ -95,7 +95,7 @@ struct QSimplexConstraint QPair helper; QSimplexVariable * artificial; - #ifdef QT_DEBUG +#ifdef QT_DEBUG bool isSatisfied() { qreal leftHandSide(0); @@ -118,7 +118,7 @@ struct QSimplexConstraint return false; } } - #endif +#endif }; class QSimplex -- cgit v0.12 From dde11ce47c2d83bae685f3ff032ee9e6e372058f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan-Arve=20S=C3=A6ther?= Date: Wed, 7 Oct 2009 11:30:30 +0200 Subject: Make some lines in the autotest more readable. --- .../qgraphicsanchorlayout/tst_qgraphicsanchorlayout.cpp | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/tests/auto/qgraphicsanchorlayout/tst_qgraphicsanchorlayout.cpp b/tests/auto/qgraphicsanchorlayout/tst_qgraphicsanchorlayout.cpp index b076631..286ea2d 100644 --- a/tests/auto/qgraphicsanchorlayout/tst_qgraphicsanchorlayout.cpp +++ b/tests/auto/qgraphicsanchorlayout/tst_qgraphicsanchorlayout.cpp @@ -161,15 +161,13 @@ void tst_QGraphicsAnchorLayout::simple() l->setContentsMargins(0, 0, 0, 0); // Horizontal - l->addAnchor(w1, Qt::AnchorLeft, l, Qt::AnchorLeft); + l->addAnchor(l, Qt::AnchorLeft, w1, Qt::AnchorLeft); l->addAnchor(w1, Qt::AnchorRight, w2, Qt::AnchorLeft); l->addAnchor(w2, Qt::AnchorRight, l, Qt::AnchorRight); // Vertical - l->addAnchor(w1, Qt::AnchorTop, l, Qt::AnchorTop); - l->addAnchor(w2, Qt::AnchorTop, l, Qt::AnchorTop); - l->addAnchor(w1, Qt::AnchorBottom, l, Qt::AnchorBottom); - l->addAnchor(w2, Qt::AnchorBottom, l, Qt::AnchorBottom); + l->addAnchors(l, w1, Qt::Vertical); + l->addAnchors(l, w2, Qt::Vertical); QGraphicsWidget p; p.setLayout(l); @@ -1172,12 +1170,9 @@ void tst_QGraphicsAnchorLayout::delete_anchor() l->addAnchor(w3, Qt::AnchorRight, l, Qt::AnchorRight); // Vertical - l->addAnchor(w1, Qt::AnchorTop, l, Qt::AnchorTop); - l->addAnchor(w1, Qt::AnchorBottom, l, Qt::AnchorBottom); - l->addAnchor(w2, Qt::AnchorTop, l, Qt::AnchorTop); - l->addAnchor(w2, Qt::AnchorBottom, l, Qt::AnchorBottom); - l->addAnchor(w3, Qt::AnchorTop, l, Qt::AnchorTop); - l->addAnchor(w3, Qt::AnchorBottom, l, Qt::AnchorBottom); + l->addAnchors(l, w1, Qt::Vertical); + l->addAnchors(l, w2, Qt::Vertical); + l->addAnchors(l, w3, Qt::Vertical); QGraphicsAnchor *anchor = l->anchor(w3, Qt::AnchorRight, l, Qt::AnchorRight); anchor->setSpacing(10); -- cgit v0.12 From fd99d512fdb3864fe750015916b8e6a2a27401c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan-Arve=20S=C3=A6ther?= Date: Wed, 7 Oct 2009 13:20:39 +0200 Subject: Store the floating items instead of the non-floating items. Makes the code a bit easier to read and speeds up setItemsGeometries() in the normal use-case. --- src/gui/graphicsview/qgraphicsanchorlayout_p.cpp | 41 +++++++++++++----------- src/gui/graphicsview/qgraphicsanchorlayout_p.h | 6 ++-- 2 files changed, 26 insertions(+), 21 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp b/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp index 34071cc..296930c 100644 --- a/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp +++ b/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp @@ -2008,14 +2008,20 @@ QGraphicsAnchorLayoutPrivate::getGraphParts(Orientation orientation) Use all visited Anchors on findPaths() so we can identify non-float Items. */ -void QGraphicsAnchorLayoutPrivate::identifyNonFloatItems(QSet visited, Orientation orientation) +void QGraphicsAnchorLayoutPrivate::identifyNonFloatItems(const QSet &visited, Orientation orientation) { - m_nonFloatItems[orientation].clear(); + QSet nonFloating; foreach (const AnchorData *ad, visited) - identifyNonFloatItems_helper(ad, orientation); + identifyNonFloatItems_helper(ad, &nonFloating); + + QSet allItems; + foreach (QGraphicsLayoutItem *item, items) + allItems.insert(item); + m_floatItems[orientation] = allItems - nonFloating; } + /*! \internal @@ -2023,22 +2029,22 @@ void QGraphicsAnchorLayoutPrivate::identifyNonFloatItems(QSet visi If the anchor is Sequential or Parallel, we must iterate on its children recursively until we reach internal anchors (items). */ -void QGraphicsAnchorLayoutPrivate::identifyNonFloatItems_helper(const AnchorData *ad, Orientation orientation) +void QGraphicsAnchorLayoutPrivate::identifyNonFloatItems_helper(const AnchorData *ad, QSet *nonFloatingItemsIdentifiedSoFar) { Q_Q(QGraphicsAnchorLayout); switch(ad->type) { case AnchorData::Normal: if (ad->from->m_item == ad->to->m_item && ad->to->m_item != q) - m_nonFloatItems[orientation].insert(ad->to->m_item); + nonFloatingItemsIdentifiedSoFar->insert(ad->to->m_item); break; case AnchorData::Sequential: foreach (const AnchorData *d, static_cast(ad)->m_edges) - identifyNonFloatItems_helper(d, orientation); + identifyNonFloatItems_helper(d, nonFloatingItemsIdentifiedSoFar); break; case AnchorData::Parallel: - identifyNonFloatItems_helper(static_cast(ad)->firstEdge, orientation); - identifyNonFloatItems_helper(static_cast(ad)->secondEdge, orientation); + identifyNonFloatItems_helper(static_cast(ad)->firstEdge, nonFloatingItemsIdentifiedSoFar); + identifyNonFloatItems_helper(static_cast(ad)->secondEdge, nonFloatingItemsIdentifiedSoFar); break; } } @@ -2070,7 +2076,10 @@ void QGraphicsAnchorLayoutPrivate::setItemsGeometries(const QRectF &geom) foreach (QGraphicsLayoutItem *item, items) { QRectF newGeom; QSizeF itemPreferredSize = item->effectiveSizeHint(Qt::PreferredSize); - if (m_nonFloatItems[Horizontal].contains(item)) { + if (m_floatItems[Horizontal].contains(item)) { + newGeom.setLeft(0); + newGeom.setRight(itemPreferredSize.width()); + } else { firstH = internalVertex(item, Qt::AnchorLeft); secondH = internalVertex(item, Qt::AnchorRight); @@ -2081,20 +2090,17 @@ void QGraphicsAnchorLayoutPrivate::setItemsGeometries(const QRectF &geom) newGeom.setLeft(right - secondH->distance); newGeom.setRight(right - firstH->distance); } - } else { - newGeom.setLeft(0); - newGeom.setRight(itemPreferredSize.width()); } - if (m_nonFloatItems[Vertical].contains(item)) { + if (m_floatItems[Vertical].contains(item)) { + newGeom.setTop(0); + newGeom.setBottom(itemPreferredSize.height()); + } else { firstV = internalVertex(item, Qt::AnchorTop); secondV = internalVertex(item, Qt::AnchorBottom); newGeom.setTop(top + firstV->distance); newGeom.setBottom(top + secondV->distance); - } else { - newGeom.setTop(0); - newGeom.setBottom(itemPreferredSize.height()); } item->setGeometry(newGeom); @@ -2554,8 +2560,7 @@ bool QGraphicsAnchorLayoutPrivate::hasConflicts() const QGraphicsAnchorLayoutPrivate *that = const_cast(this); that->calculateGraphs(); - bool floatConflict = (m_nonFloatItems[0].size() < items.size()) - || (m_nonFloatItems[1].size() < items.size()); + bool floatConflict = !m_floatItems[0].isEmpty() || !m_floatItems[1].isEmpty(); return graphHasConflicts[0] || graphHasConflicts[1] || floatConflict; } diff --git a/src/gui/graphicsview/qgraphicsanchorlayout_p.h b/src/gui/graphicsview/qgraphicsanchorlayout_p.h index 24b25de..0f045e5 100644 --- a/src/gui/graphicsview/qgraphicsanchorlayout_p.h +++ b/src/gui/graphicsview/qgraphicsanchorlayout_p.h @@ -443,8 +443,8 @@ public: void constraintsFromPaths(Orientation orientation); QList constraintsFromSizeHints(const QList &anchors); QList > getGraphParts(Orientation orientation); - void identifyNonFloatItems(QSet visited, Orientation orientation); - void identifyNonFloatItems_helper(const AnchorData *ad, Orientation orientation); + void identifyNonFloatItems(const QSet &visited, Orientation orientation); + void identifyNonFloatItems_helper(const AnchorData *ad, QSet *nonFloatingItemsIdentifiedSoFar); inline AnchorVertex *internalVertex(const QPair &itemEdge) const { @@ -511,7 +511,7 @@ public: // ### bool graphSimplified[2]; bool graphHasConflicts[2]; - QSet m_nonFloatItems[2]; + QSet m_floatItems[2]; uint calculateGraphCacheDirty : 1; }; -- cgit v0.12 From db1162da76f1d257ba9bfcaef574275e7430385f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan-Arve=20S=C3=A6ther?= Date: Thu, 8 Oct 2009 16:17:58 +0200 Subject: Rename identifyNonFloatItems -> identifyFloatItems. We changed the behaviour of that, so the name should reflect that. --- src/gui/graphicsview/qgraphicsanchorlayout_p.cpp | 14 +++++++------- src/gui/graphicsview/qgraphicsanchorlayout_p.h | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp b/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp index 2b3e405..f9b5c8c 100644 --- a/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp +++ b/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp @@ -275,8 +275,8 @@ static qreal getFactor(qreal value, qreal min, qreal pref, qreal max) } } -static qreal getExpandingFactor(qreal expSize, qreal sizeAtPreferred, - qreal sizeAtExpanding, qreal sizeAtMaximum) +static qreal getExpandingFactor(const qreal &expSize, const qreal &sizeAtPreferred, + const qreal &sizeAtExpanding, const qreal &sizeAtMaximum) { const qreal lower = qMin(sizeAtPreferred, sizeAtMaximum); const qreal upper = qMax(sizeAtPreferred, sizeAtMaximum); @@ -1842,10 +1842,10 @@ void QGraphicsAnchorLayoutPrivate::findPaths(Orientation orientation) } } - // We will walk through every reachable items (non-float) and mark them - // by keeping their references on m_nonFloatItems. With this we can easily - // identify non-float and float items. - identifyNonFloatItems(visited, orientation); + // We will walk through every reachable items (non-float) store them in a temporary set. + // We them create a set of all items and subtract the non-floating items from the set in + // order to get the floating items. The floating items is then stored in m_floatItems + identifyFloatItems(visited, orientation); } /*! @@ -2008,7 +2008,7 @@ QGraphicsAnchorLayoutPrivate::getGraphParts(Orientation orientation) Use all visited Anchors on findPaths() so we can identify non-float Items. */ -void QGraphicsAnchorLayoutPrivate::identifyNonFloatItems(const QSet &visited, Orientation orientation) +void QGraphicsAnchorLayoutPrivate::identifyFloatItems(const QSet &visited, Orientation orientation) { QSet nonFloating; diff --git a/src/gui/graphicsview/qgraphicsanchorlayout_p.h b/src/gui/graphicsview/qgraphicsanchorlayout_p.h index 0f045e5..9ac0e19 100644 --- a/src/gui/graphicsview/qgraphicsanchorlayout_p.h +++ b/src/gui/graphicsview/qgraphicsanchorlayout_p.h @@ -443,7 +443,7 @@ public: void constraintsFromPaths(Orientation orientation); QList constraintsFromSizeHints(const QList &anchors); QList > getGraphParts(Orientation orientation); - void identifyNonFloatItems(const QSet &visited, Orientation orientation); + void identifyFloatItems(const QSet &visited, Orientation orientation); void identifyNonFloatItems_helper(const AnchorData *ad, QSet *nonFloatingItemsIdentifiedSoFar); inline AnchorVertex *internalVertex(const QPair &itemEdge) const -- cgit v0.12 From eb7daff1548510002031140ceb7fc601d064f670 Mon Sep 17 00:00:00 2001 From: Janne Anttila Date: Fri, 9 Oct 2009 10:26:28 +0300 Subject: Help Nokia X86 compiler to compiler qbuttongroup autotest. Reviewed-by: TrustMe --- tests/auto/qbuttongroup/tst_qbuttongroup.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/auto/qbuttongroup/tst_qbuttongroup.cpp b/tests/auto/qbuttongroup/tst_qbuttongroup.cpp index 11c1f47..a19f865 100644 --- a/tests/auto/qbuttongroup/tst_qbuttongroup.cpp +++ b/tests/auto/qbuttongroup/tst_qbuttongroup.cpp @@ -406,7 +406,7 @@ void tst_QButtonGroup::task106609() QTestEventLoop::instance().enterLoop(1); QApplication::setActiveWindow(&dlg); - QTRY_COMPARE(QApplication::activeWindow(), &dlg); + QTRY_COMPARE(QApplication::activeWindow(), static_cast(&dlg)); //qDebug() << "int:" << spy2.count() << "QAbstractButton*:" << spy1.count(); QCOMPARE(spy2.count(), 2); -- cgit v0.12 From 52e22e7b9313233dd248753b25f56cd912382981 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Fri, 9 Oct 2009 09:49:59 +0200 Subject: Fix QHostInfo IP resolution when there's no reverse for the IP. If you try to resolve 10.3.4.6, you're probably going to get that it doesn't exist. On some systems, getnameinfo will return the IP address in string form (Linux, without NI_NAMEREQD). On some others, it will fail (Mac, Windows). So harmonise by gracefully handling the case in which getnameinfo fails. Possible behaviour change: we don't try the forward resolution any more, after completing the reverse one. Reviewed-by: Peter Hartmann --- src/network/kernel/qhostinfo_unix.cpp | 40 +++++++++++++---------------------- src/network/kernel/qhostinfo_win.cpp | 40 +++++++++++++---------------------- 2 files changed, 30 insertions(+), 50 deletions(-) diff --git a/src/network/kernel/qhostinfo_unix.cpp b/src/network/kernel/qhostinfo_unix.cpp index b4ac3d2..7e6e522 100644 --- a/src/network/kernel/qhostinfo_unix.cpp +++ b/src/network/kernel/qhostinfo_unix.cpp @@ -173,38 +173,28 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName) #endif char hbuf[NI_MAXHOST]; - if (!sa || getnameinfo(sa, saSize, hbuf, sizeof(hbuf), 0, 0, 0) != 0) { - results.setError(QHostInfo::HostNotFound); - results.setErrorString(tr("Host not found")); - return results; - } - results.setHostName(QString::fromLatin1(hbuf)); + if (sa && getnameinfo(sa, saSize, hbuf, sizeof(hbuf), 0, 0, 0) == 0) + results.setHostName(QString::fromLatin1(hbuf)); #else in_addr_t inetaddr = qt_safe_inet_addr(hostName.toLatin1().constData()); struct hostent *ent = gethostbyaddr((const char *)&inetaddr, sizeof(inetaddr), AF_INET); - if (!ent) { - results.setError(QHostInfo::HostNotFound); - results.setErrorString(tr("Host not found")); - return results; - } - results.setHostName(QString::fromLatin1(ent->h_name)); + if (ent) + results.setHostName(QString::fromLatin1(ent->h_name)); #endif + + if (results.hostName().isEmpty()) + results.setHostName(address.toString()); + results.setAddresses(QList() << address); + return results; } // IDN support - QByteArray aceHostname; - if (results.hostName().isEmpty()) { - // it's a hostname resolution - aceHostname = QUrl::toAce(hostName); - results.setHostName(hostName); - if (aceHostname.isEmpty()) { - results.setError(QHostInfo::HostNotFound); - results.setErrorString(hostName.isEmpty() ? QObject::tr("No host name given") : QObject::tr("Invalid hostname")); - return results; - } - } else { - // it's an IP reverse resolution - aceHostname = results.hostName().toLatin1(); + QByteArray aceHostname = QUrl::toAce(hostName); + results.setHostName(hostName); + if (aceHostname.isEmpty()) { + results.setError(QHostInfo::HostNotFound); + results.setErrorString(hostName.isEmpty() ? QObject::tr("No host name given") : QObject::tr("Invalid hostname")); + return results; } #if !defined (QT_NO_GETADDRINFO) diff --git a/src/network/kernel/qhostinfo_win.cpp b/src/network/kernel/qhostinfo_win.cpp index d9d7234..720aaa5 100644 --- a/src/network/kernel/qhostinfo_win.cpp +++ b/src/network/kernel/qhostinfo_win.cpp @@ -160,38 +160,28 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName) } char hbuf[NI_MAXHOST]; - if (local_getnameinfo(sa, saSize, hbuf, sizeof(hbuf), 0, 0, 0) != 0) { - results.setError(QHostInfo::HostNotFound); - results.setErrorString(tr("Host not found")); - return results; - } - results.setHostName(QString::fromLatin1(hbuf)); + if (local_getnameinfo(sa, saSize, hbuf, sizeof(hbuf), 0, 0, 0) == 0) + results.setHostName(QString::fromLatin1(hbuf)); } else { unsigned long addr = inet_addr(hostName.toLatin1().constData()); struct hostent *ent = gethostbyaddr((const char*)&addr, sizeof(addr), AF_INET); - if (!ent) { - results.setError(QHostInfo::HostNotFound); - results.setErrorString(tr("Host not found")); - return results; - } - results.setHostName(QString::fromLatin1(ent->h_name)); + if (ent) + results.setHostName(QString::fromLatin1(ent->h_name)); } + + if (results.hostName().isEmpty()) + results.setHostName(address.toString()); + results.setAddresses(QList() << address); + return results; } // IDN support - QByteArray aceHostname; - if (results.hostName().isEmpty()) { - // it's a hostname resolution - aceHostname = QUrl::toAce(hostName); - results.setHostName(hostName); - if (aceHostname.isEmpty()) { - results.setError(QHostInfo::HostNotFound); - results.setErrorString(hostName.isEmpty() ? tr("No host name given") : tr("Invalid hostname")); - return results; - } - } else { - // it's an IP reverse resolution - aceHostname = results.hostName().toLatin1(); + QByteArray aceHostname = QUrl::toAce(hostName); + results.setHostName(hostName); + if (aceHostname.isEmpty()) { + results.setError(QHostInfo::HostNotFound); + results.setErrorString(hostName.isEmpty() ? tr("No host name given") : tr("Invalid hostname")); + return results; } if (local_getaddrinfo && local_freeaddrinfo) { -- cgit v0.12 From 433430c4081c8992bc661d5481a2288eddf2037f Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Fri, 9 Oct 2009 10:16:27 +0200 Subject: Doc: update the compiler notes about Sun CC's STL not being supported The default STL (Rogue Wave STL) is far too old for Qt. It doesn't meet the ISO C++ 98 specification. Using a more recent (and standards-compliant) STL like stlport4 enables Qt to build even QtWebKit on Solaris. Also change the note indicating we're using Sun Studio 12, not 8. --- doc/src/platforms/compiler-notes.qdoc | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/doc/src/platforms/compiler-notes.qdoc b/doc/src/platforms/compiler-notes.qdoc index 5b5240a..4577bf0 100644 --- a/doc/src/platforms/compiler-notes.qdoc +++ b/doc/src/platforms/compiler-notes.qdoc @@ -204,10 +204,22 @@ \section2 Sun Studio - Qt is tested using Sun Studio 8 (Sun CC 5.5). Go to + Qt is tested using Sun Studio 12 (Sun CC 5.9). Go to \l{Sun Studio Patches} page on Sun's Web site to download the latest patches for your Sun compiler. + Please note that Qt 4.6 is stricter in its STL requirements and + that the default STL implementation used by Sun CC does not pass + those requirements. This does not affect binary compatibility and + you can continue to use STL in your own code, but Qt's + STL-compatibility functions will be disabled. + + Sun CC ships with a secondary STL implementation (called stlport4) + which is standards-compliant and can be used by Qt. You can enable + it by passing the -library=stlport4 option to the compiler. Note + that this does not affect Qt's binary compatibility, but it may + affect that of other libraries and programs that use STL. + \section2 Sun WorkShop 5.0 Sun WorkShop 5.0 is not supported with Qt 4. -- cgit v0.12 From 95a06aa7e724309c3dcd714dbf8cf3743258592f Mon Sep 17 00:00:00 2001 From: Denis Dzyubenko Date: Wed, 7 Oct 2009 13:53:42 +0200 Subject: Fixed doc for softkeys in the qwidget doc. Reviewed-by: David Boddie --- src/gui/kernel/qwidget.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/gui/kernel/qwidget.cpp b/src/gui/kernel/qwidget.cpp index 4cbf762..56602f7 100644 --- a/src/gui/kernel/qwidget.cpp +++ b/src/gui/kernel/qwidget.cpp @@ -901,9 +901,8 @@ void QWidget::setAutoFillBackground(bool enabled) \sa QEvent, QPainter, QGridLayout, QBoxLayout \section1 Softkeys - \since 4.6 - Softkeys are usually physical keys on a device that have a corresponding label or + Since Qt 4.6, Softkeys are usually physical keys on a device that have a corresponding label or other visual representation on the screen that is generally located next to its physical counterpart. They are most often found on mobile phone platforms. In modern touch based user interfaces it is also possible to have softkeys that do -- cgit v0.12 From afc718f1f21fd34a23e34af9b8a83eb55ae26f34 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Fri, 9 Oct 2009 11:06:21 +0200 Subject: Autotest: fix forward-declaration test. The problem was that we forward-declared as struct, but the function was implemented as class. It's different on MSVC. Reviewed-by: Trust Me --- tests/auto/qsharedpointer/tst_qsharedpointer.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/auto/qsharedpointer/tst_qsharedpointer.cpp b/tests/auto/qsharedpointer/tst_qsharedpointer.cpp index 58eaacb..46ec035 100644 --- a/tests/auto/qsharedpointer/tst_qsharedpointer.cpp +++ b/tests/auto/qsharedpointer/tst_qsharedpointer.cpp @@ -1701,7 +1701,7 @@ void tst_QSharedPointer::invalidConstructs() "struct DerivedData: public Data { int j; };\n" "\n" "extern int forwardDeclaredDestructorRunCount;\n" - "struct ForwardDeclared;\n" + "class ForwardDeclared;\n" "ForwardDeclared *forwardPointer();\n" ); @@ -1730,6 +1730,10 @@ void tst_QSharedPointer::invalidConstructs() bool result = (test.*testFunction)(body); if (qgetenv("QTEST_EXTERNAL_DEBUG").toInt() > 0) { qDebug("External test output:"); +#ifdef Q_CC_MSVC + // MSVC prints errors to stdout + printf("%s\n", test.standardOutput().constData()); +#endif printf("%s\n", test.standardError().constData()); } if (!result) { -- cgit v0.12 From 62e7e63779a8dbd5dec16e5eb938bf597bc22548 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Fri, 9 Oct 2009 11:18:22 +0200 Subject: Autotest: fix false positives with MSVC.NET 2003 This is definitely a compiler bug. The compiler forgets to adjust the value of the pointers inside the template operator== function. If you make the call outside the template function, it works as expected. Reviewed-by: Trust Me --- tests/auto/qsharedpointer/tst_qsharedpointer.cpp | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/tests/auto/qsharedpointer/tst_qsharedpointer.cpp b/tests/auto/qsharedpointer/tst_qsharedpointer.cpp index 46ec035..ed9206c 100644 --- a/tests/auto/qsharedpointer/tst_qsharedpointer.cpp +++ b/tests/auto/qsharedpointer/tst_qsharedpointer.cpp @@ -812,8 +812,14 @@ void tst_QSharedPointer::differentPointers() QVERIFY(baseptr.data() == aData); QVERIFY(aData == baseptr.data()); - QVERIFY(bool(operator==(baseptr, aData))); + +#if defined(Q_CC_MSVC) && _MSC_VER < 1400 + QEXPECT_FAIL("", "Compiler bug", Continue); +#endif QVERIFY(baseptr == aData); +#if defined(Q_CC_MSVC) && _MSC_VER < 1400 + QEXPECT_FAIL("", "Compiler bug", Continue); +#endif QVERIFY(aData == baseptr); } check(); @@ -829,6 +835,9 @@ void tst_QSharedPointer::differentPointers() QVERIFY(ptr == baseptr); QVERIFY(ptr.data() == baseptr.data()); QVERIFY(ptr == aBase); +#if defined(Q_CC_MSVC) && _MSC_VER < 1400 + QEXPECT_FAIL("", "Compiler bug", Continue); +#endif QVERIFY(baseptr == aData); } check(); @@ -845,6 +854,9 @@ void tst_QSharedPointer::differentPointers() QVERIFY(ptr.data() == baseptr.data()); QVERIFY(ptr == aBase); QVERIFY(ptr == aData); +#if defined(Q_CC_MSVC) && _MSC_VER < 1400 + QEXPECT_FAIL("", "Compiler bug", Continue); +#endif QVERIFY(baseptr == aData); QVERIFY(baseptr == aBase); } @@ -865,6 +877,9 @@ void tst_QSharedPointer::virtualBaseDifferentPointers() QVERIFY(ptr.data() == baseptr.data()); QVERIFY(ptr == aBase); QVERIFY(ptr == aData); +#if defined(Q_CC_MSVC) && _MSC_VER < 1400 + QEXPECT_FAIL("", "Compiler bug", Continue); +#endif QVERIFY(baseptr == aData); QVERIFY(baseptr == aBase); } @@ -882,6 +897,9 @@ void tst_QSharedPointer::virtualBaseDifferentPointers() QVERIFY(ptr.data() == baseptr.data()); QVERIFY(ptr == aBase); QVERIFY(ptr == aData); +#if defined(Q_CC_MSVC) && _MSC_VER < 1400 + QEXPECT_FAIL("", "Compiler bug", Continue); +#endif QVERIFY(baseptr == aData); QVERIFY(baseptr == aBase); } -- cgit v0.12 From 606e1150e381e0d824e6850befb101a2ed8e0542 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Fri, 9 Oct 2009 12:03:42 +0200 Subject: Add a way to allow tracking the originating object with QNetworkRequest. Added setOriginatingObject() and originatingObject() to QNetworkRequest that internally tracks the QObject using a QWeakPointer. Reviewed-by: Lars Knoll Rubberstamped-by: Thiago --- src/network/access/qnetworkrequest.cpp | 30 ++++++++++++++++++++++ src/network/access/qnetworkrequest.h | 3 +++ src/network/access/qnetworkrequest_p.h | 2 ++ tests/auto/qnetworkrequest/tst_qnetworkrequest.cpp | 16 ++++++++++++ 4 files changed, 51 insertions(+) diff --git a/src/network/access/qnetworkrequest.cpp b/src/network/access/qnetworkrequest.cpp index cde9858..ca9e606 100644 --- a/src/network/access/qnetworkrequest.cpp +++ b/src/network/access/qnetworkrequest.cpp @@ -481,6 +481,36 @@ void QNetworkRequest::setSslConfiguration(const QSslConfiguration &config) } #endif +/*! + \since 4.6 + + Allows setting a reference to the object initiating + the request. + + For example QtWebKit sets the originating object to the + QWebFrame that initiated the request. + + \sa originatingObject() +*/ +void QNetworkRequest::setOriginatingObject(QObject *object) +{ + d->originatingObject = object; +} + +/*! + \since 4.6 + + Returns a reference to the object that initiated this + network request; returns 0 if not set or the object has + been destroyed. + + \sa setOriginatingObject() +*/ +QObject *QNetworkRequest::originatingObject() const +{ + return d->originatingObject.data(); +} + static QByteArray headerName(QNetworkRequest::KnownHeaders header) { switch (header) { diff --git a/src/network/access/qnetworkrequest.h b/src/network/access/qnetworkrequest.h index 7b15237..62c6dda 100644 --- a/src/network/access/qnetworkrequest.h +++ b/src/network/access/qnetworkrequest.h @@ -120,6 +120,9 @@ public: void setSslConfiguration(const QSslConfiguration &configuration); #endif + void setOriginatingObject(QObject *object); + QObject *originatingObject() const; + private: QSharedDataPointer d; friend class QNetworkRequestPrivate; diff --git a/src/network/access/qnetworkrequest_p.h b/src/network/access/qnetworkrequest_p.h index 22b239f..9b3632f 100644 --- a/src/network/access/qnetworkrequest_p.h +++ b/src/network/access/qnetworkrequest_p.h @@ -58,6 +58,7 @@ #include "QtCore/qlist.h" #include "QtCore/qhash.h" #include "QtCore/qshareddata.h" +#include "QtCore/qsharedpointer.h" QT_BEGIN_NAMESPACE @@ -73,6 +74,7 @@ public: RawHeadersList rawHeaders; CookedHeadersMap cookedHeaders; AttributesMap attributes; + QWeakPointer originatingObject; RawHeadersList::ConstIterator findRawHeader(const QByteArray &key) const; QList rawHeadersKeys() const; diff --git a/tests/auto/qnetworkrequest/tst_qnetworkrequest.cpp b/tests/auto/qnetworkrequest/tst_qnetworkrequest.cpp index 3f9632c..2e21087 100644 --- a/tests/auto/qnetworkrequest/tst_qnetworkrequest.cpp +++ b/tests/auto/qnetworkrequest/tst_qnetworkrequest.cpp @@ -66,6 +66,7 @@ private slots: void setHeader(); void rawHeaderParsing_data(); void rawHeaderParsing(); + void originatingObject(); void removeHeader(); }; @@ -476,5 +477,20 @@ void tst_QNetworkRequest::removeHeader() QVERIFY(request.hasRawHeader("bar")); } +void tst_QNetworkRequest::originatingObject() +{ + QNetworkRequest request; + + QVERIFY(!request.originatingObject()); + + { + QObject dummy; + request.setOriginatingObject(&dummy); + QCOMPARE(request.originatingObject(), &dummy); + } + + QVERIFY(!request.originatingObject()); +} + QTEST_MAIN(tst_QNetworkRequest) #include "tst_qnetworkrequest.moc" -- cgit v0.12 From 803bebe62face37310fd8d8b97ca7faa1d4284a8 Mon Sep 17 00:00:00 2001 From: Kim Motoyoshi Kalland Date: Fri, 9 Oct 2009 12:10:42 +0200 Subject: Made QPen::setDashOffset() work with non-custom dashed lines. Task-number: QTBUG-2738 Reviewed-by: Trond --- src/gui/painting/qpen.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/gui/painting/qpen.cpp b/src/gui/painting/qpen.cpp index a050cb2..41efc80 100644 --- a/src/gui/painting/qpen.cpp +++ b/src/gui/painting/qpen.cpp @@ -411,6 +411,8 @@ Qt::PenStyle QPen::style() const pattern using the setDashPattern() function which implicitly converts the style of the pen to Qt::CustomDashLine. + \note This function resets the dash offset to zero. + \sa style(), {QPen#Pen Style}{Pen Style} */ @@ -420,7 +422,9 @@ void QPen::setStyle(Qt::PenStyle s) return; detach(); d->style = s; - static_cast(d)->dashPattern.clear(); + QPenData *dd = static_cast(d); + dd->dashPattern.clear(); + dd->dashOffset = 0; } /*! @@ -538,8 +542,12 @@ void QPen::setDashOffset(qreal offset) if (qFuzzyCompare(offset, static_cast(d)->dashOffset)) return; detach(); - static_cast(d)->dashOffset = offset; - d->style = Qt::CustomDashLine; + QPenData *dd = static_cast(d); + dd->dashOffset = offset; + if (d->style != Qt::CustomDashLine) { + dd->dashPattern = dashPattern(); + d->style = Qt::CustomDashLine; + } } /*! -- cgit v0.12 From f74570b72bd71f3747521a5f561971165f3297e5 Mon Sep 17 00:00:00 2001 From: Janne Anttila Date: Fri, 9 Oct 2009 13:58:08 +0300 Subject: Fix for tst_qfile::map auto test in Symbian OS 3.1. The map test case panic with E32User-Cbase 66 in N95 without this fix. This happens sisnce Open C bug where mmap may leave and trap handler is not inside OpenC. The workaround is to install the necessary TRAP handler in Qt, before calling mmap. AutoTests: tst_qfile::map passes Reviewed-by: Janne Koskinen --- src/corelib/io/qfsfileengine_unix.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/corelib/io/qfsfileengine_unix.cpp b/src/corelib/io/qfsfileengine_unix.cpp index 114da3b..b0cddaa 100644 --- a/src/corelib/io/qfsfileengine_unix.cpp +++ b/src/corelib/io/qfsfileengine_unix.cpp @@ -1255,8 +1255,19 @@ uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size, QFile::MemoryMapFla int realOffset = offset / pagesSize; int extra = offset % pagesSize; - void *mapAddress = mmap((void*)0, (size_t)size + extra, - access, MAP_SHARED, nativeHandle(), realOffset * pagesSize); +#ifdef Q_OS_SYMBIAN + void *mapAddress; + TRAPD(err, mapAddress = mmap((void*)0, (size_t)size + extra, + access, MAP_SHARED, nativeHandle(), realOffset * pagesSize)); + if (err != KErrNone) { + qWarning("OpenC bug: leave from mmap %d", err); + mapAddress = MAP_FAILED; + errno = EINVAL; + } +#else + void *mapAddress = mmap((void*)0, (size_t)size + extra, + access, MAP_SHARED, nativeHandle(), realOffset * pagesSize); +#endif if (MAP_FAILED != mapAddress) { uchar *address = extra + static_cast(mapAddress); maps[address] = QPair(extra, size); -- cgit v0.12 From 05727386bec0142174c9cbaea6f2b3ca72a42b63 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Fri, 9 Oct 2009 13:18:40 +0200 Subject: Fix qdoc warning about undocumented parameter Reviewed-by: Trust me --- src/network/access/qnetworkrequest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/access/qnetworkrequest.cpp b/src/network/access/qnetworkrequest.cpp index ca9e606..33bc57b 100644 --- a/src/network/access/qnetworkrequest.cpp +++ b/src/network/access/qnetworkrequest.cpp @@ -484,7 +484,7 @@ void QNetworkRequest::setSslConfiguration(const QSslConfiguration &config) /*! \since 4.6 - Allows setting a reference to the object initiating + Allows setting a reference to the \a object initiating the request. For example QtWebKit sets the originating object to the -- cgit v0.12 From f98f5c5432f13238fc640820cc222b671c1ee8df Mon Sep 17 00:00:00 2001 From: Gunnar Sletta Date: Fri, 9 Oct 2009 09:50:19 +0200 Subject: Fixed text positioning when printing in HighResolution on Mac OS X Reviewed-by: Richard --- src/gui/text/qfontengine_mac.mm | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/gui/text/qfontengine_mac.mm b/src/gui/text/qfontengine_mac.mm index 40db7b4..758d8af 100644 --- a/src/gui/text/qfontengine_mac.mm +++ b/src/gui/text/qfontengine_mac.mm @@ -138,9 +138,10 @@ QCoreTextFontEngineMulti::QCoreTextFontEngineMulti(const ATSFontFamilyRef &, con QCFString name; ATSFontGetName(atsFontRef, kATSOptionFlagsDefault, &name); - QCFType descriptor = CTFontDescriptorCreateWithNameAndSize(name, fontDef.pointSize); - QCFType baseFont = CTFontCreateWithFontDescriptor(descriptor, fontDef.pointSize, 0); - ctfont = CTFontCreateCopyWithSymbolicTraits(baseFont, fontDef.pointSize, 0, symbolicTraits, symbolicTraits); + + QCFType descriptor = CTFontDescriptorCreateWithNameAndSize(name, fontDef.pixelSize); + QCFType baseFont = CTFontCreateWithFontDescriptor(descriptor, fontDef.pixelSize, 0); + ctfont = CTFontCreateCopyWithSymbolicTraits(baseFont, fontDef.pixelSize, 0, symbolicTraits, symbolicTraits); // CTFontCreateCopyWithSymbolicTraits returns NULL if we ask for a trait that does // not exist for the given font. (for example italic) -- cgit v0.12 From 2caa16ff98348b043ecc3598e5b9af4a2e2ae3bc Mon Sep 17 00:00:00 2001 From: Gunnar Sletta Date: Thu, 8 Oct 2009 17:25:05 +0200 Subject: Fixed crash when printing to files under Cocoa When we select save as PDF in the print dialog, we get a new PMPrintSession in the printInfo object, while our stored one is deleted, so we update the pointer to be on the safe side Reviewed-by: msorvig --- src/gui/dialogs/qprintdialog_mac.mm | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/gui/dialogs/qprintdialog_mac.mm b/src/gui/dialogs/qprintdialog_mac.mm index a7587b1..667fc40 100644 --- a/src/gui/dialogs/qprintdialog_mac.mm +++ b/src/gui/dialogs/qprintdialog_mac.mm @@ -166,6 +166,12 @@ QT_USE_NAMESPACE } // Keep us in sync with file output PMDestinationType dest; + + // If the user selected print to file, the session has been + // changed behind our back and our d->ep->session object is a + // dangling pointer. Update it based on the "current" session + d->ep->session = static_cast([d->ep->printInfo PMPrintSession]); + PMSessionGetDestinationType(d->ep->session, d->ep->settings, &dest); if (dest == kPMDestinationFile) { QCFType file; -- cgit v0.12 From 4f2d382059b06f89d58816c03137d75931654b94 Mon Sep 17 00:00:00 2001 From: Aleksandar Sasha Babic Date: Fri, 9 Oct 2009 13:47:51 +0200 Subject: Revert "Workaround for OpenC daylight saving cache issue when using localtime_r." This reverts commit 2f7d1318d2dc63322a468d8c301ae718eaba0d03. --- src/corelib/tools/qdatetime.cpp | 32 ++------------------------------ 1 file changed, 2 insertions(+), 30 deletions(-) diff --git a/src/corelib/tools/qdatetime.cpp b/src/corelib/tools/qdatetime.cpp index 1277623..1b559cf 100644 --- a/src/corelib/tools/qdatetime.cpp +++ b/src/corelib/tools/qdatetime.cpp @@ -54,6 +54,7 @@ #ifndef Q_WS_WIN #include #endif + #include #if defined(Q_OS_WINCE) #include "qfunctions_wince.h" @@ -68,31 +69,6 @@ # define QDTPDEBUGN if (false) qDebug #endif -#if defined(Q_OS_SYMBIAN) - // Workaround for OpenC bug. - - // OpenC incorrectly caches DST information between localtime_r - // calls, i.e. if previous call to localtime_r has been called for DST - // affected date, also the second call will be affected by DST even - // the date is such that DST should not be applied. - - // The workaround is to call mktime with non-DST affected date before - // calling localtime_r. mktime call resets the OpenC internal DST cache - // to right value and localtime_r will return correct values. -#define FIX_OPENC_DSTCACHE \ - tm localTM; \ - localTM.tm_sec = 0; \ - localTM.tm_min = 0; \ - localTM.tm_hour = 12; \ - localTM.tm_mday = 1; \ - localTM.tm_mon = 1; \ - localTM.tm_year = 2002 - 1900; \ - localTM.tm_isdst = -1; \ - time_t temp = mktime(&localTM); -#else -#define FIX_OPENC_DSTCACHE -#endif - #if defined(Q_WS_MAC) #include #endif @@ -1162,7 +1138,6 @@ QDate QDate::currentDate() // use the reentrant version of localtime() where available tzset(); tm res; - FIX_OPENC_DSTCACHE t = localtime_r(<ime, &res); #else t = localtime(<ime); @@ -1859,13 +1834,12 @@ QTime QTime::currentTime() // use the reentrant version of localtime() where available tzset(); tm res; - FIX_OPENC_DSTCACHE t = localtime_r(<ime, &res); #else t = localtime(<ime); #endif Q_CHECK_PTR(t); - + ct.mds = MSECS_PER_HOUR * t->tm_hour + MSECS_PER_MIN * t->tm_min + 1000 * t->tm_sec + tv.tv_usec / 1000; #else @@ -2913,7 +2887,6 @@ QDateTime QDateTime::currentDateTime() // use the reentrant version of localtime() where available tzset(); tm res; - FIX_OPENC_DSTCACHE t = localtime_r(<ime, &res); #else t = localtime(<ime); @@ -3731,7 +3704,6 @@ static QDateTimePrivate::Spec utcToLocal(QDate &date, QTime &time) // use the reentrant version of localtime() where available tzset(); tm res; - FIX_OPENC_DSTCACHE brokenDown = localtime_r(&secsSince1Jan1970UTC, &res); #elif defined(_MSC_VER) && _MSC_VER >= 1400 tm res; -- cgit v0.12 From faef2f5101287ad8ce94cf8e7a4d574a7d6267fd Mon Sep 17 00:00:00 2001 From: Frans Englich Date: Fri, 9 Oct 2009 11:29:51 +0200 Subject: Symbian fix: rename examples ftp and musicplayer to start with q. Symbian already has the executables musicplayer.exe, mediaplayer.exe and ftp.exe, with the result that we overwrite them with Qt. We solve this by renaming the examples, and do it not only on Symbian, such that Qt remains consistent across platforms. This was previously partly done for mediaplayer. The folder name needs to be consistent with the executable, for qtdemo to work. Done jointly with Alessandro. Task-number: QTBUG-4743 Reviewed-by: Alessandro Portale Reviewed-by: Frans Englich --- demos/demos.pro | 2 +- demos/embedded/fluidlauncher/config_s60/config.xml | 2 +- demos/embedded/fluidlauncher/fluidlauncher.pro | 6 +- demos/mediaplayer/images/screen.png | Bin 4358 -> 0 bytes demos/mediaplayer/main.cpp | 89 --- demos/mediaplayer/mediaplayer.cpp | 845 --------------------- demos/mediaplayer/mediaplayer.h | 139 ---- demos/mediaplayer/mediaplayer.pro | 36 - demos/mediaplayer/mediaplayer.qrc | 5 - demos/mediaplayer/settings.ui | 464 ----------- demos/qmediaplayer/images/screen.png | Bin 0 -> 4358 bytes demos/qmediaplayer/main.cpp | 89 +++ demos/qmediaplayer/mediaplayer.cpp | 845 +++++++++++++++++++++ demos/qmediaplayer/mediaplayer.h | 139 ++++ demos/qmediaplayer/mediaplayer.qrc | 5 + demos/qmediaplayer/qmediaplayer.pro | 35 + demos/qmediaplayer/settings.ui | 464 +++++++++++ demos/qtdemo/xml/examples.xml | 4 +- doc/src/demos/mediaplayer.qdoc | 2 +- doc/src/examples/ftp.qdoc | 34 +- doc/src/examples/musicplayerexample.qdoc | 38 +- doc/src/getting-started/demos.qdoc | 2 +- doc/src/getting-started/examples.qdoc | 2 +- examples/network/ftp/ftp.pro | 20 - examples/network/ftp/ftp.qrc | 7 - examples/network/ftp/ftpwindow.cpp | 379 --------- examples/network/ftp/ftpwindow.h | 108 --- examples/network/ftp/images/cdtoparent.png | Bin 139 -> 0 bytes examples/network/ftp/images/dir.png | Bin 154 -> 0 bytes examples/network/ftp/images/file.png | Bin 129 -> 0 bytes examples/network/ftp/main.cpp | 67 -- examples/network/ftp/sym_iap_util.h | 510 ------------- examples/network/network.pro | 4 +- examples/network/qftp/ftp.qrc | 7 + examples/network/qftp/ftpwindow.cpp | 379 +++++++++ examples/network/qftp/ftpwindow.h | 108 +++ examples/network/qftp/images/cdtoparent.png | Bin 0 -> 139 bytes examples/network/qftp/images/dir.png | Bin 0 -> 154 bytes examples/network/qftp/images/file.png | Bin 0 -> 129 bytes examples/network/qftp/main.cpp | 67 ++ examples/network/qftp/qftp.pro | 20 + examples/network/qftp/sym_iap_util.h | 510 +++++++++++++ examples/phonon/musicplayer/main.cpp | 57 -- examples/phonon/musicplayer/mainwindow.cpp | 355 --------- examples/phonon/musicplayer/mainwindow.h | 112 --- examples/phonon/musicplayer/musicplayer.pro | 17 - examples/phonon/phonon.pro | 2 +- examples/phonon/qmusicplayer/main.cpp | 57 ++ examples/phonon/qmusicplayer/mainwindow.cpp | 355 +++++++++ examples/phonon/qmusicplayer/mainwindow.h | 112 +++ examples/phonon/qmusicplayer/qmusicplayer.pro | 17 + 51 files changed, 3258 insertions(+), 3259 deletions(-) delete mode 100644 demos/mediaplayer/images/screen.png delete mode 100644 demos/mediaplayer/main.cpp delete mode 100644 demos/mediaplayer/mediaplayer.cpp delete mode 100644 demos/mediaplayer/mediaplayer.h delete mode 100644 demos/mediaplayer/mediaplayer.pro delete mode 100644 demos/mediaplayer/mediaplayer.qrc delete mode 100644 demos/mediaplayer/settings.ui create mode 100644 demos/qmediaplayer/images/screen.png create mode 100644 demos/qmediaplayer/main.cpp create mode 100644 demos/qmediaplayer/mediaplayer.cpp create mode 100644 demos/qmediaplayer/mediaplayer.h create mode 100644 demos/qmediaplayer/mediaplayer.qrc create mode 100644 demos/qmediaplayer/qmediaplayer.pro create mode 100644 demos/qmediaplayer/settings.ui delete mode 100644 examples/network/ftp/ftp.pro delete mode 100644 examples/network/ftp/ftp.qrc delete mode 100644 examples/network/ftp/ftpwindow.cpp delete mode 100644 examples/network/ftp/ftpwindow.h delete mode 100644 examples/network/ftp/images/cdtoparent.png delete mode 100644 examples/network/ftp/images/dir.png delete mode 100644 examples/network/ftp/images/file.png delete mode 100644 examples/network/ftp/main.cpp delete mode 100644 examples/network/ftp/sym_iap_util.h create mode 100644 examples/network/qftp/ftp.qrc create mode 100644 examples/network/qftp/ftpwindow.cpp create mode 100644 examples/network/qftp/ftpwindow.h create mode 100644 examples/network/qftp/images/cdtoparent.png create mode 100644 examples/network/qftp/images/dir.png create mode 100644 examples/network/qftp/images/file.png create mode 100644 examples/network/qftp/main.cpp create mode 100644 examples/network/qftp/qftp.pro create mode 100644 examples/network/qftp/sym_iap_util.h delete mode 100644 examples/phonon/musicplayer/main.cpp delete mode 100644 examples/phonon/musicplayer/mainwindow.cpp delete mode 100644 examples/phonon/musicplayer/mainwindow.h delete mode 100644 examples/phonon/musicplayer/musicplayer.pro create mode 100644 examples/phonon/qmusicplayer/main.cpp create mode 100644 examples/phonon/qmusicplayer/mainwindow.cpp create mode 100644 examples/phonon/qmusicplayer/mainwindow.h create mode 100644 examples/phonon/qmusicplayer/qmusicplayer.pro diff --git a/demos/demos.pro b/demos/demos.pro index c4b8872..4a9d451 100644 --- a/demos/demos.pro +++ b/demos/demos.pro @@ -64,7 +64,7 @@ demos_arthurplugin.subdir = arthurplugin demos_sqlbrowser.subdir = sqlbrowser demos_undo.subdir = undo demos_qtdemo.subdir = qtdemo -demos_mediaplayer.subdir = mediaplayer +demos_mediaplayer.subdir = qmediaplayer demos_browser.subdir = browser diff --git a/demos/embedded/fluidlauncher/config_s60/config.xml b/demos/embedded/fluidlauncher/config_s60/config.xml index fefa3dd..2c61baf 100644 --- a/demos/embedded/fluidlauncher/config_s60/config.xml +++ b/demos/embedded/fluidlauncher/config_s60/config.xml @@ -6,7 +6,7 @@ - + diff --git a/demos/embedded/fluidlauncher/fluidlauncher.pro b/demos/embedded/fluidlauncher/fluidlauncher.pro index f2abde6..dd931e6 100644 --- a/demos/embedded/fluidlauncher/fluidlauncher.pro +++ b/demos/embedded/fluidlauncher/fluidlauncher.pro @@ -66,7 +66,7 @@ symbian { deform.exe \ pathstroke.exe \ wiggly.exe \ - ftp.exe \ + qftp.exe \ saxbookmarks.exe \ desktopservices.exe \ fridgemagnets.exe \ @@ -85,7 +85,7 @@ symbian { $${EPOCROOT}$$HW_ZDIR$$REG_RESOURCE_IMPORT_DIR/deform_reg.rsc \ $${EPOCROOT}$$HW_ZDIR$$REG_RESOURCE_IMPORT_DIR/pathstroke_reg.rsc \ $${EPOCROOT}$$HW_ZDIR$$REG_RESOURCE_IMPORT_DIR/wiggly_reg.rsc \ - $${EPOCROOT}$$HW_ZDIR$$REG_RESOURCE_IMPORT_DIR/ftp_reg.rsc\ + $${EPOCROOT}$$HW_ZDIR$$REG_RESOURCE_IMPORT_DIR/qftp_reg.rsc\ $${EPOCROOT}$$HW_ZDIR$$REG_RESOURCE_IMPORT_DIR/saxbookmarks_reg.rsc \ $${EPOCROOT}$$HW_ZDIR$$REG_RESOURCE_IMPORT_DIR/desktopservices_reg.rsc \ $${EPOCROOT}$$HW_ZDIR$$REG_RESOURCE_IMPORT_DIR/fridgemagnets_reg.rsc \ @@ -109,7 +109,7 @@ symbian { $${EPOCROOT}$$HW_ZDIR$$APP_RESOURCE_DIR/deform.rsc \ $${EPOCROOT}$$HW_ZDIR$$APP_RESOURCE_DIR/pathstroke.rsc \ $${EPOCROOT}$$HW_ZDIR$$APP_RESOURCE_DIR/wiggly.rsc \ - $${EPOCROOT}$$HW_ZDIR$$APP_RESOURCE_DIR/ftp.rsc\ + $${EPOCROOT}$$HW_ZDIR$$APP_RESOURCE_DIR/qftp.rsc\ $${EPOCROOT}$$HW_ZDIR$$APP_RESOURCE_DIR/saxbookmarks.rsc \ $${EPOCROOT}$$HW_ZDIR$$APP_RESOURCE_DIR/desktopservices.rsc \ $${EPOCROOT}$$HW_ZDIR$$APP_RESOURCE_DIR/fridgemagnets.rsc \ diff --git a/demos/mediaplayer/images/screen.png b/demos/mediaplayer/images/screen.png deleted file mode 100644 index a15df92..0000000 Binary files a/demos/mediaplayer/images/screen.png and /dev/null differ diff --git a/demos/mediaplayer/main.cpp b/demos/mediaplayer/main.cpp deleted file mode 100644 index 66aa445..0000000 --- a/demos/mediaplayer/main.cpp +++ /dev/null @@ -1,89 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the demonstration 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 Technology Preview License Agreement accompanying -** this package. -** -** 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.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -***************************************************************************/ - -#include -#include "mediaplayer.h" - -int main (int argc, char *argv[]) -{ - Q_INIT_RESOURCE(mediaplayer); - QApplication app(argc, argv); - app.setApplicationName("Media Player"); - app.setOrganizationName("Qt"); - app.setQuitOnLastWindowClosed(true); - - bool hasSmallScreen = -#ifdef Q_OS_SYMBIAN - /* On Symbian, we always want fullscreen. One reason is that it's not - * possible to launch any demos from the fluidlauncher due to a - * limitation in the emulator. */ - true -#else - false -#endif - ; - - QString fileString; - const QStringList args(app.arguments()); - /* We have a minor problem here, we accept two arguments, both are - * optional: - * - A file name - * - the option "-small-screen", so let's try to cope with that. - */ - for (int i = 0; i < args.count(); ++i) { - const QString &at = args.at(i); - - if (at == QLatin1String("-small-screen")) - hasSmallScreen = true; - else if (i > 0) // We don't want the app name. - fileString = at; - } - - MediaPlayer player(fileString, hasSmallScreen); - - if (hasSmallScreen) - player.showMaximized(); - else - player.show(); - - return app.exec(); -} - diff --git a/demos/mediaplayer/mediaplayer.cpp b/demos/mediaplayer/mediaplayer.cpp deleted file mode 100644 index baac236..0000000 --- a/demos/mediaplayer/mediaplayer.cpp +++ /dev/null @@ -1,845 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the demonstration 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 Technology Preview License Agreement accompanying -** this package. -** -** 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.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -***************************************************************************/ - -#include - -#define SLIDER_RANGE 8 - -#include "mediaplayer.h" -#include "ui_settings.h" - - -class MediaVideoWidget : public Phonon::VideoWidget -{ -public: - MediaVideoWidget(MediaPlayer *player, QWidget *parent = 0) : - Phonon::VideoWidget(parent), m_player(player), m_action(this) - { - m_action.setCheckable(true); - m_action.setChecked(false); - m_action.setShortcut(QKeySequence( Qt::AltModifier + Qt::Key_Return)); - m_action.setShortcutContext(Qt::WindowShortcut); - connect(&m_action, SIGNAL(toggled(bool)), SLOT(setFullScreen(bool))); - addAction(&m_action); - setAcceptDrops(true); - } - -protected: - void mouseDoubleClickEvent(QMouseEvent *e) - { - Phonon::VideoWidget::mouseDoubleClickEvent(e); - setFullScreen(!isFullScreen()); - } - - void keyPressEvent(QKeyEvent *e) - { - if (e->key() == Qt::Key_Space && !e->modifiers()) { - m_player->playPause(); - e->accept(); - return; - } else if (e->key() == Qt::Key_Escape && !e->modifiers()) { - setFullScreen(false); - e->accept(); - return; - } - Phonon::VideoWidget::keyPressEvent(e); - } - - bool event(QEvent *e) - { - switch(e->type()) - { - case QEvent::Close: - //we just ignore the cose events on the video widget - //this prevents ALT+F4 from having an effect in fullscreen mode - e->ignore(); - return true; - case QEvent::MouseMove: -#ifndef QT_NO_CURSOR - unsetCursor(); -#endif - //fall through - case QEvent::WindowStateChange: - { - //we just update the state of the checkbox, in case it wasn't already - m_action.setChecked(windowState() & Qt::WindowFullScreen); - const Qt::WindowFlags flags = m_player->windowFlags(); - if (windowState() & Qt::WindowFullScreen) { - m_timer.start(1000, this); - } else { - m_timer.stop(); -#ifndef QT_NO_CURSOR - unsetCursor(); -#endif - } - } - break; - default: - break; - } - - return Phonon::VideoWidget::event(e); - } - - void timerEvent(QTimerEvent *e) - { - if (e->timerId() == m_timer.timerId()) { - //let's store the cursor shape -#ifndef QT_NO_CURSOR - setCursor(Qt::BlankCursor); -#endif - } - Phonon::VideoWidget::timerEvent(e); - } - - void dropEvent(QDropEvent *e) - { - m_player->handleDrop(e); - } - - void dragEnterEvent(QDragEnterEvent *e) { - if (e->mimeData()->hasUrls()) - e->acceptProposedAction(); - } - -private: - MediaPlayer *m_player; - QBasicTimer m_timer; - QAction m_action; -}; - - -MediaPlayer::MediaPlayer(const QString &filePath, - const bool hasSmallScreen) : - playButton(0), nextEffect(0), settingsDialog(0), ui(0), - m_AudioOutput(Phonon::VideoCategory), - m_videoWidget(new MediaVideoWidget(this)), - m_hasSmallScreen(hasSmallScreen) -{ - setWindowTitle(tr("Media Player")); - setContextMenuPolicy(Qt::CustomContextMenu); - m_videoWidget->setContextMenuPolicy(Qt::CustomContextMenu); - - QSize buttonSize(34, 28); - - QPushButton *openButton = new QPushButton(this); - - openButton->setIcon(style()->standardIcon(QStyle::SP_DialogOpenButton)); - QPalette bpal; - QColor arrowcolor = bpal.buttonText().color(); - if (arrowcolor == Qt::black) - arrowcolor = QColor(80, 80, 80); - bpal.setBrush(QPalette::ButtonText, arrowcolor); - openButton->setPalette(bpal); - - rewindButton = new QPushButton(this); - rewindButton->setIcon(style()->standardIcon(QStyle::SP_MediaSkipBackward)); - - forwardButton = new QPushButton(this); - forwardButton->setIcon(style()->standardIcon(QStyle::SP_MediaSkipForward)); - forwardButton->setEnabled(false); - - playButton = new QPushButton(this); - playIcon = style()->standardIcon(QStyle::SP_MediaPlay); - pauseIcon = style()->standardIcon(QStyle::SP_MediaPause); - playButton->setIcon(playIcon); - - slider = new Phonon::SeekSlider(this); - slider->setMediaObject(&m_MediaObject); - volume = new Phonon::VolumeSlider(&m_AudioOutput); - - QVBoxLayout *vLayout = new QVBoxLayout(this); - vLayout->setContentsMargins(8, 8, 8, 8); - - QHBoxLayout *layout = new QHBoxLayout(); - - info = new QLabel(this); - info->setMinimumHeight(70); - info->setAcceptDrops(false); - info->setMargin(2); - info->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken); - info->setLineWidth(2); - info->setAutoFillBackground(true); - - QPalette palette; - palette.setBrush(QPalette::WindowText, Qt::white); -#ifndef Q_WS_MAC - openButton->setMinimumSize(54, buttonSize.height()); - rewindButton->setMinimumSize(buttonSize); - forwardButton->setMinimumSize(buttonSize); - playButton->setMinimumSize(buttonSize); -#endif - info->setStyleSheet("border-image:url(:/images/screen.png) ; border-width:3px"); - info->setPalette(palette); - info->setText(tr("
No media
")); - - volume->setFixedWidth(120); - - layout->addWidget(openButton); - layout->addWidget(rewindButton); - layout->addWidget(playButton); - layout->addWidget(forwardButton); - - layout->addStretch(); - layout->addWidget(volume); - - vLayout->addWidget(info); - initVideoWindow(); - vLayout->addWidget(&m_videoWindow); - QVBoxLayout *buttonPanelLayout = new QVBoxLayout(); - m_videoWindow.hide(); - buttonPanelLayout->addLayout(layout); - - timeLabel = new QLabel(this); - progressLabel = new QLabel(this); - QWidget *sliderPanel = new QWidget(this); - QHBoxLayout *sliderLayout = new QHBoxLayout(); - sliderLayout->addWidget(slider); - sliderLayout->addWidget(timeLabel); - sliderLayout->addWidget(progressLabel); - sliderLayout->setContentsMargins(0, 0, 0, 0); - sliderPanel->setLayout(sliderLayout); - - buttonPanelLayout->addWidget(sliderPanel); - buttonPanelLayout->setContentsMargins(0, 0, 0, 0); -#ifdef Q_OS_MAC - layout->setSpacing(4); - buttonPanelLayout->setSpacing(0); - info->setMinimumHeight(100); - info->setFont(QFont("verdana", 15)); - // QStyle *flatButtonStyle = new QWindowsStyle; - openButton->setFocusPolicy(Qt::NoFocus); - // openButton->setStyle(flatButtonStyle); - // playButton->setStyle(flatButtonStyle); - // rewindButton->setStyle(flatButtonStyle); - // forwardButton->setStyle(flatButtonStyle); - #endif - QWidget *buttonPanelWidget = new QWidget(this); - buttonPanelWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); - buttonPanelWidget->setLayout(buttonPanelLayout); - vLayout->addWidget(buttonPanelWidget); - - QHBoxLayout *labelLayout = new QHBoxLayout(); - - vLayout->addLayout(labelLayout); - setLayout(vLayout); - - // Create menu bar: - fileMenu = new QMenu(this); - QAction *openFileAction = fileMenu->addAction(tr("Open &File...")); - QAction *openUrlAction = fileMenu->addAction(tr("Open &Location...")); - - fileMenu->addSeparator(); - QMenu *aspectMenu = fileMenu->addMenu(tr("&Aspect ratio")); - QActionGroup *aspectGroup = new QActionGroup(aspectMenu); - connect(aspectGroup, SIGNAL(triggered(QAction *)), this, SLOT(aspectChanged(QAction *))); - aspectGroup->setExclusive(true); - QAction *aspectActionAuto = aspectMenu->addAction(tr("Auto")); - aspectActionAuto->setCheckable(true); - aspectActionAuto->setChecked(true); - aspectGroup->addAction(aspectActionAuto); - QAction *aspectActionScale = aspectMenu->addAction(tr("Scale")); - aspectActionScale->setCheckable(true); - aspectGroup->addAction(aspectActionScale); - QAction *aspectAction16_9 = aspectMenu->addAction(tr("16/9")); - aspectAction16_9->setCheckable(true); - aspectGroup->addAction(aspectAction16_9); - QAction *aspectAction4_3 = aspectMenu->addAction(tr("4/3")); - aspectAction4_3->setCheckable(true); - aspectGroup->addAction(aspectAction4_3); - - QMenu *scaleMenu = fileMenu->addMenu(tr("&Scale mode")); - QActionGroup *scaleGroup = new QActionGroup(scaleMenu); - connect(scaleGroup, SIGNAL(triggered(QAction *)), this, SLOT(scaleChanged(QAction *))); - scaleGroup->setExclusive(true); - QAction *scaleActionFit = scaleMenu->addAction(tr("Fit in view")); - scaleActionFit->setCheckable(true); - scaleActionFit->setChecked(true); - scaleGroup->addAction(scaleActionFit); - QAction *scaleActionCrop = scaleMenu->addAction(tr("Scale and crop")); - scaleActionCrop->setCheckable(true); - scaleGroup->addAction(scaleActionCrop); - - fileMenu->addSeparator(); - QAction *settingsAction = fileMenu->addAction(tr("&Settings...")); - - // Setup signal connections: - connect(rewindButton, SIGNAL(clicked()), this, SLOT(rewind())); - //connect(openButton, SIGNAL(clicked()), this, SLOT(openFile())); - openButton->setMenu(fileMenu); - - connect(playButton, SIGNAL(clicked()), this, SLOT(playPause())); - connect(forwardButton, SIGNAL(clicked()), this, SLOT(forward())); - //connect(openButton, SIGNAL(clicked()), this, SLOT(openFile())); - connect(settingsAction, SIGNAL(triggered(bool)), this, SLOT(showSettingsDialog())); - connect(openUrlAction, SIGNAL(triggered(bool)), this, SLOT(openUrl())); - connect(openFileAction, SIGNAL(triggered(bool)), this, SLOT(openFile())); - - connect(m_videoWidget, SIGNAL(customContextMenuRequested(const QPoint &)), SLOT(showContextMenu(const QPoint &))); - connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), SLOT(showContextMenu(const QPoint &))); - connect(&m_MediaObject, SIGNAL(metaDataChanged()), this, SLOT(updateInfo())); - connect(&m_MediaObject, SIGNAL(totalTimeChanged(qint64)), this, SLOT(updateTime())); - connect(&m_MediaObject, SIGNAL(tick(qint64)), this, SLOT(updateTime())); - connect(&m_MediaObject, SIGNAL(finished()), this, SLOT(finished())); - connect(&m_MediaObject, SIGNAL(stateChanged(Phonon::State, Phonon::State)), this, SLOT(stateChanged(Phonon::State, Phonon::State))); - connect(&m_MediaObject, SIGNAL(bufferStatus(int)), this, SLOT(bufferStatus(int))); - - rewindButton->setEnabled(false); - playButton->setEnabled(false); - setAcceptDrops(true); - - m_audioOutputPath = Phonon::createPath(&m_MediaObject, &m_AudioOutput); - Phonon::createPath(&m_MediaObject, m_videoWidget); - - if (!filePath.isEmpty()) - setFile(filePath); - resize(minimumSizeHint()); -} - -void MediaPlayer::stateChanged(Phonon::State newstate, Phonon::State oldstate) -{ - Q_UNUSED(oldstate); - - if (oldstate == Phonon::LoadingState) { - m_videoWindow.setVisible(m_MediaObject.hasVideo()); - info->setVisible(!m_MediaObject.hasVideo()); - QRect videoHintRect = QRect(QPoint(0, 0), m_videoWindow.sizeHint()); - QRect newVideoRect = QApplication::desktop()->screenGeometry().intersected(videoHintRect); - if (!m_hasSmallScreen) { - if (m_MediaObject.hasVideo()) { - // Flush event que so that sizeHint takes the - // recently shown/hidden m_videoWindow into account: - qApp->processEvents(); - resize(sizeHint()); - } else - resize(minimumSize()); - } - } - - switch (newstate) { - case Phonon::ErrorState: - QMessageBox::warning(this, "Phonon Mediaplayer", m_MediaObject.errorString(), QMessageBox::Close); - if (m_MediaObject.errorType() == Phonon::FatalError) { - playButton->setEnabled(false); - rewindButton->setEnabled(false); - } else { - m_MediaObject.pause(); - } - break; - case Phonon::PausedState: - case Phonon::StoppedState: - playButton->setIcon(playIcon); - if (m_MediaObject.currentSource().type() != Phonon::MediaSource::Invalid){ - playButton->setEnabled(true); - rewindButton->setEnabled(true); - } else { - playButton->setEnabled(false); - rewindButton->setEnabled(false); - } - break; - case Phonon::PlayingState: - playButton->setEnabled(true); - playButton->setIcon(pauseIcon); - if (m_MediaObject.hasVideo()) - m_videoWindow.show(); - // Fall through - case Phonon::BufferingState: - rewindButton->setEnabled(true); - break; - case Phonon::LoadingState: - rewindButton->setEnabled(false); - break; - } - -} - -void MediaPlayer::initSettingsDialog() -{ - settingsDialog = new QDialog(this); - ui = new Ui_settings(); - ui->setupUi(settingsDialog); - - connect(ui->brightnessSlider, SIGNAL(valueChanged(int)), this, SLOT(setBrightness(int))); - connect(ui->hueSlider, SIGNAL(valueChanged(int)), this, SLOT(setHue(int))); - connect(ui->saturationSlider, SIGNAL(valueChanged(int)), this, SLOT(setSaturation(int))); - connect(ui->contrastSlider , SIGNAL(valueChanged(int)), this, SLOT(setContrast(int))); - connect(ui->aspectCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(setAspect(int))); - connect(ui->scalemodeCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(setScale(int))); - - ui->brightnessSlider->setValue(int(m_videoWidget->brightness() * SLIDER_RANGE)); - ui->hueSlider->setValue(int(m_videoWidget->hue() * SLIDER_RANGE)); - ui->saturationSlider->setValue(int(m_videoWidget->saturation() * SLIDER_RANGE)); - ui->contrastSlider->setValue(int(m_videoWidget->contrast() * SLIDER_RANGE)); - ui->aspectCombo->setCurrentIndex(m_videoWidget->aspectRatio()); - ui->scalemodeCombo->setCurrentIndex(m_videoWidget->scaleMode()); - connect(ui->effectButton, SIGNAL(clicked()), this, SLOT(configureEffect())); - -#ifdef Q_WS_X11 - //Cross fading is not currently implemented in the GStreamer backend - ui->crossFadeSlider->setVisible(false); - ui->crossFadeLabel->setVisible(false); - ui->crossFadeLabel1->setVisible(false); - ui->crossFadeLabel2->setVisible(false); - ui->crossFadeLabel3->setVisible(false); -#endif - ui->crossFadeSlider->setValue((int)(2 * m_MediaObject.transitionTime() / 1000.0f)); - - // Insert audio devices: - QList devices = Phonon::BackendCapabilities::availableAudioOutputDevices(); - for (int i=0; ideviceCombo->addItem(itemText); - if (devices[i] == m_AudioOutput.outputDevice()) - ui->deviceCombo->setCurrentIndex(i); - } - - // Insert audio effects: - ui->audioEffectsCombo->addItem(tr("")); - QList currEffects = m_audioOutputPath.effects(); - Phonon::Effect *currEffect = currEffects.size() ? currEffects[0] : 0; - QList availableEffects = Phonon::BackendCapabilities::availableAudioEffects(); - for (int i=0; iaudioEffectsCombo->addItem(availableEffects[i].name()); - if (currEffect && availableEffects[i] == currEffect->description()) - ui->audioEffectsCombo->setCurrentIndex(i+1); - } - connect(ui->audioEffectsCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(effectChanged())); - -} - -void MediaPlayer::effectChanged() -{ - int currentIndex = ui->audioEffectsCombo->currentIndex(); - if (currentIndex) { - QList availableEffects = Phonon::BackendCapabilities::availableAudioEffects(); - Phonon::EffectDescription chosenEffect = availableEffects[currentIndex - 1]; - - QList currEffects = m_audioOutputPath.effects(); - Phonon::Effect *currentEffect = currEffects.size() ? currEffects[0] : 0; - - // Deleting the running effect will stop playback, it is deleted when removed from path - if (nextEffect && !(currentEffect && (currentEffect->description().name() == nextEffect->description().name()))) - delete nextEffect; - - nextEffect = new Phonon::Effect(chosenEffect); - } - ui->effectButton->setEnabled(currentIndex); -} - -void MediaPlayer::showSettingsDialog() -{ - if (!settingsDialog) - initSettingsDialog(); - - float oldBrightness = m_videoWidget->brightness(); - float oldHue = m_videoWidget->hue(); - float oldSaturation = m_videoWidget->saturation(); - float oldContrast = m_videoWidget->contrast(); - Phonon::VideoWidget::AspectRatio oldAspect = m_videoWidget->aspectRatio(); - Phonon::VideoWidget::ScaleMode oldScale = m_videoWidget->scaleMode(); - int currentEffect = ui->audioEffectsCombo->currentIndex(); - settingsDialog->exec(); - - if (settingsDialog->result() == QDialog::Accepted){ - m_MediaObject.setTransitionTime((int)(1000 * float(ui->crossFadeSlider->value()) / 2.0f)); - QList devices = Phonon::BackendCapabilities::availableAudioOutputDevices(); - m_AudioOutput.setOutputDevice(devices[ui->deviceCombo->currentIndex()]); - QList currEffects = m_audioOutputPath.effects(); - QList availableEffects = Phonon::BackendCapabilities::availableAudioEffects(); - - if (ui->audioEffectsCombo->currentIndex() > 0){ - Phonon::Effect *currentEffect = currEffects.size() ? currEffects[0] : 0; - if (!currentEffect || currentEffect->description() != nextEffect->description()){ - foreach(Phonon::Effect *effect, currEffects) { - m_audioOutputPath.removeEffect(effect); - delete effect; - } - m_audioOutputPath.insertEffect(nextEffect); - } - } else { - foreach(Phonon::Effect *effect, currEffects) { - m_audioOutputPath.removeEffect(effect); - delete effect; - nextEffect = 0; - } - } - } else { - // Restore previous settings - m_videoWidget->setBrightness(oldBrightness); - m_videoWidget->setSaturation(oldSaturation); - m_videoWidget->setHue(oldHue); - m_videoWidget->setContrast(oldContrast); - m_videoWidget->setAspectRatio(oldAspect); - m_videoWidget->setScaleMode(oldScale); - ui->audioEffectsCombo->setCurrentIndex(currentEffect); - } -} - -void MediaPlayer::initVideoWindow() -{ - QVBoxLayout *videoLayout = new QVBoxLayout(); - videoLayout->addWidget(m_videoWidget); - videoLayout->setContentsMargins(0, 0, 0, 0); - m_videoWindow.setLayout(videoLayout); - m_videoWindow.setMinimumSize(100, 100); -} - - -void MediaPlayer::configureEffect() -{ - if (!nextEffect) - return; - - - QList currEffects = m_audioOutputPath.effects(); - const QList availableEffects = Phonon::BackendCapabilities::availableAudioEffects(); - if (ui->audioEffectsCombo->currentIndex() > 0) { - Phonon::EffectDescription chosenEffect = availableEffects[ui->audioEffectsCombo->currentIndex() - 1]; - - QDialog effectDialog; - effectDialog.setWindowTitle(tr("Configure effect")); - QVBoxLayout *topLayout = new QVBoxLayout(&effectDialog); - - QLabel *description = new QLabel("Description:
" + chosenEffect.description(), &effectDialog); - description->setWordWrap(true); - topLayout->addWidget(description); - - QScrollArea *scrollArea = new QScrollArea(&effectDialog); - topLayout->addWidget(scrollArea); - - QVariantList savedParamValues; - foreach(Phonon::EffectParameter param, nextEffect->parameters()) { - savedParamValues << nextEffect->parameterValue(param); - } - - QWidget *scrollWidget = new Phonon::EffectWidget(nextEffect); - scrollWidget->setMinimumWidth(320); - scrollWidget->setContentsMargins(10, 10, 10,10); - scrollArea->setWidget(scrollWidget); - - QDialogButtonBox *bbox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, &effectDialog); - connect(bbox->button(QDialogButtonBox::Ok), SIGNAL(clicked()), &effectDialog, SLOT(accept())); - connect(bbox->button(QDialogButtonBox::Cancel), SIGNAL(clicked()), &effectDialog, SLOT(reject())); - topLayout->addWidget(bbox); - - effectDialog.exec(); - - if (effectDialog.result() != QDialog::Accepted) { - //we need to restore the paramaters values - int currentIndex = 0; - foreach(Phonon::EffectParameter param, nextEffect->parameters()) { - nextEffect->setParameterValue(param, savedParamValues.at(currentIndex++)); - } - - } - } -} - -void MediaPlayer::handleDrop(QDropEvent *e) -{ - QList urls = e->mimeData()->urls(); - if (e->proposedAction() == Qt::MoveAction){ - // Just add to the queue: - for (int i=0; i 0) { - QString fileName = urls[0].toLocalFile(); - QDir dir(fileName); - if (dir.exists()) { - dir.setFilter(QDir::Files); - QStringList entries = dir.entryList(); - if (entries.size() > 0) { - setFile(fileName + QDir::separator() + entries[0]); - for (int i=1; i< entries.size(); ++i) - m_MediaObject.enqueue(fileName + QDir::separator() + entries[i]); - } - } else { - setFile(fileName); - for (int i=1; isetEnabled(m_MediaObject.queue().size() > 0); - m_MediaObject.play(); -} - -void MediaPlayer::dropEvent(QDropEvent *e) -{ - if (e->mimeData()->hasUrls() && e->proposedAction() != Qt::LinkAction) { - e->acceptProposedAction(); - handleDrop(e); - } else { - e->ignore(); - } -} - -void MediaPlayer::dragEnterEvent(QDragEnterEvent *e) -{ - dragMoveEvent(e); -} - -void MediaPlayer::dragMoveEvent(QDragMoveEvent *e) -{ - if (e->mimeData()->hasUrls()) { - if (e->proposedAction() == Qt::CopyAction || e->proposedAction() == Qt::MoveAction){ - e->acceptProposedAction(); - } - } -} - -void MediaPlayer::playPause() -{ - if (m_MediaObject.state() == Phonon::PlayingState) - m_MediaObject.pause(); - else { - if (m_MediaObject.currentTime() == m_MediaObject.totalTime()) - m_MediaObject.seek(0); - m_MediaObject.play(); - } -} - -void MediaPlayer::setFile(const QString &fileName) -{ - setWindowTitle(fileName.right(fileName.length() - fileName.lastIndexOf('/') - 1)); - m_MediaObject.setCurrentSource(Phonon::MediaSource(fileName)); - m_MediaObject.play(); -} - -void MediaPlayer::openFile() -{ - QStringList fileNames = QFileDialog::getOpenFileNames(this, QString(), - QDesktopServices::storageLocation(QDesktopServices::MusicLocation)); - m_MediaObject.clearQueue(); - if (fileNames.size() > 0) { - QString fileName = fileNames[0]; - setFile(fileName); - for (int i=1; isetEnabled(m_MediaObject.queue().size() > 0); -} - -void MediaPlayer::bufferStatus(int percent) -{ - if (percent == 0 || percent == 100) - progressLabel->setText(QString()); - else { - QString str = QString::fromLatin1("(%1%)").arg(percent); - progressLabel->setText(str); - } -} - -void MediaPlayer::setSaturation(int val) -{ - m_videoWidget->setSaturation(val / qreal(SLIDER_RANGE)); -} - -void MediaPlayer::setHue(int val) -{ - m_videoWidget->setHue(val / qreal(SLIDER_RANGE)); -} - -void MediaPlayer::setAspect(int val) -{ - m_videoWidget->setAspectRatio(Phonon::VideoWidget::AspectRatio(val)); -} - -void MediaPlayer::setScale(int val) -{ - m_videoWidget->setScaleMode(Phonon::VideoWidget::ScaleMode(val)); -} - -void MediaPlayer::setBrightness(int val) -{ - m_videoWidget->setBrightness(val / qreal(SLIDER_RANGE)); -} - -void MediaPlayer::setContrast(int val) -{ - m_videoWidget->setContrast(val / qreal(SLIDER_RANGE)); -} - -void MediaPlayer::updateInfo() -{ - int maxLength = 30; - QString font = ""; - QString fontmono = ""; - - QMap metaData = m_MediaObject.metaData(); - QString trackArtist = metaData.value("ARTIST"); - if (trackArtist.length() > maxLength) - trackArtist = trackArtist.left(maxLength) + "..."; - - QString trackTitle = metaData.value("TITLE"); - int trackBitrate = metaData.value("BITRATE").toInt(); - - QString fileName; - if (m_MediaObject.currentSource().type() == Phonon::MediaSource::Url) { - fileName = m_MediaObject.currentSource().url().toString(); - } else { - fileName = m_MediaObject.currentSource().fileName(); - fileName = fileName.right(fileName.length() - fileName.lastIndexOf('/') - 1); - if (fileName.length() > maxLength) - fileName = fileName.left(maxLength) + "..."; - } - - QString title; - if (!trackTitle.isEmpty()) { - if (trackTitle.length() > maxLength) - trackTitle = trackTitle.left(maxLength) + "..."; - title = "Title: " + font + trackTitle + "
"; - } else if (!fileName.isEmpty()) { - if (fileName.length() > maxLength) - fileName = fileName.left(maxLength) + "..."; - title = font + fileName + "
"; - if (m_MediaObject.currentSource().type() == Phonon::MediaSource::Url) { - title.prepend("Url: "); - } else { - title.prepend("File: "); - } - } - - QString artist; - if (!trackArtist.isEmpty()) - artist = "Artist: " + font + trackArtist + ""; - - QString bitrate; - if (trackBitrate != 0) - bitrate = "
Bitrate: " + font + QString::number(trackBitrate/1000) + "kbit"; - - info->setText(title + artist + bitrate); -} - -void MediaPlayer::updateTime() -{ - long len = m_MediaObject.totalTime(); - long pos = m_MediaObject.currentTime(); - QString timeString; - if (pos || len) - { - int sec = pos/1000; - int min = sec/60; - int hour = min/60; - int msec = pos; - - QTime playTime(hour%60, min%60, sec%60, msec%1000); - sec = len / 1000; - min = sec / 60; - hour = min / 60; - msec = len; - - QTime stopTime(hour%60, min%60, sec%60, msec%1000); - QString timeFormat = "m:ss"; - if (hour > 0) - timeFormat = "h:mm:ss"; - timeString = playTime.toString(timeFormat); - if (len) - timeString += " / " + stopTime.toString(timeFormat); - } - timeLabel->setText(timeString); -} - -void MediaPlayer::rewind() -{ - m_MediaObject.seek(0); -} - -void MediaPlayer::forward() -{ - QList queue = m_MediaObject.queue(); - if (queue.size() > 0) { - m_MediaObject.setCurrentSource(queue[0]); - forwardButton->setEnabled(queue.size() > 1); - m_MediaObject.play(); - } -} - -void MediaPlayer::openUrl() -{ - QSettings settings; - settings.beginGroup(QLatin1String("BrowserMainWindow")); - QString sourceURL = settings.value("location").toString(); - bool ok = false; - sourceURL = QInputDialog::getText(this, tr("Open Location"), tr("Please enter a valid address here:"), QLineEdit::Normal, sourceURL, &ok); - if (ok && !sourceURL.isEmpty()) { - setWindowTitle(sourceURL.right(sourceURL.length() - sourceURL.lastIndexOf('/') - 1)); - m_MediaObject.setCurrentSource(Phonon::MediaSource(QUrl::fromEncoded(sourceURL.toUtf8()))); - m_MediaObject.play(); - settings.setValue("location", sourceURL); - } -} - -void MediaPlayer::finished() -{ -} - -void MediaPlayer::showContextMenu(const QPoint &p) -{ - fileMenu->popup(m_videoWidget->isFullScreen() ? p : mapToGlobal(p)); -} - -void MediaPlayer::scaleChanged(QAction *act) -{ - if (act->text() == tr("Scale and crop")) - m_videoWidget->setScaleMode(Phonon::VideoWidget::ScaleAndCrop); - else - m_videoWidget->setScaleMode(Phonon::VideoWidget::FitInView); -} - -void MediaPlayer::aspectChanged(QAction *act) -{ - if (act->text() == tr("16/9")) - m_videoWidget->setAspectRatio(Phonon::VideoWidget::AspectRatio16_9); - else if (act->text() == tr("Scale")) - m_videoWidget->setAspectRatio(Phonon::VideoWidget::AspectRatioWidget); - else if (act->text() == tr("4/3")) - m_videoWidget->setAspectRatio(Phonon::VideoWidget::AspectRatio4_3); - else - m_videoWidget->setAspectRatio(Phonon::VideoWidget::AspectRatioAuto); -} - diff --git a/demos/mediaplayer/mediaplayer.h b/demos/mediaplayer/mediaplayer.h deleted file mode 100644 index 40ffa40..0000000 --- a/demos/mediaplayer/mediaplayer.h +++ /dev/null @@ -1,139 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the demonstration 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 Technology Preview License Agreement accompanying -** this package. -** -** 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.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -***************************************************************************/ - -#ifndef MEDIALAYER_H -#define MEDIAPLAYER_H - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE -class QPushButton; -class QLabel; -class QSlider; -class QTextEdit; -class QMenu; -class Ui_settings; -QT_END_NAMESPACE - -class MediaPlayer : - public QWidget -{ - Q_OBJECT -public: - MediaPlayer(const QString &, - const bool hasSmallScreen); - - void dragEnterEvent(QDragEnterEvent *e); - void dragMoveEvent(QDragMoveEvent *e); - void dropEvent(QDropEvent *e); - void handleDrop(QDropEvent *e); - void setFile(const QString &text); - void initVideoWindow(); - void initSettingsDialog(); - -public slots: - void openFile(); - void rewind(); - void forward(); - void updateInfo(); - void updateTime(); - void finished(); - void playPause(); - void scaleChanged(QAction *); - void aspectChanged(QAction *); - -private slots: - void setAspect(int); - void setScale(int); - void setSaturation(int); - void setContrast(int); - void setHue(int); - void setBrightness(int); - void stateChanged(Phonon::State newstate, Phonon::State oldstate); - void effectChanged(); - void showSettingsDialog(); - void showContextMenu(const QPoint &); - void bufferStatus(int percent); - void openUrl(); - void configureEffect(); - -private: - QIcon playIcon; - QIcon pauseIcon; - QMenu *fileMenu; - QPushButton *playButton; - QPushButton *rewindButton; - QPushButton *forwardButton; - Phonon::SeekSlider *slider; - QLabel *timeLabel; - QLabel *progressLabel; - Phonon::VolumeSlider *volume; - QSlider *m_hueSlider; - QSlider *m_satSlider; - QSlider *m_contSlider; - QLabel *info; - Phonon::Effect *nextEffect; - QDialog *settingsDialog; - Ui_settings *ui; - - QWidget m_videoWindow; - Phonon::MediaObject m_MediaObject; - Phonon::AudioOutput m_AudioOutput; - Phonon::VideoWidget *m_videoWidget; - Phonon::Path m_audioOutputPath; - const bool m_hasSmallScreen; -}; - -#endif //MEDIAPLAYER_H diff --git a/demos/mediaplayer/mediaplayer.pro b/demos/mediaplayer/mediaplayer.pro deleted file mode 100644 index a420cc3..0000000 --- a/demos/mediaplayer/mediaplayer.pro +++ /dev/null @@ -1,36 +0,0 @@ -###################################################################### -# Automatically generated by qmake (2.01a) Thu Aug 23 18:02:14 2007 -###################################################################### - -TEMPLATE = app -TARGET = qmediaplayer -DEPENDPATH += . build src ui - -QT += phonon - -FORMS += settings.ui -RESOURCES += mediaplayer.qrc - -!win32:CONFIG += CONSOLE - -SOURCES += main.cpp mediaplayer.cpp -HEADERS += mediaplayer.h - -target.path = $$[QT_INSTALL_DEMOS]/qmediaplayer -sources.files = $$SOURCES $$HEADERS $$FORMS $$RESOURCES *.pro *.html *.doc images -sources.path = $$[QT_INSTALL_DEMOS]/mediaplayer -INSTALLS += target sources - -wince*{ -DEPLOYMENT_PLUGIN += phonon_ds9 phonon_waveout -} - -symbian { - TARGET.UID3 = 0xA000C613 - - addFiles.sources = ../embedded/desktopservices/data/sax.mp3 - addFiles.path = /data/sounds/ - DEPLOYMENT += addFiles - - include($$QT_SOURCE_TREE/demos/symbianpkgrules.pri) -} diff --git a/demos/mediaplayer/mediaplayer.qrc b/demos/mediaplayer/mediaplayer.qrc deleted file mode 100644 index bcdf404..0000000 --- a/demos/mediaplayer/mediaplayer.qrc +++ /dev/null @@ -1,5 +0,0 @@ - - - images/screen.png - - diff --git a/demos/mediaplayer/settings.ui b/demos/mediaplayer/settings.ui deleted file mode 100644 index d2cedd4..0000000 --- a/demos/mediaplayer/settings.ui +++ /dev/null @@ -1,464 +0,0 @@ - - settings - - - - 0 - 0 - 360 - 362 - - - - Settings - - - - - - Video options: - - - true - - - - - - Contrast: - - - - - - - -8 - - - 8 - - - Qt::Horizontal - - - QSlider::TicksBelow - - - 4 - - - - - - - Brightness: - - - - - - - -8 - - - 8 - - - Qt::Horizontal - - - QSlider::TicksBelow - - - 4 - - - - - - - Saturation: - - - - - - - -8 - - - 8 - - - Qt::Horizontal - - - QSlider::TicksBelow - - - 4 - - - - - - - Hue: - - - - - - - -8 - - - 8 - - - Qt::Horizontal - - - QSlider::TicksBelow - - - 4 - - - - - - - Aspect ratio: - - - - - - - - 180 - 0 - - - - - Auto - - - - - Stretch - - - - - 4/3 - - - - - 16/9 - - - - - - - - Scale Mode: - - - - - - - - 180 - 0 - - - - - Fit in view - - - - - Scale and crop - - - - - - - - - - - Audio options: - - - true - - - - - - - - - 0 - 0 - - - - - 90 - 0 - - - - Audio device: - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - - - - - - 0 - 0 - - - - - - - - - - - - - 0 - 0 - - - - - 90 - 0 - - - - Audio effect: - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - - - - - - 0 - 0 - - - - - - - - false - - - Setup - - - - - - - - - - - - 0 - 0 - - - - - 90 - 0 - - - - Cross fade: - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - - - - - - - - 0 - 0 - - - - -20 - - - 20 - - - 1 - - - 2 - - - 0 - - - Qt::Horizontal - - - QSlider::TicksBelow - - - - - - - - - - 9 - - - - -10 Sec - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 9 - - - - 0 - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 9 - - - - 10 Sec - - - - - - - - - - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - - - buttonBox - accepted() - settings - accept() - - - 248 - 254 - - - 157 - 274 - - - - - buttonBox - rejected() - settings - reject() - - - 316 - 260 - - - 286 - 274 - - - - - diff --git a/demos/qmediaplayer/images/screen.png b/demos/qmediaplayer/images/screen.png new file mode 100644 index 0000000..a15df92 Binary files /dev/null and b/demos/qmediaplayer/images/screen.png differ diff --git a/demos/qmediaplayer/main.cpp b/demos/qmediaplayer/main.cpp new file mode 100644 index 0000000..66aa445 --- /dev/null +++ b/demos/qmediaplayer/main.cpp @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the demonstration 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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +***************************************************************************/ + +#include +#include "mediaplayer.h" + +int main (int argc, char *argv[]) +{ + Q_INIT_RESOURCE(mediaplayer); + QApplication app(argc, argv); + app.setApplicationName("Media Player"); + app.setOrganizationName("Qt"); + app.setQuitOnLastWindowClosed(true); + + bool hasSmallScreen = +#ifdef Q_OS_SYMBIAN + /* On Symbian, we always want fullscreen. One reason is that it's not + * possible to launch any demos from the fluidlauncher due to a + * limitation in the emulator. */ + true +#else + false +#endif + ; + + QString fileString; + const QStringList args(app.arguments()); + /* We have a minor problem here, we accept two arguments, both are + * optional: + * - A file name + * - the option "-small-screen", so let's try to cope with that. + */ + for (int i = 0; i < args.count(); ++i) { + const QString &at = args.at(i); + + if (at == QLatin1String("-small-screen")) + hasSmallScreen = true; + else if (i > 0) // We don't want the app name. + fileString = at; + } + + MediaPlayer player(fileString, hasSmallScreen); + + if (hasSmallScreen) + player.showMaximized(); + else + player.show(); + + return app.exec(); +} + diff --git a/demos/qmediaplayer/mediaplayer.cpp b/demos/qmediaplayer/mediaplayer.cpp new file mode 100644 index 0000000..baac236 --- /dev/null +++ b/demos/qmediaplayer/mediaplayer.cpp @@ -0,0 +1,845 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the demonstration 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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +***************************************************************************/ + +#include + +#define SLIDER_RANGE 8 + +#include "mediaplayer.h" +#include "ui_settings.h" + + +class MediaVideoWidget : public Phonon::VideoWidget +{ +public: + MediaVideoWidget(MediaPlayer *player, QWidget *parent = 0) : + Phonon::VideoWidget(parent), m_player(player), m_action(this) + { + m_action.setCheckable(true); + m_action.setChecked(false); + m_action.setShortcut(QKeySequence( Qt::AltModifier + Qt::Key_Return)); + m_action.setShortcutContext(Qt::WindowShortcut); + connect(&m_action, SIGNAL(toggled(bool)), SLOT(setFullScreen(bool))); + addAction(&m_action); + setAcceptDrops(true); + } + +protected: + void mouseDoubleClickEvent(QMouseEvent *e) + { + Phonon::VideoWidget::mouseDoubleClickEvent(e); + setFullScreen(!isFullScreen()); + } + + void keyPressEvent(QKeyEvent *e) + { + if (e->key() == Qt::Key_Space && !e->modifiers()) { + m_player->playPause(); + e->accept(); + return; + } else if (e->key() == Qt::Key_Escape && !e->modifiers()) { + setFullScreen(false); + e->accept(); + return; + } + Phonon::VideoWidget::keyPressEvent(e); + } + + bool event(QEvent *e) + { + switch(e->type()) + { + case QEvent::Close: + //we just ignore the cose events on the video widget + //this prevents ALT+F4 from having an effect in fullscreen mode + e->ignore(); + return true; + case QEvent::MouseMove: +#ifndef QT_NO_CURSOR + unsetCursor(); +#endif + //fall through + case QEvent::WindowStateChange: + { + //we just update the state of the checkbox, in case it wasn't already + m_action.setChecked(windowState() & Qt::WindowFullScreen); + const Qt::WindowFlags flags = m_player->windowFlags(); + if (windowState() & Qt::WindowFullScreen) { + m_timer.start(1000, this); + } else { + m_timer.stop(); +#ifndef QT_NO_CURSOR + unsetCursor(); +#endif + } + } + break; + default: + break; + } + + return Phonon::VideoWidget::event(e); + } + + void timerEvent(QTimerEvent *e) + { + if (e->timerId() == m_timer.timerId()) { + //let's store the cursor shape +#ifndef QT_NO_CURSOR + setCursor(Qt::BlankCursor); +#endif + } + Phonon::VideoWidget::timerEvent(e); + } + + void dropEvent(QDropEvent *e) + { + m_player->handleDrop(e); + } + + void dragEnterEvent(QDragEnterEvent *e) { + if (e->mimeData()->hasUrls()) + e->acceptProposedAction(); + } + +private: + MediaPlayer *m_player; + QBasicTimer m_timer; + QAction m_action; +}; + + +MediaPlayer::MediaPlayer(const QString &filePath, + const bool hasSmallScreen) : + playButton(0), nextEffect(0), settingsDialog(0), ui(0), + m_AudioOutput(Phonon::VideoCategory), + m_videoWidget(new MediaVideoWidget(this)), + m_hasSmallScreen(hasSmallScreen) +{ + setWindowTitle(tr("Media Player")); + setContextMenuPolicy(Qt::CustomContextMenu); + m_videoWidget->setContextMenuPolicy(Qt::CustomContextMenu); + + QSize buttonSize(34, 28); + + QPushButton *openButton = new QPushButton(this); + + openButton->setIcon(style()->standardIcon(QStyle::SP_DialogOpenButton)); + QPalette bpal; + QColor arrowcolor = bpal.buttonText().color(); + if (arrowcolor == Qt::black) + arrowcolor = QColor(80, 80, 80); + bpal.setBrush(QPalette::ButtonText, arrowcolor); + openButton->setPalette(bpal); + + rewindButton = new QPushButton(this); + rewindButton->setIcon(style()->standardIcon(QStyle::SP_MediaSkipBackward)); + + forwardButton = new QPushButton(this); + forwardButton->setIcon(style()->standardIcon(QStyle::SP_MediaSkipForward)); + forwardButton->setEnabled(false); + + playButton = new QPushButton(this); + playIcon = style()->standardIcon(QStyle::SP_MediaPlay); + pauseIcon = style()->standardIcon(QStyle::SP_MediaPause); + playButton->setIcon(playIcon); + + slider = new Phonon::SeekSlider(this); + slider->setMediaObject(&m_MediaObject); + volume = new Phonon::VolumeSlider(&m_AudioOutput); + + QVBoxLayout *vLayout = new QVBoxLayout(this); + vLayout->setContentsMargins(8, 8, 8, 8); + + QHBoxLayout *layout = new QHBoxLayout(); + + info = new QLabel(this); + info->setMinimumHeight(70); + info->setAcceptDrops(false); + info->setMargin(2); + info->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken); + info->setLineWidth(2); + info->setAutoFillBackground(true); + + QPalette palette; + palette.setBrush(QPalette::WindowText, Qt::white); +#ifndef Q_WS_MAC + openButton->setMinimumSize(54, buttonSize.height()); + rewindButton->setMinimumSize(buttonSize); + forwardButton->setMinimumSize(buttonSize); + playButton->setMinimumSize(buttonSize); +#endif + info->setStyleSheet("border-image:url(:/images/screen.png) ; border-width:3px"); + info->setPalette(palette); + info->setText(tr("
No media
")); + + volume->setFixedWidth(120); + + layout->addWidget(openButton); + layout->addWidget(rewindButton); + layout->addWidget(playButton); + layout->addWidget(forwardButton); + + layout->addStretch(); + layout->addWidget(volume); + + vLayout->addWidget(info); + initVideoWindow(); + vLayout->addWidget(&m_videoWindow); + QVBoxLayout *buttonPanelLayout = new QVBoxLayout(); + m_videoWindow.hide(); + buttonPanelLayout->addLayout(layout); + + timeLabel = new QLabel(this); + progressLabel = new QLabel(this); + QWidget *sliderPanel = new QWidget(this); + QHBoxLayout *sliderLayout = new QHBoxLayout(); + sliderLayout->addWidget(slider); + sliderLayout->addWidget(timeLabel); + sliderLayout->addWidget(progressLabel); + sliderLayout->setContentsMargins(0, 0, 0, 0); + sliderPanel->setLayout(sliderLayout); + + buttonPanelLayout->addWidget(sliderPanel); + buttonPanelLayout->setContentsMargins(0, 0, 0, 0); +#ifdef Q_OS_MAC + layout->setSpacing(4); + buttonPanelLayout->setSpacing(0); + info->setMinimumHeight(100); + info->setFont(QFont("verdana", 15)); + // QStyle *flatButtonStyle = new QWindowsStyle; + openButton->setFocusPolicy(Qt::NoFocus); + // openButton->setStyle(flatButtonStyle); + // playButton->setStyle(flatButtonStyle); + // rewindButton->setStyle(flatButtonStyle); + // forwardButton->setStyle(flatButtonStyle); + #endif + QWidget *buttonPanelWidget = new QWidget(this); + buttonPanelWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); + buttonPanelWidget->setLayout(buttonPanelLayout); + vLayout->addWidget(buttonPanelWidget); + + QHBoxLayout *labelLayout = new QHBoxLayout(); + + vLayout->addLayout(labelLayout); + setLayout(vLayout); + + // Create menu bar: + fileMenu = new QMenu(this); + QAction *openFileAction = fileMenu->addAction(tr("Open &File...")); + QAction *openUrlAction = fileMenu->addAction(tr("Open &Location...")); + + fileMenu->addSeparator(); + QMenu *aspectMenu = fileMenu->addMenu(tr("&Aspect ratio")); + QActionGroup *aspectGroup = new QActionGroup(aspectMenu); + connect(aspectGroup, SIGNAL(triggered(QAction *)), this, SLOT(aspectChanged(QAction *))); + aspectGroup->setExclusive(true); + QAction *aspectActionAuto = aspectMenu->addAction(tr("Auto")); + aspectActionAuto->setCheckable(true); + aspectActionAuto->setChecked(true); + aspectGroup->addAction(aspectActionAuto); + QAction *aspectActionScale = aspectMenu->addAction(tr("Scale")); + aspectActionScale->setCheckable(true); + aspectGroup->addAction(aspectActionScale); + QAction *aspectAction16_9 = aspectMenu->addAction(tr("16/9")); + aspectAction16_9->setCheckable(true); + aspectGroup->addAction(aspectAction16_9); + QAction *aspectAction4_3 = aspectMenu->addAction(tr("4/3")); + aspectAction4_3->setCheckable(true); + aspectGroup->addAction(aspectAction4_3); + + QMenu *scaleMenu = fileMenu->addMenu(tr("&Scale mode")); + QActionGroup *scaleGroup = new QActionGroup(scaleMenu); + connect(scaleGroup, SIGNAL(triggered(QAction *)), this, SLOT(scaleChanged(QAction *))); + scaleGroup->setExclusive(true); + QAction *scaleActionFit = scaleMenu->addAction(tr("Fit in view")); + scaleActionFit->setCheckable(true); + scaleActionFit->setChecked(true); + scaleGroup->addAction(scaleActionFit); + QAction *scaleActionCrop = scaleMenu->addAction(tr("Scale and crop")); + scaleActionCrop->setCheckable(true); + scaleGroup->addAction(scaleActionCrop); + + fileMenu->addSeparator(); + QAction *settingsAction = fileMenu->addAction(tr("&Settings...")); + + // Setup signal connections: + connect(rewindButton, SIGNAL(clicked()), this, SLOT(rewind())); + //connect(openButton, SIGNAL(clicked()), this, SLOT(openFile())); + openButton->setMenu(fileMenu); + + connect(playButton, SIGNAL(clicked()), this, SLOT(playPause())); + connect(forwardButton, SIGNAL(clicked()), this, SLOT(forward())); + //connect(openButton, SIGNAL(clicked()), this, SLOT(openFile())); + connect(settingsAction, SIGNAL(triggered(bool)), this, SLOT(showSettingsDialog())); + connect(openUrlAction, SIGNAL(triggered(bool)), this, SLOT(openUrl())); + connect(openFileAction, SIGNAL(triggered(bool)), this, SLOT(openFile())); + + connect(m_videoWidget, SIGNAL(customContextMenuRequested(const QPoint &)), SLOT(showContextMenu(const QPoint &))); + connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), SLOT(showContextMenu(const QPoint &))); + connect(&m_MediaObject, SIGNAL(metaDataChanged()), this, SLOT(updateInfo())); + connect(&m_MediaObject, SIGNAL(totalTimeChanged(qint64)), this, SLOT(updateTime())); + connect(&m_MediaObject, SIGNAL(tick(qint64)), this, SLOT(updateTime())); + connect(&m_MediaObject, SIGNAL(finished()), this, SLOT(finished())); + connect(&m_MediaObject, SIGNAL(stateChanged(Phonon::State, Phonon::State)), this, SLOT(stateChanged(Phonon::State, Phonon::State))); + connect(&m_MediaObject, SIGNAL(bufferStatus(int)), this, SLOT(bufferStatus(int))); + + rewindButton->setEnabled(false); + playButton->setEnabled(false); + setAcceptDrops(true); + + m_audioOutputPath = Phonon::createPath(&m_MediaObject, &m_AudioOutput); + Phonon::createPath(&m_MediaObject, m_videoWidget); + + if (!filePath.isEmpty()) + setFile(filePath); + resize(minimumSizeHint()); +} + +void MediaPlayer::stateChanged(Phonon::State newstate, Phonon::State oldstate) +{ + Q_UNUSED(oldstate); + + if (oldstate == Phonon::LoadingState) { + m_videoWindow.setVisible(m_MediaObject.hasVideo()); + info->setVisible(!m_MediaObject.hasVideo()); + QRect videoHintRect = QRect(QPoint(0, 0), m_videoWindow.sizeHint()); + QRect newVideoRect = QApplication::desktop()->screenGeometry().intersected(videoHintRect); + if (!m_hasSmallScreen) { + if (m_MediaObject.hasVideo()) { + // Flush event que so that sizeHint takes the + // recently shown/hidden m_videoWindow into account: + qApp->processEvents(); + resize(sizeHint()); + } else + resize(minimumSize()); + } + } + + switch (newstate) { + case Phonon::ErrorState: + QMessageBox::warning(this, "Phonon Mediaplayer", m_MediaObject.errorString(), QMessageBox::Close); + if (m_MediaObject.errorType() == Phonon::FatalError) { + playButton->setEnabled(false); + rewindButton->setEnabled(false); + } else { + m_MediaObject.pause(); + } + break; + case Phonon::PausedState: + case Phonon::StoppedState: + playButton->setIcon(playIcon); + if (m_MediaObject.currentSource().type() != Phonon::MediaSource::Invalid){ + playButton->setEnabled(true); + rewindButton->setEnabled(true); + } else { + playButton->setEnabled(false); + rewindButton->setEnabled(false); + } + break; + case Phonon::PlayingState: + playButton->setEnabled(true); + playButton->setIcon(pauseIcon); + if (m_MediaObject.hasVideo()) + m_videoWindow.show(); + // Fall through + case Phonon::BufferingState: + rewindButton->setEnabled(true); + break; + case Phonon::LoadingState: + rewindButton->setEnabled(false); + break; + } + +} + +void MediaPlayer::initSettingsDialog() +{ + settingsDialog = new QDialog(this); + ui = new Ui_settings(); + ui->setupUi(settingsDialog); + + connect(ui->brightnessSlider, SIGNAL(valueChanged(int)), this, SLOT(setBrightness(int))); + connect(ui->hueSlider, SIGNAL(valueChanged(int)), this, SLOT(setHue(int))); + connect(ui->saturationSlider, SIGNAL(valueChanged(int)), this, SLOT(setSaturation(int))); + connect(ui->contrastSlider , SIGNAL(valueChanged(int)), this, SLOT(setContrast(int))); + connect(ui->aspectCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(setAspect(int))); + connect(ui->scalemodeCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(setScale(int))); + + ui->brightnessSlider->setValue(int(m_videoWidget->brightness() * SLIDER_RANGE)); + ui->hueSlider->setValue(int(m_videoWidget->hue() * SLIDER_RANGE)); + ui->saturationSlider->setValue(int(m_videoWidget->saturation() * SLIDER_RANGE)); + ui->contrastSlider->setValue(int(m_videoWidget->contrast() * SLIDER_RANGE)); + ui->aspectCombo->setCurrentIndex(m_videoWidget->aspectRatio()); + ui->scalemodeCombo->setCurrentIndex(m_videoWidget->scaleMode()); + connect(ui->effectButton, SIGNAL(clicked()), this, SLOT(configureEffect())); + +#ifdef Q_WS_X11 + //Cross fading is not currently implemented in the GStreamer backend + ui->crossFadeSlider->setVisible(false); + ui->crossFadeLabel->setVisible(false); + ui->crossFadeLabel1->setVisible(false); + ui->crossFadeLabel2->setVisible(false); + ui->crossFadeLabel3->setVisible(false); +#endif + ui->crossFadeSlider->setValue((int)(2 * m_MediaObject.transitionTime() / 1000.0f)); + + // Insert audio devices: + QList devices = Phonon::BackendCapabilities::availableAudioOutputDevices(); + for (int i=0; ideviceCombo->addItem(itemText); + if (devices[i] == m_AudioOutput.outputDevice()) + ui->deviceCombo->setCurrentIndex(i); + } + + // Insert audio effects: + ui->audioEffectsCombo->addItem(tr("")); + QList currEffects = m_audioOutputPath.effects(); + Phonon::Effect *currEffect = currEffects.size() ? currEffects[0] : 0; + QList availableEffects = Phonon::BackendCapabilities::availableAudioEffects(); + for (int i=0; iaudioEffectsCombo->addItem(availableEffects[i].name()); + if (currEffect && availableEffects[i] == currEffect->description()) + ui->audioEffectsCombo->setCurrentIndex(i+1); + } + connect(ui->audioEffectsCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(effectChanged())); + +} + +void MediaPlayer::effectChanged() +{ + int currentIndex = ui->audioEffectsCombo->currentIndex(); + if (currentIndex) { + QList availableEffects = Phonon::BackendCapabilities::availableAudioEffects(); + Phonon::EffectDescription chosenEffect = availableEffects[currentIndex - 1]; + + QList currEffects = m_audioOutputPath.effects(); + Phonon::Effect *currentEffect = currEffects.size() ? currEffects[0] : 0; + + // Deleting the running effect will stop playback, it is deleted when removed from path + if (nextEffect && !(currentEffect && (currentEffect->description().name() == nextEffect->description().name()))) + delete nextEffect; + + nextEffect = new Phonon::Effect(chosenEffect); + } + ui->effectButton->setEnabled(currentIndex); +} + +void MediaPlayer::showSettingsDialog() +{ + if (!settingsDialog) + initSettingsDialog(); + + float oldBrightness = m_videoWidget->brightness(); + float oldHue = m_videoWidget->hue(); + float oldSaturation = m_videoWidget->saturation(); + float oldContrast = m_videoWidget->contrast(); + Phonon::VideoWidget::AspectRatio oldAspect = m_videoWidget->aspectRatio(); + Phonon::VideoWidget::ScaleMode oldScale = m_videoWidget->scaleMode(); + int currentEffect = ui->audioEffectsCombo->currentIndex(); + settingsDialog->exec(); + + if (settingsDialog->result() == QDialog::Accepted){ + m_MediaObject.setTransitionTime((int)(1000 * float(ui->crossFadeSlider->value()) / 2.0f)); + QList devices = Phonon::BackendCapabilities::availableAudioOutputDevices(); + m_AudioOutput.setOutputDevice(devices[ui->deviceCombo->currentIndex()]); + QList currEffects = m_audioOutputPath.effects(); + QList availableEffects = Phonon::BackendCapabilities::availableAudioEffects(); + + if (ui->audioEffectsCombo->currentIndex() > 0){ + Phonon::Effect *currentEffect = currEffects.size() ? currEffects[0] : 0; + if (!currentEffect || currentEffect->description() != nextEffect->description()){ + foreach(Phonon::Effect *effect, currEffects) { + m_audioOutputPath.removeEffect(effect); + delete effect; + } + m_audioOutputPath.insertEffect(nextEffect); + } + } else { + foreach(Phonon::Effect *effect, currEffects) { + m_audioOutputPath.removeEffect(effect); + delete effect; + nextEffect = 0; + } + } + } else { + // Restore previous settings + m_videoWidget->setBrightness(oldBrightness); + m_videoWidget->setSaturation(oldSaturation); + m_videoWidget->setHue(oldHue); + m_videoWidget->setContrast(oldContrast); + m_videoWidget->setAspectRatio(oldAspect); + m_videoWidget->setScaleMode(oldScale); + ui->audioEffectsCombo->setCurrentIndex(currentEffect); + } +} + +void MediaPlayer::initVideoWindow() +{ + QVBoxLayout *videoLayout = new QVBoxLayout(); + videoLayout->addWidget(m_videoWidget); + videoLayout->setContentsMargins(0, 0, 0, 0); + m_videoWindow.setLayout(videoLayout); + m_videoWindow.setMinimumSize(100, 100); +} + + +void MediaPlayer::configureEffect() +{ + if (!nextEffect) + return; + + + QList currEffects = m_audioOutputPath.effects(); + const QList availableEffects = Phonon::BackendCapabilities::availableAudioEffects(); + if (ui->audioEffectsCombo->currentIndex() > 0) { + Phonon::EffectDescription chosenEffect = availableEffects[ui->audioEffectsCombo->currentIndex() - 1]; + + QDialog effectDialog; + effectDialog.setWindowTitle(tr("Configure effect")); + QVBoxLayout *topLayout = new QVBoxLayout(&effectDialog); + + QLabel *description = new QLabel("Description:
" + chosenEffect.description(), &effectDialog); + description->setWordWrap(true); + topLayout->addWidget(description); + + QScrollArea *scrollArea = new QScrollArea(&effectDialog); + topLayout->addWidget(scrollArea); + + QVariantList savedParamValues; + foreach(Phonon::EffectParameter param, nextEffect->parameters()) { + savedParamValues << nextEffect->parameterValue(param); + } + + QWidget *scrollWidget = new Phonon::EffectWidget(nextEffect); + scrollWidget->setMinimumWidth(320); + scrollWidget->setContentsMargins(10, 10, 10,10); + scrollArea->setWidget(scrollWidget); + + QDialogButtonBox *bbox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, &effectDialog); + connect(bbox->button(QDialogButtonBox::Ok), SIGNAL(clicked()), &effectDialog, SLOT(accept())); + connect(bbox->button(QDialogButtonBox::Cancel), SIGNAL(clicked()), &effectDialog, SLOT(reject())); + topLayout->addWidget(bbox); + + effectDialog.exec(); + + if (effectDialog.result() != QDialog::Accepted) { + //we need to restore the paramaters values + int currentIndex = 0; + foreach(Phonon::EffectParameter param, nextEffect->parameters()) { + nextEffect->setParameterValue(param, savedParamValues.at(currentIndex++)); + } + + } + } +} + +void MediaPlayer::handleDrop(QDropEvent *e) +{ + QList urls = e->mimeData()->urls(); + if (e->proposedAction() == Qt::MoveAction){ + // Just add to the queue: + for (int i=0; i 0) { + QString fileName = urls[0].toLocalFile(); + QDir dir(fileName); + if (dir.exists()) { + dir.setFilter(QDir::Files); + QStringList entries = dir.entryList(); + if (entries.size() > 0) { + setFile(fileName + QDir::separator() + entries[0]); + for (int i=1; i< entries.size(); ++i) + m_MediaObject.enqueue(fileName + QDir::separator() + entries[i]); + } + } else { + setFile(fileName); + for (int i=1; isetEnabled(m_MediaObject.queue().size() > 0); + m_MediaObject.play(); +} + +void MediaPlayer::dropEvent(QDropEvent *e) +{ + if (e->mimeData()->hasUrls() && e->proposedAction() != Qt::LinkAction) { + e->acceptProposedAction(); + handleDrop(e); + } else { + e->ignore(); + } +} + +void MediaPlayer::dragEnterEvent(QDragEnterEvent *e) +{ + dragMoveEvent(e); +} + +void MediaPlayer::dragMoveEvent(QDragMoveEvent *e) +{ + if (e->mimeData()->hasUrls()) { + if (e->proposedAction() == Qt::CopyAction || e->proposedAction() == Qt::MoveAction){ + e->acceptProposedAction(); + } + } +} + +void MediaPlayer::playPause() +{ + if (m_MediaObject.state() == Phonon::PlayingState) + m_MediaObject.pause(); + else { + if (m_MediaObject.currentTime() == m_MediaObject.totalTime()) + m_MediaObject.seek(0); + m_MediaObject.play(); + } +} + +void MediaPlayer::setFile(const QString &fileName) +{ + setWindowTitle(fileName.right(fileName.length() - fileName.lastIndexOf('/') - 1)); + m_MediaObject.setCurrentSource(Phonon::MediaSource(fileName)); + m_MediaObject.play(); +} + +void MediaPlayer::openFile() +{ + QStringList fileNames = QFileDialog::getOpenFileNames(this, QString(), + QDesktopServices::storageLocation(QDesktopServices::MusicLocation)); + m_MediaObject.clearQueue(); + if (fileNames.size() > 0) { + QString fileName = fileNames[0]; + setFile(fileName); + for (int i=1; isetEnabled(m_MediaObject.queue().size() > 0); +} + +void MediaPlayer::bufferStatus(int percent) +{ + if (percent == 0 || percent == 100) + progressLabel->setText(QString()); + else { + QString str = QString::fromLatin1("(%1%)").arg(percent); + progressLabel->setText(str); + } +} + +void MediaPlayer::setSaturation(int val) +{ + m_videoWidget->setSaturation(val / qreal(SLIDER_RANGE)); +} + +void MediaPlayer::setHue(int val) +{ + m_videoWidget->setHue(val / qreal(SLIDER_RANGE)); +} + +void MediaPlayer::setAspect(int val) +{ + m_videoWidget->setAspectRatio(Phonon::VideoWidget::AspectRatio(val)); +} + +void MediaPlayer::setScale(int val) +{ + m_videoWidget->setScaleMode(Phonon::VideoWidget::ScaleMode(val)); +} + +void MediaPlayer::setBrightness(int val) +{ + m_videoWidget->setBrightness(val / qreal(SLIDER_RANGE)); +} + +void MediaPlayer::setContrast(int val) +{ + m_videoWidget->setContrast(val / qreal(SLIDER_RANGE)); +} + +void MediaPlayer::updateInfo() +{ + int maxLength = 30; + QString font = ""; + QString fontmono = ""; + + QMap metaData = m_MediaObject.metaData(); + QString trackArtist = metaData.value("ARTIST"); + if (trackArtist.length() > maxLength) + trackArtist = trackArtist.left(maxLength) + "..."; + + QString trackTitle = metaData.value("TITLE"); + int trackBitrate = metaData.value("BITRATE").toInt(); + + QString fileName; + if (m_MediaObject.currentSource().type() == Phonon::MediaSource::Url) { + fileName = m_MediaObject.currentSource().url().toString(); + } else { + fileName = m_MediaObject.currentSource().fileName(); + fileName = fileName.right(fileName.length() - fileName.lastIndexOf('/') - 1); + if (fileName.length() > maxLength) + fileName = fileName.left(maxLength) + "..."; + } + + QString title; + if (!trackTitle.isEmpty()) { + if (trackTitle.length() > maxLength) + trackTitle = trackTitle.left(maxLength) + "..."; + title = "Title: " + font + trackTitle + "
"; + } else if (!fileName.isEmpty()) { + if (fileName.length() > maxLength) + fileName = fileName.left(maxLength) + "..."; + title = font + fileName + "
"; + if (m_MediaObject.currentSource().type() == Phonon::MediaSource::Url) { + title.prepend("Url: "); + } else { + title.prepend("File: "); + } + } + + QString artist; + if (!trackArtist.isEmpty()) + artist = "Artist: " + font + trackArtist + ""; + + QString bitrate; + if (trackBitrate != 0) + bitrate = "
Bitrate: " + font + QString::number(trackBitrate/1000) + "kbit"; + + info->setText(title + artist + bitrate); +} + +void MediaPlayer::updateTime() +{ + long len = m_MediaObject.totalTime(); + long pos = m_MediaObject.currentTime(); + QString timeString; + if (pos || len) + { + int sec = pos/1000; + int min = sec/60; + int hour = min/60; + int msec = pos; + + QTime playTime(hour%60, min%60, sec%60, msec%1000); + sec = len / 1000; + min = sec / 60; + hour = min / 60; + msec = len; + + QTime stopTime(hour%60, min%60, sec%60, msec%1000); + QString timeFormat = "m:ss"; + if (hour > 0) + timeFormat = "h:mm:ss"; + timeString = playTime.toString(timeFormat); + if (len) + timeString += " / " + stopTime.toString(timeFormat); + } + timeLabel->setText(timeString); +} + +void MediaPlayer::rewind() +{ + m_MediaObject.seek(0); +} + +void MediaPlayer::forward() +{ + QList queue = m_MediaObject.queue(); + if (queue.size() > 0) { + m_MediaObject.setCurrentSource(queue[0]); + forwardButton->setEnabled(queue.size() > 1); + m_MediaObject.play(); + } +} + +void MediaPlayer::openUrl() +{ + QSettings settings; + settings.beginGroup(QLatin1String("BrowserMainWindow")); + QString sourceURL = settings.value("location").toString(); + bool ok = false; + sourceURL = QInputDialog::getText(this, tr("Open Location"), tr("Please enter a valid address here:"), QLineEdit::Normal, sourceURL, &ok); + if (ok && !sourceURL.isEmpty()) { + setWindowTitle(sourceURL.right(sourceURL.length() - sourceURL.lastIndexOf('/') - 1)); + m_MediaObject.setCurrentSource(Phonon::MediaSource(QUrl::fromEncoded(sourceURL.toUtf8()))); + m_MediaObject.play(); + settings.setValue("location", sourceURL); + } +} + +void MediaPlayer::finished() +{ +} + +void MediaPlayer::showContextMenu(const QPoint &p) +{ + fileMenu->popup(m_videoWidget->isFullScreen() ? p : mapToGlobal(p)); +} + +void MediaPlayer::scaleChanged(QAction *act) +{ + if (act->text() == tr("Scale and crop")) + m_videoWidget->setScaleMode(Phonon::VideoWidget::ScaleAndCrop); + else + m_videoWidget->setScaleMode(Phonon::VideoWidget::FitInView); +} + +void MediaPlayer::aspectChanged(QAction *act) +{ + if (act->text() == tr("16/9")) + m_videoWidget->setAspectRatio(Phonon::VideoWidget::AspectRatio16_9); + else if (act->text() == tr("Scale")) + m_videoWidget->setAspectRatio(Phonon::VideoWidget::AspectRatioWidget); + else if (act->text() == tr("4/3")) + m_videoWidget->setAspectRatio(Phonon::VideoWidget::AspectRatio4_3); + else + m_videoWidget->setAspectRatio(Phonon::VideoWidget::AspectRatioAuto); +} + diff --git a/demos/qmediaplayer/mediaplayer.h b/demos/qmediaplayer/mediaplayer.h new file mode 100644 index 0000000..40ffa40 --- /dev/null +++ b/demos/qmediaplayer/mediaplayer.h @@ -0,0 +1,139 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the demonstration 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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +***************************************************************************/ + +#ifndef MEDIALAYER_H +#define MEDIAPLAYER_H + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE +class QPushButton; +class QLabel; +class QSlider; +class QTextEdit; +class QMenu; +class Ui_settings; +QT_END_NAMESPACE + +class MediaPlayer : + public QWidget +{ + Q_OBJECT +public: + MediaPlayer(const QString &, + const bool hasSmallScreen); + + void dragEnterEvent(QDragEnterEvent *e); + void dragMoveEvent(QDragMoveEvent *e); + void dropEvent(QDropEvent *e); + void handleDrop(QDropEvent *e); + void setFile(const QString &text); + void initVideoWindow(); + void initSettingsDialog(); + +public slots: + void openFile(); + void rewind(); + void forward(); + void updateInfo(); + void updateTime(); + void finished(); + void playPause(); + void scaleChanged(QAction *); + void aspectChanged(QAction *); + +private slots: + void setAspect(int); + void setScale(int); + void setSaturation(int); + void setContrast(int); + void setHue(int); + void setBrightness(int); + void stateChanged(Phonon::State newstate, Phonon::State oldstate); + void effectChanged(); + void showSettingsDialog(); + void showContextMenu(const QPoint &); + void bufferStatus(int percent); + void openUrl(); + void configureEffect(); + +private: + QIcon playIcon; + QIcon pauseIcon; + QMenu *fileMenu; + QPushButton *playButton; + QPushButton *rewindButton; + QPushButton *forwardButton; + Phonon::SeekSlider *slider; + QLabel *timeLabel; + QLabel *progressLabel; + Phonon::VolumeSlider *volume; + QSlider *m_hueSlider; + QSlider *m_satSlider; + QSlider *m_contSlider; + QLabel *info; + Phonon::Effect *nextEffect; + QDialog *settingsDialog; + Ui_settings *ui; + + QWidget m_videoWindow; + Phonon::MediaObject m_MediaObject; + Phonon::AudioOutput m_AudioOutput; + Phonon::VideoWidget *m_videoWidget; + Phonon::Path m_audioOutputPath; + const bool m_hasSmallScreen; +}; + +#endif //MEDIAPLAYER_H diff --git a/demos/qmediaplayer/mediaplayer.qrc b/demos/qmediaplayer/mediaplayer.qrc new file mode 100644 index 0000000..bcdf404 --- /dev/null +++ b/demos/qmediaplayer/mediaplayer.qrc @@ -0,0 +1,5 @@ + + + images/screen.png + + diff --git a/demos/qmediaplayer/qmediaplayer.pro b/demos/qmediaplayer/qmediaplayer.pro new file mode 100644 index 0000000..2f15c28 --- /dev/null +++ b/demos/qmediaplayer/qmediaplayer.pro @@ -0,0 +1,35 @@ +###################################################################### +# Automatically generated by qmake (2.01a) Thu Aug 23 18:02:14 2007 +###################################################################### + +TEMPLATE = app +DEPENDPATH += . build src ui + +QT += phonon + +FORMS += settings.ui +RESOURCES += mediaplayer.qrc + +!win32:CONFIG += CONSOLE + +SOURCES += main.cpp mediaplayer.cpp +HEADERS += mediaplayer.h + +target.path = $$[QT_INSTALL_DEMOS]/qmediaplayer +sources.files = $$SOURCES $$HEADERS $$FORMS $$RESOURCES *.pro *.html *.doc images +sources.path = $$[QT_INSTALL_DEMOS]/qmediaplayer +INSTALLS += target sources + +wince*{ +DEPLOYMENT_PLUGIN += phonon_ds9 phonon_waveout +} + +symbian { + TARGET.UID3 = 0xA000C613 + + addFiles.sources = ../embedded/desktopservices/data/sax.mp3 + addFiles.path = /data/sounds/ + DEPLOYMENT += addFiles + + include($$QT_SOURCE_TREE/demos/symbianpkgrules.pri) +} diff --git a/demos/qmediaplayer/settings.ui b/demos/qmediaplayer/settings.ui new file mode 100644 index 0000000..d2cedd4 --- /dev/null +++ b/demos/qmediaplayer/settings.ui @@ -0,0 +1,464 @@ + + settings + + + + 0 + 0 + 360 + 362 + + + + Settings + + + + + + Video options: + + + true + + + + + + Contrast: + + + + + + + -8 + + + 8 + + + Qt::Horizontal + + + QSlider::TicksBelow + + + 4 + + + + + + + Brightness: + + + + + + + -8 + + + 8 + + + Qt::Horizontal + + + QSlider::TicksBelow + + + 4 + + + + + + + Saturation: + + + + + + + -8 + + + 8 + + + Qt::Horizontal + + + QSlider::TicksBelow + + + 4 + + + + + + + Hue: + + + + + + + -8 + + + 8 + + + Qt::Horizontal + + + QSlider::TicksBelow + + + 4 + + + + + + + Aspect ratio: + + + + + + + + 180 + 0 + + + + + Auto + + + + + Stretch + + + + + 4/3 + + + + + 16/9 + + + + + + + + Scale Mode: + + + + + + + + 180 + 0 + + + + + Fit in view + + + + + Scale and crop + + + + + + + + + + + Audio options: + + + true + + + + + + + + + 0 + 0 + + + + + 90 + 0 + + + + Audio device: + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + + + + 0 + 0 + + + + + + + + + + + + + 0 + 0 + + + + + 90 + 0 + + + + Audio effect: + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + + + + 0 + 0 + + + + + + + + false + + + Setup + + + + + + + + + + + + 0 + 0 + + + + + 90 + 0 + + + + Cross fade: + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + + + + + + 0 + 0 + + + + -20 + + + 20 + + + 1 + + + 2 + + + 0 + + + Qt::Horizontal + + + QSlider::TicksBelow + + + + + + + + + + 9 + + + + -10 Sec + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 9 + + + + 0 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 9 + + + + 10 Sec + + + + + + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + settings + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + settings + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/demos/qtdemo/xml/examples.xml b/demos/qtdemo/xml/examples.xml index 3f0cd25..2c31484 100644 --- a/demos/qtdemo/xml/examples.xml +++ b/demos/qtdemo/xml/examples.xml @@ -121,7 +121,7 @@ - + @@ -152,7 +152,7 @@ - + diff --git a/doc/src/demos/mediaplayer.qdoc b/doc/src/demos/mediaplayer.qdoc index 9e6b3f9..17ae79b 100644 --- a/doc/src/demos/mediaplayer.qdoc +++ b/doc/src/demos/mediaplayer.qdoc @@ -40,7 +40,7 @@ ****************************************************************************/ /*! - \example demos/mediaplayer + \example demos/qmediaplayer \title Media Player The Media Player demonstration shows how \l{Phonon Module}{Phonon} diff --git a/doc/src/examples/ftp.qdoc b/doc/src/examples/ftp.qdoc index ec8584c..8fded88 100644 --- a/doc/src/examples/ftp.qdoc +++ b/doc/src/examples/ftp.qdoc @@ -78,13 +78,13 @@ \l{QFtp::Command}{commands} we request are finished, the progress of current commands, and information about files on the server. - \snippet examples/network/ftp/ftpwindow.h 0 + \snippet examples/network/qftp/ftpwindow.h 0 We will look at each slot when we examine the \c FtpWindow implementation in the next section. We also make use of a few private variables: - \snippet examples/network/ftp/ftpwindow.h 1 + \snippet examples/network/qftp/ftpwindow.h 1 The \c isDirectory hash keeps a history of all entries explored on the FTP server, and registers whether an entry represents a @@ -98,7 +98,7 @@ We move on to the slots, starting with \c connectOrDisconnect(). - \snippet examples/network/ftp/ftpwindow.cpp 0 + \snippet examples/network/qftp/ftpwindow.cpp 0 If \c ftp is already pointing to a QFtp object, we QFtp::Close its FTP connection and delete the object it points to. Note that we do @@ -106,7 +106,7 @@ to finish its abort operation. \dots - \snippet examples/network/ftp/ftpwindow.cpp 1 + \snippet examples/network/qftp/ftpwindow.cpp 1 If we get here, \c connectOrDisconnect() was called to establish a new FTP connection. We create a new QFtp for our new connection, @@ -118,7 +118,7 @@ is emitted repeatedly during an FTP file transfer, giving us progress reports. - \snippet examples/network/ftp/ftpwindow.cpp 2 + \snippet examples/network/qftp/ftpwindow.cpp 2 The \gui {Ftp Server} line edit contains the IP address or hostname of the server to which we want to connect. We first check @@ -134,39 +134,39 @@ We move on to the \c downloadFile() slot: - \snippet examples/network/ftp/ftpwindow.cpp 3 + \snippet examples/network/qftp/ftpwindow.cpp 3 \dots - \snippet examples/network/ftp/ftpwindow.cpp 4 + \snippet examples/network/qftp/ftpwindow.cpp 4 We first fetch the name of the file, which we find in the selected item of \c fileList. We then start the download by using QFtp::get(). QFtp will send progress signals during the download and a signal when the download is completed. - \snippet examples/network/ftp/ftpwindow.cpp 5 + \snippet examples/network/qftp/ftpwindow.cpp 5 QFtp supports canceling the download of files. - \snippet examples/network/ftp/ftpwindow.cpp 6 + \snippet examples/network/qftp/ftpwindow.cpp 6 The \c ftpCommandFinished() slot is called when QFtp has finished a QFtp::Command. If an error occurred during the command, QFtp will set \c error to one of the values in the QFtp::Error enum; otherwise, \c error is zero. - \snippet examples/network/ftp/ftpwindow.cpp 7 + \snippet examples/network/qftp/ftpwindow.cpp 7 After login, the QFtp::list() function will list the top-level directory on the server. addToList() is connected to QFtp::listInfo(), and will be invoked for each entry in that directory. - \snippet examples/network/ftp/ftpwindow.cpp 8 + \snippet examples/network/qftp/ftpwindow.cpp 8 When a \l{QFtp::}{Get} command is finished, a file has finished downloading (or an error occurred during the download). - \snippet examples/network/ftp/ftpwindow.cpp 9 + \snippet examples/network/qftp/ftpwindow.cpp 9 After a \l{QFtp::}{List} command is performed, we have to check if no entries were found (in which case our \c addToList() function @@ -174,7 +174,7 @@ Let's continue with the \c addToList() slot: - \snippet examples/network/ftp/ftpwindow.cpp 10 + \snippet examples/network/qftp/ftpwindow.cpp 10 When a new file has been resolved during a QFtp::List command, this slot is invoked with a QUrlInfo describing the file. We @@ -182,26 +182,26 @@ does not have a current item, we set the new item to be the current item. - \snippet examples/network/ftp/ftpwindow.cpp 11 + \snippet examples/network/qftp/ftpwindow.cpp 11 The \c processItem() slot is called when an item is double clicked in the \gui {File List}. If the item represents a directory, we want to load the contents of that directory with QFtp::list(). - \snippet examples/network/ftp/ftpwindow.cpp 12 + \snippet examples/network/qftp/ftpwindow.cpp 12 \c cdToParent() is invoked when the user requests to go to the parent directory of the one displayed in the file list. After changing the directory, we QFtp::List its contents. - \snippet examples/network/ftp/ftpwindow.cpp 13 + \snippet examples/network/qftp/ftpwindow.cpp 13 The \c updateDataTransferProgress() slot is called regularly by QFtp::dataTransferProgress() when a file download is in progress. We use a QProgressDialog to show the download progression to the user. - \snippet examples/network/ftp/ftpwindow.cpp 14 + \snippet examples/network/qftp/ftpwindow.cpp 14 The \c enableDownloadButton() is called whenever the current item in \c fileList changes. If the item represents a file, the \gui diff --git a/doc/src/examples/musicplayerexample.qdoc b/doc/src/examples/musicplayerexample.qdoc index 41c9f3a..7145583 100644 --- a/doc/src/examples/musicplayerexample.qdoc +++ b/doc/src/examples/musicplayerexample.qdoc @@ -40,7 +40,7 @@ ****************************************************************************/ /*! - \example phonon/musicplayer + \example phonon/qmusicplayer \title Music Player Example The Music Player Example shows how to use Phonon - the multimedia @@ -90,7 +90,7 @@ look at them when we walk through the \c MainWindow implementation. - \snippet examples/phonon/musicplayer/mainwindow.h 2 + \snippet examples/phonon/qmusicplayer/mainwindow.h 2 We use the \l{Phonon::}{SeekSlider} to move the current playback position in the media stream, and the \l{Phonon::}{VolumeSlider} @@ -99,7 +99,7 @@ metaInformationProvider, to get the meta information from the music files. More on this later. - \snippet examples/phonon/musicplayer/mainwindow.h 1 + \snippet examples/phonon/qmusicplayer/mainwindow.h 1 The \l{Phonon::}{MediaObject} informs us of the state of the playback and properties of the media it is playing back through a series of @@ -116,7 +116,7 @@ We start with the constructor: - \snippet examples/phonon/musicplayer/mainwindow.cpp 0 + \snippet examples/phonon/qmusicplayer/mainwindow.cpp 0 We start by instantiating our media and audio output objects. As mentioned, the media object knows how to playback @@ -130,20 +130,20 @@ paths. Objects are connected using the \c createPath() function, which is part of the Phonon namespace. - \snippet examples/phonon/musicplayer/mainwindow.cpp 1 + \snippet examples/phonon/qmusicplayer/mainwindow.cpp 1 We also connect signals of the media object to slots in our \c MainWindow. We will examine them shortly. - \snippet examples/phonon/musicplayer/mainwindow.cpp 2 + \snippet examples/phonon/qmusicplayer/mainwindow.cpp 2 Finally, we call private helper functions to set up the GUI. The \c setupUi() function contains code for setting up the seek , and volume slider. We move on to \c setupUi(): - \snippet examples/phonon/musicplayer/mainwindow.cpp 3 + \snippet examples/phonon/qmusicplayer/mainwindow.cpp 3 \dots - \snippet examples/phonon/musicplayer/mainwindow.cpp 4 + \snippet examples/phonon/qmusicplayer/mainwindow.cpp 4 After creating the widgets, they must be supplied with the \l{Phonon::}{MediaObject} and \l{Phonon::}{AudioOutput} objects @@ -152,12 +152,12 @@ In the \c setupActions(), we connect the actions for the play, pause, and stop tool buttons, to slots of the media object. - \snippet examples/phonon/musicplayer/mainwindow.cpp 5 + \snippet examples/phonon/qmusicplayer/mainwindow.cpp 5 We move on to the slots of \c MainWindow, starting with \c addFiles(): - \snippet examples/phonon/musicplayer/mainwindow.cpp 6 + \snippet examples/phonon/qmusicplayer/mainwindow.cpp 6 In the \c addFiles() slot, we add files selected by the user to the \c sources list. We then set the first source selected on the @@ -169,7 +169,7 @@ stateChanged() signal. The \c stateChanged() slot is connected to this signal. - \snippet examples/phonon/musicplayer/mainwindow.cpp 9 + \snippet examples/phonon/qmusicplayer/mainwindow.cpp 9 The \l{Phonon::MediaObject::}{errorString()} function gives a description of the error that is suitable for users of a Phonon @@ -177,7 +177,7 @@ helps us determine whether it is possible to try to play the same file again. - \snippet examples/phonon/musicplayer/mainwindow.cpp 10 + \snippet examples/phonon/qmusicplayer/mainwindow.cpp 10 We update the GUI when the playback state changes, i.e., when it starts, pauses, stops, or resumes. @@ -188,26 +188,26 @@ The \c tick() slot is connected to a \l{Phonon::}{MediaObject} signal which is emitted when the playback position changes: - \snippet examples/phonon/musicplayer/mainwindow.cpp 11 + \snippet examples/phonon/qmusicplayer/mainwindow.cpp 11 The \c time is given in milliseconds. When the table is clicked on with the mouse, \c tableClick() is invoked: - \snippet examples/phonon/musicplayer/mainwindow.cpp 12 + \snippet examples/phonon/qmusicplayer/mainwindow.cpp 12 Since we stop the media object, we first check whether it is currently playing. \c row contains the row in the table that was clicked upon; the indices of \c sources follows the table, so we can simply use \c row to find the new source. - \snippet examples/phonon/musicplayer/mainwindow.cpp 13 + \snippet examples/phonon/qmusicplayer/mainwindow.cpp 13 When the media source changes, we simply need to select the corresponding row in the table. - \snippet examples/phonon/musicplayer/mainwindow.cpp 14 + \snippet examples/phonon/qmusicplayer/mainwindow.cpp 14 When \c metaStateChanged() is invoked, \c metaInformationProvider has resolved the meta data for its current @@ -220,7 +220,7 @@ music table. A file might not contain the meta data requested, in which case an empty string is returned. - \snippet examples/phonon/musicplayer/mainwindow.cpp 15 + \snippet examples/phonon/qmusicplayer/mainwindow.cpp 15 If we have media sources in \c sources of which meta information is not resolved, we set a new source on the \c @@ -229,7 +229,7 @@ We move on to the \c aboutToFinish() slot: - \snippet examples/phonon/musicplayer/mainwindow.cpp 16 + \snippet examples/phonon/qmusicplayer/mainwindow.cpp 16 When a file is finished playing, the Music Player will move on and play the next file in the table. This slot is connected to the @@ -244,5 +244,5 @@ \l{QCoreApplication::}{setApplicationName()}. This is because D-Bus, which is used by Phonon on Linux systems, demands this. - \snippet examples/phonon/musicplayer/main.cpp 1 + \snippet examples/phonon/qmusicplayer/main.cpp 1 */ diff --git a/doc/src/getting-started/demos.qdoc b/doc/src/getting-started/demos.qdoc index 532715e..8f2829a 100644 --- a/doc/src/getting-started/demos.qdoc +++ b/doc/src/getting-started/demos.qdoc @@ -157,7 +157,7 @@ \section1 Phonon \list - \o \l{demos/mediaplayer}{Media Player} demonstrates how the \l{Phonon Module} can be + \o \l{demos/qmediaplayer}{Media Player} demonstrates how the \l{Phonon Module} can be used to implement a basic media player application. \endlist diff --git a/doc/src/getting-started/examples.qdoc b/doc/src/getting-started/examples.qdoc index 30dae88..2ad730a7 100644 --- a/doc/src/getting-started/examples.qdoc +++ b/doc/src/getting-started/examples.qdoc @@ -827,7 +827,7 @@ \list \o \l{phonon/capabilities}{Capabilities}\raisedaster - \o \l{phonon/musicplayer}{Music Player}\raisedaster + \o \l{phonon/qmusicplayer}{Music Player}\raisedaster \endlist */ diff --git a/examples/network/ftp/ftp.pro b/examples/network/ftp/ftp.pro deleted file mode 100644 index ce2a97b..0000000 --- a/examples/network/ftp/ftp.pro +++ /dev/null @@ -1,20 +0,0 @@ -HEADERS = ftpwindow.h -SOURCES = ftpwindow.cpp \ - main.cpp -RESOURCES += ftp.qrc -QT += network - -# install -target.path = $$[QT_INSTALL_EXAMPLES]/network/ftp -sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS ftp.pro images -sources.path = $$[QT_INSTALL_EXAMPLES]/network/ftp -INSTALLS += target sources - -symbian { - TARGET.UID3 = 0xA000A648 - include($$QT_SOURCE_TREE/examples/symbianpkgrules.pri) - HEADERS += sym_iap_util.h - INCLUDEPATH += $$APP_LAYER_SYSTEMINCLUDE - TARGET.CAPABILITY="NetworkServices ReadUserData WriteUserData" - LIBS+=-lesock -lcommdb -linsock # For IAP selection -} diff --git a/examples/network/ftp/ftp.qrc b/examples/network/ftp/ftp.qrc deleted file mode 100644 index b598ab8..0000000 --- a/examples/network/ftp/ftp.qrc +++ /dev/null @@ -1,7 +0,0 @@ - - - images/cdtoparent.png - images/dir.png - images/file.png - - diff --git a/examples/network/ftp/ftpwindow.cpp b/examples/network/ftp/ftpwindow.cpp deleted file mode 100644 index f3fc52b..0000000 --- a/examples/network/ftp/ftpwindow.cpp +++ /dev/null @@ -1,379 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** 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 Technology Preview License Agreement accompanying -** this package. -** -** 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.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include -#include - -#include "ftpwindow.h" - -#ifdef Q_OS_SYMBIAN -#include "sym_iap_util.h" -#endif - -FtpWindow::FtpWindow(QWidget *parent) - : QDialog(parent), ftp(0) -{ - ftpServerLabel = new QLabel(tr("Ftp &server:")); - ftpServerLineEdit = new QLineEdit("ftp.qt.nokia.com"); - ftpServerLabel->setBuddy(ftpServerLineEdit); - - statusLabel = new QLabel(tr("Please enter the name of an FTP server.")); -#ifdef Q_OS_SYMBIAN - // Use word wrapping to fit the text on screen - statusLabel->setWordWrap( true ); -#endif - - fileList = new QTreeWidget; - fileList->setEnabled(false); - fileList->setRootIsDecorated(false); - fileList->setHeaderLabels(QStringList() << tr("Name") << tr("Size") << tr("Owner") << tr("Group") << tr("Time")); - fileList->header()->setStretchLastSection(false); - - connectButton = new QPushButton(tr("Connect")); - connectButton->setDefault(true); - - cdToParentButton = new QPushButton; - cdToParentButton->setIcon(QPixmap(":/images/cdtoparent.png")); - cdToParentButton->setEnabled(false); - - downloadButton = new QPushButton(tr("Download")); - downloadButton->setEnabled(false); - - quitButton = new QPushButton(tr("Quit")); - - buttonBox = new QDialogButtonBox; - buttonBox->addButton(downloadButton, QDialogButtonBox::ActionRole); - buttonBox->addButton(quitButton, QDialogButtonBox::RejectRole); - - progressDialog = new QProgressDialog(this); - - connect(fileList, SIGNAL(itemActivated(QTreeWidgetItem *, int)), - this, SLOT(processItem(QTreeWidgetItem *, int))); - connect(fileList, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)), - this, SLOT(enableDownloadButton())); - connect(progressDialog, SIGNAL(canceled()), this, SLOT(cancelDownload())); - connect(connectButton, SIGNAL(clicked()), this, SLOT(connectOrDisconnect())); - connect(cdToParentButton, SIGNAL(clicked()), this, SLOT(cdToParent())); - connect(downloadButton, SIGNAL(clicked()), this, SLOT(downloadFile())); - connect(quitButton, SIGNAL(clicked()), this, SLOT(close())); - - QHBoxLayout *topLayout = new QHBoxLayout; - topLayout->addWidget(ftpServerLabel); - topLayout->addWidget(ftpServerLineEdit); -#ifndef Q_OS_SYMBIAN - topLayout->addWidget(cdToParentButton); - topLayout->addWidget(connectButton); -#else - // Make app better lookin on small screen - QHBoxLayout *topLayout2 = new QHBoxLayout; - topLayout2->addWidget(cdToParentButton); - topLayout2->addWidget(connectButton); -#endif - - QVBoxLayout *mainLayout = new QVBoxLayout; - mainLayout->addLayout(topLayout); -#ifdef Q_OS_SYMBIAN - // Make app better lookin on small screen - mainLayout->addLayout(topLayout2); -#endif - mainLayout->addWidget(fileList); - mainLayout->addWidget(statusLabel); - mainLayout->addWidget(buttonBox); - setLayout(mainLayout); - -#ifdef Q_OS_SYMBIAN - bDefaultIapSet = false; -#endif - - setWindowTitle(tr("FTP")); -} - -QSize FtpWindow::sizeHint() const -{ - return QSize(500, 300); -} - -//![0] -void FtpWindow::connectOrDisconnect() -{ -#ifdef Q_OS_SYMBIAN - if(!bDefaultIapSet) { - qt_SetDefaultIap(); - bDefaultIapSet = true; - } -#endif - if (ftp) { - ftp->abort(); - ftp->deleteLater(); - ftp = 0; -//![0] - fileList->setEnabled(false); - cdToParentButton->setEnabled(false); - downloadButton->setEnabled(false); - connectButton->setEnabled(true); - connectButton->setText(tr("Connect")); -#ifndef QT_NO_CURSOR - setCursor(Qt::ArrowCursor); -#endif - statusLabel->setText(tr("Please enter the name of an FTP server.")); - return; - } - -#ifndef QT_NO_CURSOR - setCursor(Qt::WaitCursor); -#endif - -//![1] - ftp = new QFtp(this); - connect(ftp, SIGNAL(commandFinished(int, bool)), - this, SLOT(ftpCommandFinished(int, bool))); - connect(ftp, SIGNAL(listInfo(const QUrlInfo &)), - this, SLOT(addToList(const QUrlInfo &))); - connect(ftp, SIGNAL(dataTransferProgress(qint64, qint64)), - this, SLOT(updateDataTransferProgress(qint64, qint64))); - - fileList->clear(); - currentPath.clear(); - isDirectory.clear(); -//![1] - -//![2] - QUrl url(ftpServerLineEdit->text()); - if (!url.isValid() || url.scheme().toLower() != QLatin1String("ftp")) { - ftp->connectToHost(ftpServerLineEdit->text(), 21); - ftp->login(); - } else { - ftp->connectToHost(url.host(), url.port(21)); - - if (!url.userName().isEmpty()) - ftp->login(QUrl::fromPercentEncoding(url.userName().toLatin1()), url.password()); - else - ftp->login(); - if (!url.path().isEmpty()) - ftp->cd(url.path()); - } -//![2] - - fileList->setEnabled(true); - connectButton->setEnabled(false); - connectButton->setText(tr("Disconnect")); - statusLabel->setText(tr("Connecting to FTP server %1...") - .arg(ftpServerLineEdit->text())); -} - -//![3] -void FtpWindow::downloadFile() -{ - QString fileName = fileList->currentItem()->text(0); -//![3] -// - if (QFile::exists(fileName)) { - QMessageBox::information(this, tr("FTP"), - tr("There already exists a file called %1 in " - "the current directory.") - .arg(fileName)); - return; - } - -//![4] - file = new QFile(fileName); - if (!file->open(QIODevice::WriteOnly)) { - QMessageBox::information(this, tr("FTP"), - tr("Unable to save the file %1: %2.") - .arg(fileName).arg(file->errorString())); - delete file; - return; - } - - ftp->get(fileList->currentItem()->text(0), file); - - progressDialog->setLabelText(tr("Downloading %1...").arg(fileName)); - downloadButton->setEnabled(false); - progressDialog->exec(); -} -//![4] - -//![5] -void FtpWindow::cancelDownload() -{ - ftp->abort(); -} -//![5] - -//![6] -void FtpWindow::ftpCommandFinished(int, bool error) -{ -#ifndef QT_NO_CURSOR - setCursor(Qt::ArrowCursor); -#endif - - if (ftp->currentCommand() == QFtp::ConnectToHost) { - if (error) { - QMessageBox::information(this, tr("FTP"), - tr("Unable to connect to the FTP server " - "at %1. Please check that the host " - "name is correct.") - .arg(ftpServerLineEdit->text())); - connectOrDisconnect(); - return; - } - statusLabel->setText(tr("Logged onto %1.") - .arg(ftpServerLineEdit->text())); - fileList->setFocus(); - downloadButton->setDefault(true); - connectButton->setEnabled(true); - return; - } -//![6] - -//![7] - if (ftp->currentCommand() == QFtp::Login) - ftp->list(); -//![7] - -//![8] - if (ftp->currentCommand() == QFtp::Get) { - if (error) { - statusLabel->setText(tr("Canceled download of %1.") - .arg(file->fileName())); - file->close(); - file->remove(); - } else { - statusLabel->setText(tr("Downloaded %1 to current directory.") - .arg(file->fileName())); - file->close(); - } - delete file; - enableDownloadButton(); - progressDialog->hide(); -//![8] -//![9] - } else if (ftp->currentCommand() == QFtp::List) { - if (isDirectory.isEmpty()) { - fileList->addTopLevelItem(new QTreeWidgetItem(QStringList() << tr(""))); - fileList->setEnabled(false); - } - } -//![9] -} - -//![10] -void FtpWindow::addToList(const QUrlInfo &urlInfo) -{ - QTreeWidgetItem *item = new QTreeWidgetItem; - item->setText(0, urlInfo.name()); - item->setText(1, QString::number(urlInfo.size())); - item->setText(2, urlInfo.owner()); - item->setText(3, urlInfo.group()); - item->setText(4, urlInfo.lastModified().toString("MMM dd yyyy")); - - QPixmap pixmap(urlInfo.isDir() ? ":/images/dir.png" : ":/images/file.png"); - item->setIcon(0, pixmap); - - isDirectory[urlInfo.name()] = urlInfo.isDir(); - fileList->addTopLevelItem(item); - if (!fileList->currentItem()) { - fileList->setCurrentItem(fileList->topLevelItem(0)); - fileList->setEnabled(true); - } -} -//![10] - -//![11] -void FtpWindow::processItem(QTreeWidgetItem *item, int /*column*/) -{ - QString name = item->text(0); - if (isDirectory.value(name)) { - fileList->clear(); - isDirectory.clear(); - currentPath += "/" + name; - ftp->cd(name); - ftp->list(); - cdToParentButton->setEnabled(true); -#ifndef QT_NO_CURSOR - setCursor(Qt::WaitCursor); -#endif - return; - } -} -//![11] - -//![12] -void FtpWindow::cdToParent() -{ -#ifndef QT_NO_CURSOR - setCursor(Qt::WaitCursor); -#endif - fileList->clear(); - isDirectory.clear(); - currentPath = currentPath.left(currentPath.lastIndexOf('/')); - if (currentPath.isEmpty()) { - cdToParentButton->setEnabled(false); - ftp->cd("/"); - } else { - ftp->cd(currentPath); - } - ftp->list(); -} -//![12] - -//![13] -void FtpWindow::updateDataTransferProgress(qint64 readBytes, - qint64 totalBytes) -{ - progressDialog->setMaximum(totalBytes); - progressDialog->setValue(readBytes); -} -//![13] - -//![14] -void FtpWindow::enableDownloadButton() -{ - QTreeWidgetItem *current = fileList->currentItem(); - if (current) { - QString currentFile = current->text(0); - downloadButton->setEnabled(!isDirectory.value(currentFile)); - } else { - downloadButton->setEnabled(false); - } -} -//![14] - diff --git a/examples/network/ftp/ftpwindow.h b/examples/network/ftp/ftpwindow.h deleted file mode 100644 index f92c36a..0000000 --- a/examples/network/ftp/ftpwindow.h +++ /dev/null @@ -1,108 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** 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 Technology Preview License Agreement accompanying -** this package. -** -** 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.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef FTPWINDOW_H -#define FTPWINDOW_H - -#include -#include - -QT_BEGIN_NAMESPACE -class QDialogButtonBox; -class QFile; -class QFtp; -class QLabel; -class QLineEdit; -class QTreeWidget; -class QTreeWidgetItem; -class QProgressDialog; -class QPushButton; -class QUrlInfo; -QT_END_NAMESPACE - -class FtpWindow : public QDialog -{ - Q_OBJECT - -public: - FtpWindow(QWidget *parent = 0); - QSize sizeHint() const; - -//![0] -private slots: - void connectOrDisconnect(); - void downloadFile(); - void cancelDownload(); - - void ftpCommandFinished(int commandId, bool error); - void addToList(const QUrlInfo &urlInfo); - void processItem(QTreeWidgetItem *item, int column); - void cdToParent(); - void updateDataTransferProgress(qint64 readBytes, - qint64 totalBytes); - void enableDownloadButton(); -//![0] - -private: - QLabel *ftpServerLabel; - QLineEdit *ftpServerLineEdit; - QLabel *statusLabel; - QTreeWidget *fileList; - QPushButton *cdToParentButton; - QPushButton *connectButton; - QPushButton *downloadButton; - QPushButton *quitButton; - QDialogButtonBox *buttonBox; - QProgressDialog *progressDialog; - -//![1] - QHash isDirectory; - QString currentPath; - QFtp *ftp; - QFile *file; - -#ifdef Q_OS_SYMBIAN - bool bDefaultIapSet; -#endif -//![1] -}; - -#endif diff --git a/examples/network/ftp/images/cdtoparent.png b/examples/network/ftp/images/cdtoparent.png deleted file mode 100644 index 24b6180..0000000 Binary files a/examples/network/ftp/images/cdtoparent.png and /dev/null differ diff --git a/examples/network/ftp/images/dir.png b/examples/network/ftp/images/dir.png deleted file mode 100644 index 0ce5ae7..0000000 Binary files a/examples/network/ftp/images/dir.png and /dev/null differ diff --git a/examples/network/ftp/images/file.png b/examples/network/ftp/images/file.png deleted file mode 100644 index be6c530..0000000 Binary files a/examples/network/ftp/images/file.png and /dev/null differ diff --git a/examples/network/ftp/main.cpp b/examples/network/ftp/main.cpp deleted file mode 100644 index d44ccd7..0000000 --- a/examples/network/ftp/main.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** 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 Technology Preview License Agreement accompanying -** this package. -** -** 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.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include -#include "ftpwindow.h" - -#ifdef Q_OS_SYMBIAN -#include -#include -#endif - -int main(int argc, char *argv[]) -{ - Q_INIT_RESOURCE(ftp); -#ifdef Q_OS_SYMBIAN - // Change current directory from default private to c:\data - // in order that user can access the downloaded content - QDir::setCurrent( "c:\\data" ); -#endif - QApplication app(argc, argv); - FtpWindow ftpWin; -#ifdef Q_OS_SYMBIAN - // Make application better looking and more usable on small screen - ftpWin.showMaximized(); -#else - ftpWin.show(); -#endif - return ftpWin.exec(); -} diff --git a/examples/network/ftp/sym_iap_util.h b/examples/network/ftp/sym_iap_util.h deleted file mode 100644 index ebeae0a..0000000 --- a/examples/network/ftp/sym_iap_util.h +++ /dev/null @@ -1,510 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** 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 Technology Preview License Agreement accompanying -** this package. -** -** 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.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ -#ifndef QSYM_IAP_UTIL_H -#define QSYM_IAP_UTIL_H - -// Symbian -#include -#include -#include -#include -#include -#include -#include - -// OpenC -#include -#include - -//Qt -#include -#include -//#include - -_LIT(KIapNameSetting, "IAP\\Name"); // text - mandatory -_LIT(KIapDialogPref, "IAP\\DialogPref"); // TUnit32 - optional -_LIT(KIapService, "IAP\\IAPService"); // TUnit32 - mandatory -_LIT(KIapServiceType, "IAP\\IAPServiceType"); // text - mandatory -_LIT(KIapBearer, "IAP\\IAPBearer"); // TUint32 - optional -_LIT(KIapBearerType, "IAP\\IAPBearerType"); // text - optional -_LIT(KIapNetwork, "IAP\\IAPNetwork"); // TUint32 - optional - -const QLatin1String qtOrganizationTag("Trolltech"); -const QLatin1String qtNetworkModuleTag("QtNetwork"); -const QLatin1String iapGroupTag("IAP"); -const QLatin1String iapNamesArrayTag("Names"); -const QLatin1String iapNameItemTag("Name"); - -static QTextCodec *utf16LETextCodec = 0; - -void clearIapNamesSettings(QSettings &settings) { - settings.beginGroup(qtNetworkModuleTag); - settings.beginGroup(iapGroupTag); - settings.remove(iapNamesArrayTag); - settings.endGroup(); - settings.endGroup(); -} - -void writeIapNamesSettings(QSettings &settings, const QStringList& iapNames) { - clearIapNamesSettings(settings); - settings.beginGroup(qtNetworkModuleTag); - settings.beginGroup(iapGroupTag); - settings.beginWriteArray(iapNamesArrayTag); - for (int index = 0; index < iapNames.size(); ++index) { - settings.setArrayIndex(index); - settings.setValue(iapNameItemTag, iapNames.at(index)); - } - settings.endArray(); - settings.endGroup(); - settings.endGroup(); -} - -void readIapNamesSettings(QSettings &settings, QStringList& iapNames) { - settings.beginGroup(qtNetworkModuleTag); - settings.beginGroup(iapGroupTag); - int last = settings.beginReadArray(iapNamesArrayTag); - for (int index = 0; index < last; ++index) { - settings.setArrayIndex(index); - iapNames.append(settings.value(iapNameItemTag).toString()); - } - settings.endArray(); - settings.endGroup(); - settings.endGroup(); -} - -static QString qt_TNameToQString(TName data) { - if(utf16LETextCodec == 0) - utf16LETextCodec = QTextCodec::codecForName("UTF-16LE"); - - QByteArray tmpByteArray = QByteArray::fromRawData((char*)(data.PtrZ()), data.Length() * 2); - return utf16LETextCodec->toUnicode(tmpByteArray); -} - -static QString qt_InterfaceInfoL() -{ - QString output; - - TBuf8<512> buffer; - TBuf<128> t; - TAutoClose ss; - User::LeaveIfError(ss.iObj.Connect()); - ss.PushL(); - - TAutoClose sock; - User::LeaveIfError(sock.iObj.Open(ss.iObj, _L("udp"))); - sock.PushL(); - - User::LeaveIfError(sock.iObj.SetOpt(KSoInetEnumInterfaces, KSolInetIfCtrl)); - - TProtocolDesc in; - User::LeaveIfError(sock.iObj.Info(in)); - printf("EPOC32 IP Configuration TCPIP Version %d.%d.%d\n", in.iVersion.iMajor, in.iVersion.iMinor, in.iVersion.iBuild); - - TPckgBuf info, next; - - TInt res=sock.iObj.GetOpt(KSoInetNextInterface, KSolInetIfCtrl, info); - if(res!=KErrNone) - User::Leave(res); - TInt count = 0; - while(res==KErrNone) { - res=sock.iObj.GetOpt(KSoInetNextInterface, KSolInetIfCtrl, next); - - if(info().iName != _L("") && info().iName != _L("loop6") && info().iName != _L("loop4")) { - printf("Interface %d\n", count++); - - printf("Name \"%s\"\n", qt_TNameToQString(info().iName).toLatin1().data()); - printf("NIF tag \"%s\"\n", qt_TNameToQString(info().iTag).toLatin1().data()); - - printf("State "); - switch (info().iState) - { - case EIfPending: - printf("pending\n"); - break; - case EIfUp: - printf("up\n"); - break; - case EIfBusy: - printf("busy\n"); - break; - default: - printf("down\n"); - break; - } - - printf("Mtu %d\n", info().iMtu); - printf("Speed Metric %d\n", info().iSpeedMetric); - - printf("Features:"); - info().iFeatures & KIfIsLoopback ? printf(" loopback") : printf(""); - info().iFeatures & KIfIsDialup ? printf(" dialup") : printf(""); - info().iFeatures & KIfIsPointToPoint ? printf(" pointtopoint") : printf(""); - info().iFeatures & KIfCanBroadcast ? printf(" canbroadcast") : printf(""); - info().iFeatures & KIfCanMulticast ? printf(" canmulticast") : printf(""); - info().iFeatures & KIfCanSetMTU ? printf(" cansetmtu") : printf(""); - info().iFeatures & KIfHasHardwareAddr ? printf(" hardwareaddr") : printf(""); - info().iFeatures & KIfCanSetHardwareAddr ? printf(" cansethardwareaddr") : printf(""); - printf("\n"); - - TName address; - info().iAddress.Output(address); - printf("Addr: %s\n", qt_TNameToQString(address).toLatin1().data()); - - if(info().iAddress.IsLinkLocal()) { - printf(" -link local\n"); - } else if(info().iAddress.IsSiteLocal()) { - printf(" -site local\n"); - } else { - printf(" -global\n"); - } - - info().iNetMask.Output(address); - printf("Netmask %s\n", qt_TNameToQString(address).toLatin1().data()); - - info().iBrdAddr.Output(address); - printf("Broadcast address %s\n", qt_TNameToQString(address).toLatin1().data()); - - info().iDefGate.Output(address); - printf("Gatew: %s\n", qt_TNameToQString(address).toLatin1().data()); - - info().iNameSer1.Output(address); - printf("DNS 1: %s\n", qt_TNameToQString(address).toLatin1().data()); - - info().iNameSer2.Output(address); - printf("DNS 2: %s\n", qt_TNameToQString(address).toLatin1().data()); - - if (info().iHwAddr.Family() != KAFUnspec) { - printf("Hardware address "); - TUint j; - for(j = sizeof(SSockAddr) ; j < sizeof(SSockAddr) + 6 ; ++j) { - if(j < (TUint)info().iHwAddr.Length()) { - printf("%02X", info().iHwAddr[j]); - } else { - printf("??"); - } - if(j < sizeof(SSockAddr) + 5) - printf("-"); - else - printf("\n"); - } - } - } - if(res == KErrNone) { - info = next; - printf("\n"); - } else { - printf("\n"); - } - } - - sock.Pop(); - ss.Pop(); - - return output; -} - -static QString qt_RouteInfoL() { - QString output; - TAutoClose ss; - User::LeaveIfError(ss.iObj.Connect()); - ss.PushL(); - - TAutoClose sock; - User::LeaveIfError(sock.iObj.Open(ss.iObj, _L("udp"))); - sock.PushL(); - - TSoInetRouteInfo routeInfo; - TPckg routeInfoPkg(routeInfo); - - TName destAddr; - TName netMask; - TName gateway; - TName ifAddr; - - // Begins enumeration of routes by setting this option - User::LeaveIfError(sock.iObj.SetOpt(KSoInetEnumRoutes, KSolInetRtCtrl)); - - // The TSoInetRouteInfo contains information for a new route each time GetOpt returns KErrNone - for(TInt i = 0; sock.iObj.GetOpt(KSoInetNextRoute, KSolInetRtCtrl, routeInfoPkg) == KErrNone ; i++) - { - // Extract the destination and netmask - routeInfo.iDstAddr.Output(destAddr); - routeInfo.iNetMask.Output(netMask); - routeInfo.iGateway.Output(gateway); - routeInfo.iIfAddr.Output(ifAddr); -/* - if(destAddr.Length() <= 2) - continue; - - if(netMask.Find(_L("255.255.255.255")) != KErrNotFound - || netMask.Find(_L("0.0.0.0")) != KErrNotFound - || netMask.Find(_L("ffff:ffff:ffff:ffff")) != KErrNotFound) - continue; -*/ - printf("Route Info #[%i]\n", i); - printf("DstAddr %s\n", qt_TNameToQString(destAddr).toLatin1().data()); - printf("NetMask %s\n", qt_TNameToQString(netMask).toLatin1().data()); - printf("Gateway %s\n", qt_TNameToQString(gateway).toLatin1().data()); - printf("IfAddr %s\n", qt_TNameToQString(ifAddr).toLatin1().data()); - printf("\n"); - } - - sock.Pop(); - ss.Pop(); - - return output; -} - -QString qt_TDesC2QStringL(const TDesC& aDescriptor) -{ -#ifdef QT_NO_UNICODE - return QString::fromLocal8Bit(aDescriptor.Ptr(), aDescriptor.Length()); -#else - return QString::fromUtf16(aDescriptor.Ptr(), aDescriptor.Length()); -#endif -} - -static bool qt_SetDefaultIapName(const QString &iapName, int &error) { - struct ifreq ifReq; - // clear structure - memset(&ifReq, 0, sizeof(struct ifreq)); - // set IAP name value - // make sure it is in UTF8 - strcpy(ifReq.ifr_name, iapName.toUtf8().data()); - - if(setdefaultif(&ifReq) == 0) { - // OK - error = 0; - return true; - } else { - error = errno; - return false; - } - -} -static bool qt_SetDefaultSnapId(const int snapId, int &error) { - struct ifreq ifReq; - // clear structure - memset(&ifReq, 0, sizeof(struct ifreq)); - // set SNAP ID value - ifReq.ifr_ifru.snap_id = snapId; - - if(setdefaultif(&ifReq) == 0) { - // OK - error = 0; - return true; - } else { - error = errno; - return false; - } - -} - -static void qt_SaveIapName(QSettings& settings, QStringList& iapNames, QString& iapNameValue) { - if(iapNames.contains(iapNameValue) && iapNames.first() == iapNameValue) { - // no need to update - } else { - if(iapNameValue != QString("Easy WLAN")) { - // new selection alway on top - iapNames.removeAll(iapNameValue); - iapNames.prepend(iapNameValue); - writeIapNamesSettings(settings, iapNames); - } else { - // Unbeliveable ... if IAP dodn't exist before - // no matter what you choose from IAP selection list - // you will get "Easy WLAN" as IAP name value - - // somehow commsdb is not in sync - } - } -} - -static QString qt_OfferIapDialog() { - TBuf8<256> iapName; - - RSocketServ socketServ; - CleanupClosePushL(socketServ); - - RConnection connection; - CleanupClosePushL(connection); - - socketServ.Connect(); - connection.Open(socketServ); - connection.Start(); - - connection.GetDesSetting(TPtrC(KIapNameSetting), iapName); - - //connection.Stop(); - - iapName.ZeroTerminate(); - QString strIapName((char*)iapName.Ptr()); - - int error = 0; - if(!qt_SetDefaultIapName(strIapName, error)) { - //printf("failed setdefaultif @ %i with %s and errno = %d \n", __LINE__, strIapName.toUtf8().data(), error); - strIapName = QString(""); - } - - CleanupStack::PopAndDestroy(&connection); - CleanupStack::PopAndDestroy(&socketServ); - - return strIapName; -} - -static QString qt_CheckForActiveConnection() { - TUint count; - - RSocketServ serv; - CleanupClosePushL(serv); - - RConnection conn; - CleanupClosePushL(conn); - - serv.Connect(); - conn.Open(serv); - - TConnectionInfoBuf connInfo; - - TBuf8<256> iapName; - TBuf8<256> iapServiceType; - - QString strIapName; - - if (conn.EnumerateConnections(count) == KErrNone) { - if(count > 0) { - for (TUint i = 1; i <= count; i++) { - if (conn.GetConnectionInfo(i, connInfo) == KErrNone) { - RConnection tempConn; - CleanupClosePushL(tempConn); - tempConn.Open(serv); - if (tempConn.Attach(connInfo, RConnection::EAttachTypeNormal) == KErrNone) { - tempConn.GetDesSetting(TPtrC(KIapNameSetting), iapName); - tempConn.GetDesSetting(TPtrC(KIapServiceType), iapServiceType); - //tempConn.Stop(); - iapName.ZeroTerminate(); - iapServiceType.ZeroTerminate(); - -// if(iapServiceType.Find(_L8("LANService")) != KErrNotFound) { -// activeLanConnectionFound = ETrue; -// break; -// } - strIapName = QString((char*)iapName.Ptr()); - int error = 0; - if(!qt_SetDefaultIapName(strIapName, error)) { - //printf("failed setdefaultif @ %i with %s and errno = %d \n", __LINE__, strIapName.toUtf8().data(), error); - strIapName = QString(""); - } - - CleanupStack::PopAndDestroy(&tempConn); - break; - } - } - } - } - } - - //conn.Stop(); - - CleanupStack::PopAndDestroy(&conn); - CleanupStack::PopAndDestroy(&serv); - - return strIapName; -} - -static QString qt_CheckSettingsForConnection(QStringList& iapNames) { - QString strIapName; - for(int index = 0; index < iapNames.size(); ++index) { - strIapName = iapNames.at(index); - int error = 0; - if(!qt_SetDefaultIapName(strIapName, error)) { - //printf("failed setdefaultif @ %i with %s and errno = %d \n", __LINE__, strIapName.toUtf8().data(), error); - strIapName = QString(""); - } else { - return strIapName; - } - } - return strIapName; -} - -static void qt_SetDefaultIapL() -{ - // settings @ /c/data/.config/Trolltech.com - QSettings settings(QSettings::UserScope, qtOrganizationTag); - // populate iap name list - QStringList iapNames; - readIapNamesSettings(settings, iapNames); - - QString iapNameValue; - - iapNameValue = qt_CheckForActiveConnection(); - - if(!iapNameValue.isEmpty()) { - qt_SaveIapName(settings, iapNames, iapNameValue); - return; - } - - iapNameValue = qt_CheckSettingsForConnection(iapNames); - - if(!iapNameValue.isEmpty()) { - qt_SaveIapName(settings, iapNames, iapNameValue); - return; - } - - /* - * no active LAN connections yet - * no IAP in settings - * offer IAP dialog to user - */ - iapNameValue = qt_OfferIapDialog(); - qt_SaveIapName(settings, iapNames, iapNameValue); - return; - -} - -static int qt_SetDefaultIap() -{ - TRAPD(err1, qt_SetDefaultIapL()); -// TRAPD(err2, qt_InterfaceInfoL()); -// TRAPD(err3, qt_RouteInfoL()); - return err1; -} - -#endif // QSYM_IAP_UTIL_H diff --git a/examples/network/network.pro b/examples/network/network.pro index 38cdae8..0849271 100644 --- a/examples/network/network.pro +++ b/examples/network/network.pro @@ -6,7 +6,7 @@ SUBDIRS = blockingfortuneclient \ downloadmanager \ fortuneclient \ fortuneserver \ - ftp \ + qftp \ http \ loopback \ threadedfortuneserver \ @@ -16,7 +16,7 @@ SUBDIRS = blockingfortuneclient \ # no QProcess !vxworks:!qnx:SUBDIRS += network-chat -symbian: SUBDIRS = ftp +symbian: SUBDIRS = qftp contains(QT_CONFIG, openssl):SUBDIRS += securesocketclient diff --git a/examples/network/qftp/ftp.qrc b/examples/network/qftp/ftp.qrc new file mode 100644 index 0000000..b598ab8 --- /dev/null +++ b/examples/network/qftp/ftp.qrc @@ -0,0 +1,7 @@ + + + images/cdtoparent.png + images/dir.png + images/file.png + + diff --git a/examples/network/qftp/ftpwindow.cpp b/examples/network/qftp/ftpwindow.cpp new file mode 100644 index 0000000..f3fc52b --- /dev/null +++ b/examples/network/qftp/ftpwindow.cpp @@ -0,0 +1,379 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** 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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +#include "ftpwindow.h" + +#ifdef Q_OS_SYMBIAN +#include "sym_iap_util.h" +#endif + +FtpWindow::FtpWindow(QWidget *parent) + : QDialog(parent), ftp(0) +{ + ftpServerLabel = new QLabel(tr("Ftp &server:")); + ftpServerLineEdit = new QLineEdit("ftp.qt.nokia.com"); + ftpServerLabel->setBuddy(ftpServerLineEdit); + + statusLabel = new QLabel(tr("Please enter the name of an FTP server.")); +#ifdef Q_OS_SYMBIAN + // Use word wrapping to fit the text on screen + statusLabel->setWordWrap( true ); +#endif + + fileList = new QTreeWidget; + fileList->setEnabled(false); + fileList->setRootIsDecorated(false); + fileList->setHeaderLabels(QStringList() << tr("Name") << tr("Size") << tr("Owner") << tr("Group") << tr("Time")); + fileList->header()->setStretchLastSection(false); + + connectButton = new QPushButton(tr("Connect")); + connectButton->setDefault(true); + + cdToParentButton = new QPushButton; + cdToParentButton->setIcon(QPixmap(":/images/cdtoparent.png")); + cdToParentButton->setEnabled(false); + + downloadButton = new QPushButton(tr("Download")); + downloadButton->setEnabled(false); + + quitButton = new QPushButton(tr("Quit")); + + buttonBox = new QDialogButtonBox; + buttonBox->addButton(downloadButton, QDialogButtonBox::ActionRole); + buttonBox->addButton(quitButton, QDialogButtonBox::RejectRole); + + progressDialog = new QProgressDialog(this); + + connect(fileList, SIGNAL(itemActivated(QTreeWidgetItem *, int)), + this, SLOT(processItem(QTreeWidgetItem *, int))); + connect(fileList, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)), + this, SLOT(enableDownloadButton())); + connect(progressDialog, SIGNAL(canceled()), this, SLOT(cancelDownload())); + connect(connectButton, SIGNAL(clicked()), this, SLOT(connectOrDisconnect())); + connect(cdToParentButton, SIGNAL(clicked()), this, SLOT(cdToParent())); + connect(downloadButton, SIGNAL(clicked()), this, SLOT(downloadFile())); + connect(quitButton, SIGNAL(clicked()), this, SLOT(close())); + + QHBoxLayout *topLayout = new QHBoxLayout; + topLayout->addWidget(ftpServerLabel); + topLayout->addWidget(ftpServerLineEdit); +#ifndef Q_OS_SYMBIAN + topLayout->addWidget(cdToParentButton); + topLayout->addWidget(connectButton); +#else + // Make app better lookin on small screen + QHBoxLayout *topLayout2 = new QHBoxLayout; + topLayout2->addWidget(cdToParentButton); + topLayout2->addWidget(connectButton); +#endif + + QVBoxLayout *mainLayout = new QVBoxLayout; + mainLayout->addLayout(topLayout); +#ifdef Q_OS_SYMBIAN + // Make app better lookin on small screen + mainLayout->addLayout(topLayout2); +#endif + mainLayout->addWidget(fileList); + mainLayout->addWidget(statusLabel); + mainLayout->addWidget(buttonBox); + setLayout(mainLayout); + +#ifdef Q_OS_SYMBIAN + bDefaultIapSet = false; +#endif + + setWindowTitle(tr("FTP")); +} + +QSize FtpWindow::sizeHint() const +{ + return QSize(500, 300); +} + +//![0] +void FtpWindow::connectOrDisconnect() +{ +#ifdef Q_OS_SYMBIAN + if(!bDefaultIapSet) { + qt_SetDefaultIap(); + bDefaultIapSet = true; + } +#endif + if (ftp) { + ftp->abort(); + ftp->deleteLater(); + ftp = 0; +//![0] + fileList->setEnabled(false); + cdToParentButton->setEnabled(false); + downloadButton->setEnabled(false); + connectButton->setEnabled(true); + connectButton->setText(tr("Connect")); +#ifndef QT_NO_CURSOR + setCursor(Qt::ArrowCursor); +#endif + statusLabel->setText(tr("Please enter the name of an FTP server.")); + return; + } + +#ifndef QT_NO_CURSOR + setCursor(Qt::WaitCursor); +#endif + +//![1] + ftp = new QFtp(this); + connect(ftp, SIGNAL(commandFinished(int, bool)), + this, SLOT(ftpCommandFinished(int, bool))); + connect(ftp, SIGNAL(listInfo(const QUrlInfo &)), + this, SLOT(addToList(const QUrlInfo &))); + connect(ftp, SIGNAL(dataTransferProgress(qint64, qint64)), + this, SLOT(updateDataTransferProgress(qint64, qint64))); + + fileList->clear(); + currentPath.clear(); + isDirectory.clear(); +//![1] + +//![2] + QUrl url(ftpServerLineEdit->text()); + if (!url.isValid() || url.scheme().toLower() != QLatin1String("ftp")) { + ftp->connectToHost(ftpServerLineEdit->text(), 21); + ftp->login(); + } else { + ftp->connectToHost(url.host(), url.port(21)); + + if (!url.userName().isEmpty()) + ftp->login(QUrl::fromPercentEncoding(url.userName().toLatin1()), url.password()); + else + ftp->login(); + if (!url.path().isEmpty()) + ftp->cd(url.path()); + } +//![2] + + fileList->setEnabled(true); + connectButton->setEnabled(false); + connectButton->setText(tr("Disconnect")); + statusLabel->setText(tr("Connecting to FTP server %1...") + .arg(ftpServerLineEdit->text())); +} + +//![3] +void FtpWindow::downloadFile() +{ + QString fileName = fileList->currentItem()->text(0); +//![3] +// + if (QFile::exists(fileName)) { + QMessageBox::information(this, tr("FTP"), + tr("There already exists a file called %1 in " + "the current directory.") + .arg(fileName)); + return; + } + +//![4] + file = new QFile(fileName); + if (!file->open(QIODevice::WriteOnly)) { + QMessageBox::information(this, tr("FTP"), + tr("Unable to save the file %1: %2.") + .arg(fileName).arg(file->errorString())); + delete file; + return; + } + + ftp->get(fileList->currentItem()->text(0), file); + + progressDialog->setLabelText(tr("Downloading %1...").arg(fileName)); + downloadButton->setEnabled(false); + progressDialog->exec(); +} +//![4] + +//![5] +void FtpWindow::cancelDownload() +{ + ftp->abort(); +} +//![5] + +//![6] +void FtpWindow::ftpCommandFinished(int, bool error) +{ +#ifndef QT_NO_CURSOR + setCursor(Qt::ArrowCursor); +#endif + + if (ftp->currentCommand() == QFtp::ConnectToHost) { + if (error) { + QMessageBox::information(this, tr("FTP"), + tr("Unable to connect to the FTP server " + "at %1. Please check that the host " + "name is correct.") + .arg(ftpServerLineEdit->text())); + connectOrDisconnect(); + return; + } + statusLabel->setText(tr("Logged onto %1.") + .arg(ftpServerLineEdit->text())); + fileList->setFocus(); + downloadButton->setDefault(true); + connectButton->setEnabled(true); + return; + } +//![6] + +//![7] + if (ftp->currentCommand() == QFtp::Login) + ftp->list(); +//![7] + +//![8] + if (ftp->currentCommand() == QFtp::Get) { + if (error) { + statusLabel->setText(tr("Canceled download of %1.") + .arg(file->fileName())); + file->close(); + file->remove(); + } else { + statusLabel->setText(tr("Downloaded %1 to current directory.") + .arg(file->fileName())); + file->close(); + } + delete file; + enableDownloadButton(); + progressDialog->hide(); +//![8] +//![9] + } else if (ftp->currentCommand() == QFtp::List) { + if (isDirectory.isEmpty()) { + fileList->addTopLevelItem(new QTreeWidgetItem(QStringList() << tr(""))); + fileList->setEnabled(false); + } + } +//![9] +} + +//![10] +void FtpWindow::addToList(const QUrlInfo &urlInfo) +{ + QTreeWidgetItem *item = new QTreeWidgetItem; + item->setText(0, urlInfo.name()); + item->setText(1, QString::number(urlInfo.size())); + item->setText(2, urlInfo.owner()); + item->setText(3, urlInfo.group()); + item->setText(4, urlInfo.lastModified().toString("MMM dd yyyy")); + + QPixmap pixmap(urlInfo.isDir() ? ":/images/dir.png" : ":/images/file.png"); + item->setIcon(0, pixmap); + + isDirectory[urlInfo.name()] = urlInfo.isDir(); + fileList->addTopLevelItem(item); + if (!fileList->currentItem()) { + fileList->setCurrentItem(fileList->topLevelItem(0)); + fileList->setEnabled(true); + } +} +//![10] + +//![11] +void FtpWindow::processItem(QTreeWidgetItem *item, int /*column*/) +{ + QString name = item->text(0); + if (isDirectory.value(name)) { + fileList->clear(); + isDirectory.clear(); + currentPath += "/" + name; + ftp->cd(name); + ftp->list(); + cdToParentButton->setEnabled(true); +#ifndef QT_NO_CURSOR + setCursor(Qt::WaitCursor); +#endif + return; + } +} +//![11] + +//![12] +void FtpWindow::cdToParent() +{ +#ifndef QT_NO_CURSOR + setCursor(Qt::WaitCursor); +#endif + fileList->clear(); + isDirectory.clear(); + currentPath = currentPath.left(currentPath.lastIndexOf('/')); + if (currentPath.isEmpty()) { + cdToParentButton->setEnabled(false); + ftp->cd("/"); + } else { + ftp->cd(currentPath); + } + ftp->list(); +} +//![12] + +//![13] +void FtpWindow::updateDataTransferProgress(qint64 readBytes, + qint64 totalBytes) +{ + progressDialog->setMaximum(totalBytes); + progressDialog->setValue(readBytes); +} +//![13] + +//![14] +void FtpWindow::enableDownloadButton() +{ + QTreeWidgetItem *current = fileList->currentItem(); + if (current) { + QString currentFile = current->text(0); + downloadButton->setEnabled(!isDirectory.value(currentFile)); + } else { + downloadButton->setEnabled(false); + } +} +//![14] + diff --git a/examples/network/qftp/ftpwindow.h b/examples/network/qftp/ftpwindow.h new file mode 100644 index 0000000..f92c36a --- /dev/null +++ b/examples/network/qftp/ftpwindow.h @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** 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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef FTPWINDOW_H +#define FTPWINDOW_H + +#include +#include + +QT_BEGIN_NAMESPACE +class QDialogButtonBox; +class QFile; +class QFtp; +class QLabel; +class QLineEdit; +class QTreeWidget; +class QTreeWidgetItem; +class QProgressDialog; +class QPushButton; +class QUrlInfo; +QT_END_NAMESPACE + +class FtpWindow : public QDialog +{ + Q_OBJECT + +public: + FtpWindow(QWidget *parent = 0); + QSize sizeHint() const; + +//![0] +private slots: + void connectOrDisconnect(); + void downloadFile(); + void cancelDownload(); + + void ftpCommandFinished(int commandId, bool error); + void addToList(const QUrlInfo &urlInfo); + void processItem(QTreeWidgetItem *item, int column); + void cdToParent(); + void updateDataTransferProgress(qint64 readBytes, + qint64 totalBytes); + void enableDownloadButton(); +//![0] + +private: + QLabel *ftpServerLabel; + QLineEdit *ftpServerLineEdit; + QLabel *statusLabel; + QTreeWidget *fileList; + QPushButton *cdToParentButton; + QPushButton *connectButton; + QPushButton *downloadButton; + QPushButton *quitButton; + QDialogButtonBox *buttonBox; + QProgressDialog *progressDialog; + +//![1] + QHash isDirectory; + QString currentPath; + QFtp *ftp; + QFile *file; + +#ifdef Q_OS_SYMBIAN + bool bDefaultIapSet; +#endif +//![1] +}; + +#endif diff --git a/examples/network/qftp/images/cdtoparent.png b/examples/network/qftp/images/cdtoparent.png new file mode 100644 index 0000000..24b6180 Binary files /dev/null and b/examples/network/qftp/images/cdtoparent.png differ diff --git a/examples/network/qftp/images/dir.png b/examples/network/qftp/images/dir.png new file mode 100644 index 0000000..0ce5ae7 Binary files /dev/null and b/examples/network/qftp/images/dir.png differ diff --git a/examples/network/qftp/images/file.png b/examples/network/qftp/images/file.png new file mode 100644 index 0000000..be6c530 Binary files /dev/null and b/examples/network/qftp/images/file.png differ diff --git a/examples/network/qftp/main.cpp b/examples/network/qftp/main.cpp new file mode 100644 index 0000000..d44ccd7 --- /dev/null +++ b/examples/network/qftp/main.cpp @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** 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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include "ftpwindow.h" + +#ifdef Q_OS_SYMBIAN +#include +#include +#endif + +int main(int argc, char *argv[]) +{ + Q_INIT_RESOURCE(ftp); +#ifdef Q_OS_SYMBIAN + // Change current directory from default private to c:\data + // in order that user can access the downloaded content + QDir::setCurrent( "c:\\data" ); +#endif + QApplication app(argc, argv); + FtpWindow ftpWin; +#ifdef Q_OS_SYMBIAN + // Make application better looking and more usable on small screen + ftpWin.showMaximized(); +#else + ftpWin.show(); +#endif + return ftpWin.exec(); +} diff --git a/examples/network/qftp/qftp.pro b/examples/network/qftp/qftp.pro new file mode 100644 index 0000000..b3106c3 --- /dev/null +++ b/examples/network/qftp/qftp.pro @@ -0,0 +1,20 @@ +HEADERS = ftpwindow.h +SOURCES = ftpwindow.cpp \ + main.cpp +RESOURCES += ftp.qrc +QT += network + +# install +target.path = $$[QT_INSTALL_EXAMPLES]/network/qftp +sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS *.pro images +sources.path = $$[QT_INSTALL_EXAMPLES]/network/qftp +INSTALLS += target sources + +symbian { + TARGET.UID3 = 0xA000A648 + include($$QT_SOURCE_TREE/examples/symbianpkgrules.pri) + HEADERS += sym_iap_util.h + INCLUDEPATH += $$APP_LAYER_SYSTEMINCLUDE + TARGET.CAPABILITY="NetworkServices ReadUserData WriteUserData" + LIBS+=-lesock -lcommdb -linsock # For IAP selection +} diff --git a/examples/network/qftp/sym_iap_util.h b/examples/network/qftp/sym_iap_util.h new file mode 100644 index 0000000..ebeae0a --- /dev/null +++ b/examples/network/qftp/sym_iap_util.h @@ -0,0 +1,510 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** 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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef QSYM_IAP_UTIL_H +#define QSYM_IAP_UTIL_H + +// Symbian +#include +#include +#include +#include +#include +#include +#include + +// OpenC +#include +#include + +//Qt +#include +#include +//#include + +_LIT(KIapNameSetting, "IAP\\Name"); // text - mandatory +_LIT(KIapDialogPref, "IAP\\DialogPref"); // TUnit32 - optional +_LIT(KIapService, "IAP\\IAPService"); // TUnit32 - mandatory +_LIT(KIapServiceType, "IAP\\IAPServiceType"); // text - mandatory +_LIT(KIapBearer, "IAP\\IAPBearer"); // TUint32 - optional +_LIT(KIapBearerType, "IAP\\IAPBearerType"); // text - optional +_LIT(KIapNetwork, "IAP\\IAPNetwork"); // TUint32 - optional + +const QLatin1String qtOrganizationTag("Trolltech"); +const QLatin1String qtNetworkModuleTag("QtNetwork"); +const QLatin1String iapGroupTag("IAP"); +const QLatin1String iapNamesArrayTag("Names"); +const QLatin1String iapNameItemTag("Name"); + +static QTextCodec *utf16LETextCodec = 0; + +void clearIapNamesSettings(QSettings &settings) { + settings.beginGroup(qtNetworkModuleTag); + settings.beginGroup(iapGroupTag); + settings.remove(iapNamesArrayTag); + settings.endGroup(); + settings.endGroup(); +} + +void writeIapNamesSettings(QSettings &settings, const QStringList& iapNames) { + clearIapNamesSettings(settings); + settings.beginGroup(qtNetworkModuleTag); + settings.beginGroup(iapGroupTag); + settings.beginWriteArray(iapNamesArrayTag); + for (int index = 0; index < iapNames.size(); ++index) { + settings.setArrayIndex(index); + settings.setValue(iapNameItemTag, iapNames.at(index)); + } + settings.endArray(); + settings.endGroup(); + settings.endGroup(); +} + +void readIapNamesSettings(QSettings &settings, QStringList& iapNames) { + settings.beginGroup(qtNetworkModuleTag); + settings.beginGroup(iapGroupTag); + int last = settings.beginReadArray(iapNamesArrayTag); + for (int index = 0; index < last; ++index) { + settings.setArrayIndex(index); + iapNames.append(settings.value(iapNameItemTag).toString()); + } + settings.endArray(); + settings.endGroup(); + settings.endGroup(); +} + +static QString qt_TNameToQString(TName data) { + if(utf16LETextCodec == 0) + utf16LETextCodec = QTextCodec::codecForName("UTF-16LE"); + + QByteArray tmpByteArray = QByteArray::fromRawData((char*)(data.PtrZ()), data.Length() * 2); + return utf16LETextCodec->toUnicode(tmpByteArray); +} + +static QString qt_InterfaceInfoL() +{ + QString output; + + TBuf8<512> buffer; + TBuf<128> t; + TAutoClose ss; + User::LeaveIfError(ss.iObj.Connect()); + ss.PushL(); + + TAutoClose sock; + User::LeaveIfError(sock.iObj.Open(ss.iObj, _L("udp"))); + sock.PushL(); + + User::LeaveIfError(sock.iObj.SetOpt(KSoInetEnumInterfaces, KSolInetIfCtrl)); + + TProtocolDesc in; + User::LeaveIfError(sock.iObj.Info(in)); + printf("EPOC32 IP Configuration TCPIP Version %d.%d.%d\n", in.iVersion.iMajor, in.iVersion.iMinor, in.iVersion.iBuild); + + TPckgBuf info, next; + + TInt res=sock.iObj.GetOpt(KSoInetNextInterface, KSolInetIfCtrl, info); + if(res!=KErrNone) + User::Leave(res); + TInt count = 0; + while(res==KErrNone) { + res=sock.iObj.GetOpt(KSoInetNextInterface, KSolInetIfCtrl, next); + + if(info().iName != _L("") && info().iName != _L("loop6") && info().iName != _L("loop4")) { + printf("Interface %d\n", count++); + + printf("Name \"%s\"\n", qt_TNameToQString(info().iName).toLatin1().data()); + printf("NIF tag \"%s\"\n", qt_TNameToQString(info().iTag).toLatin1().data()); + + printf("State "); + switch (info().iState) + { + case EIfPending: + printf("pending\n"); + break; + case EIfUp: + printf("up\n"); + break; + case EIfBusy: + printf("busy\n"); + break; + default: + printf("down\n"); + break; + } + + printf("Mtu %d\n", info().iMtu); + printf("Speed Metric %d\n", info().iSpeedMetric); + + printf("Features:"); + info().iFeatures & KIfIsLoopback ? printf(" loopback") : printf(""); + info().iFeatures & KIfIsDialup ? printf(" dialup") : printf(""); + info().iFeatures & KIfIsPointToPoint ? printf(" pointtopoint") : printf(""); + info().iFeatures & KIfCanBroadcast ? printf(" canbroadcast") : printf(""); + info().iFeatures & KIfCanMulticast ? printf(" canmulticast") : printf(""); + info().iFeatures & KIfCanSetMTU ? printf(" cansetmtu") : printf(""); + info().iFeatures & KIfHasHardwareAddr ? printf(" hardwareaddr") : printf(""); + info().iFeatures & KIfCanSetHardwareAddr ? printf(" cansethardwareaddr") : printf(""); + printf("\n"); + + TName address; + info().iAddress.Output(address); + printf("Addr: %s\n", qt_TNameToQString(address).toLatin1().data()); + + if(info().iAddress.IsLinkLocal()) { + printf(" -link local\n"); + } else if(info().iAddress.IsSiteLocal()) { + printf(" -site local\n"); + } else { + printf(" -global\n"); + } + + info().iNetMask.Output(address); + printf("Netmask %s\n", qt_TNameToQString(address).toLatin1().data()); + + info().iBrdAddr.Output(address); + printf("Broadcast address %s\n", qt_TNameToQString(address).toLatin1().data()); + + info().iDefGate.Output(address); + printf("Gatew: %s\n", qt_TNameToQString(address).toLatin1().data()); + + info().iNameSer1.Output(address); + printf("DNS 1: %s\n", qt_TNameToQString(address).toLatin1().data()); + + info().iNameSer2.Output(address); + printf("DNS 2: %s\n", qt_TNameToQString(address).toLatin1().data()); + + if (info().iHwAddr.Family() != KAFUnspec) { + printf("Hardware address "); + TUint j; + for(j = sizeof(SSockAddr) ; j < sizeof(SSockAddr) + 6 ; ++j) { + if(j < (TUint)info().iHwAddr.Length()) { + printf("%02X", info().iHwAddr[j]); + } else { + printf("??"); + } + if(j < sizeof(SSockAddr) + 5) + printf("-"); + else + printf("\n"); + } + } + } + if(res == KErrNone) { + info = next; + printf("\n"); + } else { + printf("\n"); + } + } + + sock.Pop(); + ss.Pop(); + + return output; +} + +static QString qt_RouteInfoL() { + QString output; + TAutoClose ss; + User::LeaveIfError(ss.iObj.Connect()); + ss.PushL(); + + TAutoClose sock; + User::LeaveIfError(sock.iObj.Open(ss.iObj, _L("udp"))); + sock.PushL(); + + TSoInetRouteInfo routeInfo; + TPckg routeInfoPkg(routeInfo); + + TName destAddr; + TName netMask; + TName gateway; + TName ifAddr; + + // Begins enumeration of routes by setting this option + User::LeaveIfError(sock.iObj.SetOpt(KSoInetEnumRoutes, KSolInetRtCtrl)); + + // The TSoInetRouteInfo contains information for a new route each time GetOpt returns KErrNone + for(TInt i = 0; sock.iObj.GetOpt(KSoInetNextRoute, KSolInetRtCtrl, routeInfoPkg) == KErrNone ; i++) + { + // Extract the destination and netmask + routeInfo.iDstAddr.Output(destAddr); + routeInfo.iNetMask.Output(netMask); + routeInfo.iGateway.Output(gateway); + routeInfo.iIfAddr.Output(ifAddr); +/* + if(destAddr.Length() <= 2) + continue; + + if(netMask.Find(_L("255.255.255.255")) != KErrNotFound + || netMask.Find(_L("0.0.0.0")) != KErrNotFound + || netMask.Find(_L("ffff:ffff:ffff:ffff")) != KErrNotFound) + continue; +*/ + printf("Route Info #[%i]\n", i); + printf("DstAddr %s\n", qt_TNameToQString(destAddr).toLatin1().data()); + printf("NetMask %s\n", qt_TNameToQString(netMask).toLatin1().data()); + printf("Gateway %s\n", qt_TNameToQString(gateway).toLatin1().data()); + printf("IfAddr %s\n", qt_TNameToQString(ifAddr).toLatin1().data()); + printf("\n"); + } + + sock.Pop(); + ss.Pop(); + + return output; +} + +QString qt_TDesC2QStringL(const TDesC& aDescriptor) +{ +#ifdef QT_NO_UNICODE + return QString::fromLocal8Bit(aDescriptor.Ptr(), aDescriptor.Length()); +#else + return QString::fromUtf16(aDescriptor.Ptr(), aDescriptor.Length()); +#endif +} + +static bool qt_SetDefaultIapName(const QString &iapName, int &error) { + struct ifreq ifReq; + // clear structure + memset(&ifReq, 0, sizeof(struct ifreq)); + // set IAP name value + // make sure it is in UTF8 + strcpy(ifReq.ifr_name, iapName.toUtf8().data()); + + if(setdefaultif(&ifReq) == 0) { + // OK + error = 0; + return true; + } else { + error = errno; + return false; + } + +} +static bool qt_SetDefaultSnapId(const int snapId, int &error) { + struct ifreq ifReq; + // clear structure + memset(&ifReq, 0, sizeof(struct ifreq)); + // set SNAP ID value + ifReq.ifr_ifru.snap_id = snapId; + + if(setdefaultif(&ifReq) == 0) { + // OK + error = 0; + return true; + } else { + error = errno; + return false; + } + +} + +static void qt_SaveIapName(QSettings& settings, QStringList& iapNames, QString& iapNameValue) { + if(iapNames.contains(iapNameValue) && iapNames.first() == iapNameValue) { + // no need to update + } else { + if(iapNameValue != QString("Easy WLAN")) { + // new selection alway on top + iapNames.removeAll(iapNameValue); + iapNames.prepend(iapNameValue); + writeIapNamesSettings(settings, iapNames); + } else { + // Unbeliveable ... if IAP dodn't exist before + // no matter what you choose from IAP selection list + // you will get "Easy WLAN" as IAP name value + + // somehow commsdb is not in sync + } + } +} + +static QString qt_OfferIapDialog() { + TBuf8<256> iapName; + + RSocketServ socketServ; + CleanupClosePushL(socketServ); + + RConnection connection; + CleanupClosePushL(connection); + + socketServ.Connect(); + connection.Open(socketServ); + connection.Start(); + + connection.GetDesSetting(TPtrC(KIapNameSetting), iapName); + + //connection.Stop(); + + iapName.ZeroTerminate(); + QString strIapName((char*)iapName.Ptr()); + + int error = 0; + if(!qt_SetDefaultIapName(strIapName, error)) { + //printf("failed setdefaultif @ %i with %s and errno = %d \n", __LINE__, strIapName.toUtf8().data(), error); + strIapName = QString(""); + } + + CleanupStack::PopAndDestroy(&connection); + CleanupStack::PopAndDestroy(&socketServ); + + return strIapName; +} + +static QString qt_CheckForActiveConnection() { + TUint count; + + RSocketServ serv; + CleanupClosePushL(serv); + + RConnection conn; + CleanupClosePushL(conn); + + serv.Connect(); + conn.Open(serv); + + TConnectionInfoBuf connInfo; + + TBuf8<256> iapName; + TBuf8<256> iapServiceType; + + QString strIapName; + + if (conn.EnumerateConnections(count) == KErrNone) { + if(count > 0) { + for (TUint i = 1; i <= count; i++) { + if (conn.GetConnectionInfo(i, connInfo) == KErrNone) { + RConnection tempConn; + CleanupClosePushL(tempConn); + tempConn.Open(serv); + if (tempConn.Attach(connInfo, RConnection::EAttachTypeNormal) == KErrNone) { + tempConn.GetDesSetting(TPtrC(KIapNameSetting), iapName); + tempConn.GetDesSetting(TPtrC(KIapServiceType), iapServiceType); + //tempConn.Stop(); + iapName.ZeroTerminate(); + iapServiceType.ZeroTerminate(); + +// if(iapServiceType.Find(_L8("LANService")) != KErrNotFound) { +// activeLanConnectionFound = ETrue; +// break; +// } + strIapName = QString((char*)iapName.Ptr()); + int error = 0; + if(!qt_SetDefaultIapName(strIapName, error)) { + //printf("failed setdefaultif @ %i with %s and errno = %d \n", __LINE__, strIapName.toUtf8().data(), error); + strIapName = QString(""); + } + + CleanupStack::PopAndDestroy(&tempConn); + break; + } + } + } + } + } + + //conn.Stop(); + + CleanupStack::PopAndDestroy(&conn); + CleanupStack::PopAndDestroy(&serv); + + return strIapName; +} + +static QString qt_CheckSettingsForConnection(QStringList& iapNames) { + QString strIapName; + for(int index = 0; index < iapNames.size(); ++index) { + strIapName = iapNames.at(index); + int error = 0; + if(!qt_SetDefaultIapName(strIapName, error)) { + //printf("failed setdefaultif @ %i with %s and errno = %d \n", __LINE__, strIapName.toUtf8().data(), error); + strIapName = QString(""); + } else { + return strIapName; + } + } + return strIapName; +} + +static void qt_SetDefaultIapL() +{ + // settings @ /c/data/.config/Trolltech.com + QSettings settings(QSettings::UserScope, qtOrganizationTag); + // populate iap name list + QStringList iapNames; + readIapNamesSettings(settings, iapNames); + + QString iapNameValue; + + iapNameValue = qt_CheckForActiveConnection(); + + if(!iapNameValue.isEmpty()) { + qt_SaveIapName(settings, iapNames, iapNameValue); + return; + } + + iapNameValue = qt_CheckSettingsForConnection(iapNames); + + if(!iapNameValue.isEmpty()) { + qt_SaveIapName(settings, iapNames, iapNameValue); + return; + } + + /* + * no active LAN connections yet + * no IAP in settings + * offer IAP dialog to user + */ + iapNameValue = qt_OfferIapDialog(); + qt_SaveIapName(settings, iapNames, iapNameValue); + return; + +} + +static int qt_SetDefaultIap() +{ + TRAPD(err1, qt_SetDefaultIapL()); +// TRAPD(err2, qt_InterfaceInfoL()); +// TRAPD(err3, qt_RouteInfoL()); + return err1; +} + +#endif // QSYM_IAP_UTIL_H diff --git a/examples/phonon/musicplayer/main.cpp b/examples/phonon/musicplayer/main.cpp deleted file mode 100644 index fc7baa3..0000000 --- a/examples/phonon/musicplayer/main.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** 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 Technology Preview License Agreement accompanying -** this package. -** -** 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.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ -#include - -#include "mainwindow.h" - -//![1] -int main(int argv, char **args) -{ - QApplication app(argv, args); - app.setApplicationName("Music Player"); - app.setQuitOnLastWindowClosed(true); - - MainWindow window; - window.show(); - - return app.exec(); -} -//![1] diff --git a/examples/phonon/musicplayer/mainwindow.cpp b/examples/phonon/musicplayer/mainwindow.cpp deleted file mode 100644 index 787ae53..0000000 --- a/examples/phonon/musicplayer/mainwindow.cpp +++ /dev/null @@ -1,355 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** 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 Technology Preview License Agreement accompanying -** this package. -** -** 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.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -***************************************************************************/ - -#include - -#include "mainwindow.h" - -//![0] -MainWindow::MainWindow() -{ - audioOutput = new Phonon::AudioOutput(Phonon::MusicCategory, this); - mediaObject = new Phonon::MediaObject(this); - metaInformationResolver = new Phonon::MediaObject(this); - - mediaObject->setTickInterval(1000); -//![0] -//![2] - connect(mediaObject, SIGNAL(tick(qint64)), this, SLOT(tick(qint64))); - connect(mediaObject, SIGNAL(stateChanged(Phonon::State, Phonon::State)), - this, SLOT(stateChanged(Phonon::State, Phonon::State))); - connect(metaInformationResolver, SIGNAL(stateChanged(Phonon::State,Phonon::State)), - this, SLOT(metaStateChanged(Phonon::State, Phonon::State))); - connect(mediaObject, SIGNAL(currentSourceChanged(const Phonon::MediaSource &)), - this, SLOT(sourceChanged(const Phonon::MediaSource &))); - connect(mediaObject, SIGNAL(aboutToFinish()), this, SLOT(aboutToFinish())); -//![2] - -//![1] - Phonon::createPath(mediaObject, audioOutput); -//![1] - - setupActions(); - setupMenus(); - setupUi(); - timeLcd->display("00:00"); -} - -//![6] -void MainWindow::addFiles() -{ - QStringList files = QFileDialog::getOpenFileNames(this, tr("Select Music Files"), - QDesktopServices::storageLocation(QDesktopServices::MusicLocation)); - - if (files.isEmpty()) - return; - - int index = sources.size(); - foreach (QString string, files) { - Phonon::MediaSource source(string); - - sources.append(source); - } - if (!sources.isEmpty()) - metaInformationResolver->setCurrentSource(sources.at(index)); - -} -//![6] - -void MainWindow::about() -{ - QMessageBox::information(this, tr("About Music Player"), - tr("The Music Player example shows how to use Phonon - the multimedia" - " framework that comes with Qt - to create a simple music player.")); -} - -//![9] -void MainWindow::stateChanged(Phonon::State newState, Phonon::State /* oldState */) -{ - switch (newState) { - case Phonon::ErrorState: - if (mediaObject->errorType() == Phonon::FatalError) { - QMessageBox::warning(this, tr("Fatal Error"), - mediaObject->errorString()); - } else { - QMessageBox::warning(this, tr("Error"), - mediaObject->errorString()); - } - break; -//![9] -//![10] - case Phonon::PlayingState: - playAction->setEnabled(false); - pauseAction->setEnabled(true); - stopAction->setEnabled(true); - break; - case Phonon::StoppedState: - stopAction->setEnabled(false); - playAction->setEnabled(true); - pauseAction->setEnabled(false); - timeLcd->display("00:00"); - break; - case Phonon::PausedState: - pauseAction->setEnabled(false); - stopAction->setEnabled(true); - playAction->setEnabled(true); - break; -//![10] - case Phonon::BufferingState: - break; - default: - ; - } -} - -//![11] -void MainWindow::tick(qint64 time) -{ - QTime displayTime(0, (time / 60000) % 60, (time / 1000) % 60); - - timeLcd->display(displayTime.toString("mm:ss")); -} -//![11] - -//![12] -void MainWindow::tableClicked(int row, int /* column */) -{ - bool wasPlaying = mediaObject->state() == Phonon::PlayingState; - - mediaObject->stop(); - mediaObject->clearQueue(); - - if (row >= sources.size()) - return; - - mediaObject->setCurrentSource(sources[row]); - - if (wasPlaying) - mediaObject->play(); - else - mediaObject->stop(); -} -//![12] - -//![13] -void MainWindow::sourceChanged(const Phonon::MediaSource &source) -{ - musicTable->selectRow(sources.indexOf(source)); - timeLcd->display("00:00"); -} -//![13] - -//![14] -void MainWindow::metaStateChanged(Phonon::State newState, Phonon::State /* oldState */) -{ - if (newState == Phonon::ErrorState) { - QMessageBox::warning(this, tr("Error opening files"), - metaInformationResolver->errorString()); - while (!sources.isEmpty() && - !(sources.takeLast() == metaInformationResolver->currentSource())) {} /* loop */; - return; - } - - if (newState != Phonon::StoppedState && newState != Phonon::PausedState) - return; - - if (metaInformationResolver->currentSource().type() == Phonon::MediaSource::Invalid) - return; - - QMap metaData = metaInformationResolver->metaData(); - - QString title = metaData.value("TITLE"); - if (title == "") - title = metaInformationResolver->currentSource().fileName(); - - QTableWidgetItem *titleItem = new QTableWidgetItem(title); - titleItem->setFlags(titleItem->flags() ^ Qt::ItemIsEditable); - QTableWidgetItem *artistItem = new QTableWidgetItem(metaData.value("ARTIST")); - artistItem->setFlags(artistItem->flags() ^ Qt::ItemIsEditable); - QTableWidgetItem *albumItem = new QTableWidgetItem(metaData.value("ALBUM")); - albumItem->setFlags(albumItem->flags() ^ Qt::ItemIsEditable); - QTableWidgetItem *yearItem = new QTableWidgetItem(metaData.value("DATE")); - yearItem->setFlags(yearItem->flags() ^ Qt::ItemIsEditable); -//![14] - - int currentRow = musicTable->rowCount(); - musicTable->insertRow(currentRow); - musicTable->setItem(currentRow, 0, titleItem); - musicTable->setItem(currentRow, 1, artistItem); - musicTable->setItem(currentRow, 2, albumItem); - musicTable->setItem(currentRow, 3, yearItem); - -//![15] - if (musicTable->selectedItems().isEmpty()) { - musicTable->selectRow(0); - mediaObject->setCurrentSource(metaInformationResolver->currentSource()); - } - - Phonon::MediaSource source = metaInformationResolver->currentSource(); - int index = sources.indexOf(metaInformationResolver->currentSource()) + 1; - if (sources.size() > index) { - metaInformationResolver->setCurrentSource(sources.at(index)); - } - else { - musicTable->resizeColumnsToContents(); - if (musicTable->columnWidth(0) > 300) - musicTable->setColumnWidth(0, 300); - } -} -//![15] - -//![16] -void MainWindow::aboutToFinish() -{ - int index = sources.indexOf(mediaObject->currentSource()) + 1; - if (sources.size() > index) { - mediaObject->enqueue(sources.at(index)); - } -} -//![16] - -void MainWindow::setupActions() -{ - playAction = new QAction(style()->standardIcon(QStyle::SP_MediaPlay), tr("Play"), this); - playAction->setShortcut(tr("Crl+P")); - playAction->setDisabled(true); - pauseAction = new QAction(style()->standardIcon(QStyle::SP_MediaPause), tr("Pause"), this); - pauseAction->setShortcut(tr("Ctrl+A")); - pauseAction->setDisabled(true); - stopAction = new QAction(style()->standardIcon(QStyle::SP_MediaStop), tr("Stop"), this); - stopAction->setShortcut(tr("Ctrl+S")); - stopAction->setDisabled(true); - nextAction = new QAction(style()->standardIcon(QStyle::SP_MediaSkipForward), tr("Next"), this); - nextAction->setShortcut(tr("Ctrl+N")); - previousAction = new QAction(style()->standardIcon(QStyle::SP_MediaSkipBackward), tr("Previous"), this); - previousAction->setShortcut(tr("Ctrl+R")); - addFilesAction = new QAction(tr("Add &Files"), this); - addFilesAction->setShortcut(tr("Ctrl+F")); - exitAction = new QAction(tr("E&xit"), this); - exitAction->setShortcuts(QKeySequence::Quit); - aboutAction = new QAction(tr("A&bout"), this); - aboutAction->setShortcut(tr("Ctrl+B")); - aboutQtAction = new QAction(tr("About &Qt"), this); - aboutQtAction->setShortcut(tr("Ctrl+Q")); - -//![5] - connect(playAction, SIGNAL(triggered()), mediaObject, SLOT(play())); - connect(pauseAction, SIGNAL(triggered()), mediaObject, SLOT(pause()) ); - connect(stopAction, SIGNAL(triggered()), mediaObject, SLOT(stop())); -//![5] - connect(addFilesAction, SIGNAL(triggered()), this, SLOT(addFiles())); - connect(exitAction, SIGNAL(triggered()), this, SLOT(close())); - connect(aboutAction, SIGNAL(triggered()), this, SLOT(about())); - connect(aboutQtAction, SIGNAL(triggered()), qApp, SLOT(aboutQt())); -} - -void MainWindow::setupMenus() -{ - QMenu *fileMenu = menuBar()->addMenu(tr("&File")); - fileMenu->addAction(addFilesAction); - fileMenu->addSeparator(); - fileMenu->addAction(exitAction); - - QMenu *aboutMenu = menuBar()->addMenu(tr("&Help")); - aboutMenu->addAction(aboutAction); - aboutMenu->addAction(aboutQtAction); -} - -//![3] -void MainWindow::setupUi() -{ -//![3] - QToolBar *bar = new QToolBar; - - bar->addAction(playAction); - bar->addAction(pauseAction); - bar->addAction(stopAction); - -//![4] - seekSlider = new Phonon::SeekSlider(this); - seekSlider->setMediaObject(mediaObject); - - volumeSlider = new Phonon::VolumeSlider(this); - volumeSlider->setAudioOutput(audioOutput); -//![4] - volumeSlider->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum); - - QLabel *volumeLabel = new QLabel; - volumeLabel->setPixmap(QPixmap("images/volume.png")); - - QPalette palette; - palette.setBrush(QPalette::Light, Qt::darkGray); - - timeLcd = new QLCDNumber; - timeLcd->setPalette(palette); - - QStringList headers; - headers << tr("Title") << tr("Artist") << tr("Album") << tr("Year"); - - musicTable = new QTableWidget(0, 4); - musicTable->setHorizontalHeaderLabels(headers); - musicTable->setSelectionMode(QAbstractItemView::SingleSelection); - musicTable->setSelectionBehavior(QAbstractItemView::SelectRows); - connect(musicTable, SIGNAL(cellPressed(int, int)), - this, SLOT(tableClicked(int, int))); - - QHBoxLayout *seekerLayout = new QHBoxLayout; - seekerLayout->addWidget(seekSlider); - seekerLayout->addWidget(timeLcd); - - QHBoxLayout *playbackLayout = new QHBoxLayout; - playbackLayout->addWidget(bar); - playbackLayout->addStretch(); - playbackLayout->addWidget(volumeLabel); - playbackLayout->addWidget(volumeSlider); - - QVBoxLayout *mainLayout = new QVBoxLayout; - mainLayout->addWidget(musicTable); - mainLayout->addLayout(seekerLayout); - mainLayout->addLayout(playbackLayout); - - QWidget *widget = new QWidget; - widget->setLayout(mainLayout); - - setCentralWidget(widget); - setWindowTitle("Phonon Music Player"); -} - diff --git a/examples/phonon/musicplayer/mainwindow.h b/examples/phonon/musicplayer/mainwindow.h deleted file mode 100644 index 41f8147..0000000 --- a/examples/phonon/musicplayer/mainwindow.h +++ /dev/null @@ -1,112 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** 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 Technology Preview License Agreement accompanying -** this package. -** -** 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.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef MAINWINDOW_H -#define MAINWINDOW_H - -#include -#include -#include -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE -class QAction; -class QTableWidget; -class QLCDNumber; -QT_END_NAMESPACE - -//![0] - -class MainWindow : public QMainWindow -{ -//![0] - Q_OBJECT - -public: - MainWindow(); - - QSize sizeHint() const { - return QSize(500, 300); - } - -private slots: - void addFiles(); - void about(); -//![1] - void stateChanged(Phonon::State newState, Phonon::State oldState); - void tick(qint64 time); - void sourceChanged(const Phonon::MediaSource &source); - void metaStateChanged(Phonon::State newState, Phonon::State oldState); - void aboutToFinish(); - void tableClicked(int row, int column); -//![1] - -private: - void setupActions(); - void setupMenus(); - void setupUi(); - -//![2] - Phonon::SeekSlider *seekSlider; - Phonon::MediaObject *mediaObject; - Phonon::MediaObject *metaInformationResolver; - Phonon::AudioOutput *audioOutput; - Phonon::VolumeSlider *volumeSlider; - QList sources; -//![2] - - QAction *playAction; - QAction *pauseAction; - QAction *stopAction; - QAction *nextAction; - QAction *previousAction; - QAction *addFilesAction; - QAction *exitAction; - QAction *aboutAction; - QAction *aboutQtAction; - QLCDNumber *timeLcd; - QTableWidget *musicTable; -}; - -#endif diff --git a/examples/phonon/musicplayer/musicplayer.pro b/examples/phonon/musicplayer/musicplayer.pro deleted file mode 100644 index a0c953a..0000000 --- a/examples/phonon/musicplayer/musicplayer.pro +++ /dev/null @@ -1,17 +0,0 @@ -QT += phonon - -HEADERS += mainwindow.h -SOURCES += main.cpp \ - mainwindow.cpp - -# install -target.path = $$[QT_INSTALL_EXAMPLES]/phonon/musicplayer -sources.files = $$SOURCES $$HEADERS $$FORMS $$RESOURCES *.pro *.png images -sources.path = $$[QT_INSTALL_EXAMPLES]/phonon/musicplayer -INSTALLS += target sources - -wince*{ -DEPLOYMENT_PLUGIN += phonon_ds9 phonon_waveout -} - -symbian:TARGET.UID3 = 0xA000CF6A diff --git a/examples/phonon/phonon.pro b/examples/phonon/phonon.pro index 0ddf767..aa6ac13 100644 --- a/examples/phonon/phonon.pro +++ b/examples/phonon/phonon.pro @@ -1,6 +1,6 @@ TEMPLATE = subdirs CONFIG += ordered -SUBDIRS = musicplayer \ +SUBDIRS = qmusicplayer \ capabilities # install diff --git a/examples/phonon/qmusicplayer/main.cpp b/examples/phonon/qmusicplayer/main.cpp new file mode 100644 index 0000000..fc7baa3 --- /dev/null +++ b/examples/phonon/qmusicplayer/main.cpp @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** 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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include + +#include "mainwindow.h" + +//![1] +int main(int argv, char **args) +{ + QApplication app(argv, args); + app.setApplicationName("Music Player"); + app.setQuitOnLastWindowClosed(true); + + MainWindow window; + window.show(); + + return app.exec(); +} +//![1] diff --git a/examples/phonon/qmusicplayer/mainwindow.cpp b/examples/phonon/qmusicplayer/mainwindow.cpp new file mode 100644 index 0000000..787ae53 --- /dev/null +++ b/examples/phonon/qmusicplayer/mainwindow.cpp @@ -0,0 +1,355 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** 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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +***************************************************************************/ + +#include + +#include "mainwindow.h" + +//![0] +MainWindow::MainWindow() +{ + audioOutput = new Phonon::AudioOutput(Phonon::MusicCategory, this); + mediaObject = new Phonon::MediaObject(this); + metaInformationResolver = new Phonon::MediaObject(this); + + mediaObject->setTickInterval(1000); +//![0] +//![2] + connect(mediaObject, SIGNAL(tick(qint64)), this, SLOT(tick(qint64))); + connect(mediaObject, SIGNAL(stateChanged(Phonon::State, Phonon::State)), + this, SLOT(stateChanged(Phonon::State, Phonon::State))); + connect(metaInformationResolver, SIGNAL(stateChanged(Phonon::State,Phonon::State)), + this, SLOT(metaStateChanged(Phonon::State, Phonon::State))); + connect(mediaObject, SIGNAL(currentSourceChanged(const Phonon::MediaSource &)), + this, SLOT(sourceChanged(const Phonon::MediaSource &))); + connect(mediaObject, SIGNAL(aboutToFinish()), this, SLOT(aboutToFinish())); +//![2] + +//![1] + Phonon::createPath(mediaObject, audioOutput); +//![1] + + setupActions(); + setupMenus(); + setupUi(); + timeLcd->display("00:00"); +} + +//![6] +void MainWindow::addFiles() +{ + QStringList files = QFileDialog::getOpenFileNames(this, tr("Select Music Files"), + QDesktopServices::storageLocation(QDesktopServices::MusicLocation)); + + if (files.isEmpty()) + return; + + int index = sources.size(); + foreach (QString string, files) { + Phonon::MediaSource source(string); + + sources.append(source); + } + if (!sources.isEmpty()) + metaInformationResolver->setCurrentSource(sources.at(index)); + +} +//![6] + +void MainWindow::about() +{ + QMessageBox::information(this, tr("About Music Player"), + tr("The Music Player example shows how to use Phonon - the multimedia" + " framework that comes with Qt - to create a simple music player.")); +} + +//![9] +void MainWindow::stateChanged(Phonon::State newState, Phonon::State /* oldState */) +{ + switch (newState) { + case Phonon::ErrorState: + if (mediaObject->errorType() == Phonon::FatalError) { + QMessageBox::warning(this, tr("Fatal Error"), + mediaObject->errorString()); + } else { + QMessageBox::warning(this, tr("Error"), + mediaObject->errorString()); + } + break; +//![9] +//![10] + case Phonon::PlayingState: + playAction->setEnabled(false); + pauseAction->setEnabled(true); + stopAction->setEnabled(true); + break; + case Phonon::StoppedState: + stopAction->setEnabled(false); + playAction->setEnabled(true); + pauseAction->setEnabled(false); + timeLcd->display("00:00"); + break; + case Phonon::PausedState: + pauseAction->setEnabled(false); + stopAction->setEnabled(true); + playAction->setEnabled(true); + break; +//![10] + case Phonon::BufferingState: + break; + default: + ; + } +} + +//![11] +void MainWindow::tick(qint64 time) +{ + QTime displayTime(0, (time / 60000) % 60, (time / 1000) % 60); + + timeLcd->display(displayTime.toString("mm:ss")); +} +//![11] + +//![12] +void MainWindow::tableClicked(int row, int /* column */) +{ + bool wasPlaying = mediaObject->state() == Phonon::PlayingState; + + mediaObject->stop(); + mediaObject->clearQueue(); + + if (row >= sources.size()) + return; + + mediaObject->setCurrentSource(sources[row]); + + if (wasPlaying) + mediaObject->play(); + else + mediaObject->stop(); +} +//![12] + +//![13] +void MainWindow::sourceChanged(const Phonon::MediaSource &source) +{ + musicTable->selectRow(sources.indexOf(source)); + timeLcd->display("00:00"); +} +//![13] + +//![14] +void MainWindow::metaStateChanged(Phonon::State newState, Phonon::State /* oldState */) +{ + if (newState == Phonon::ErrorState) { + QMessageBox::warning(this, tr("Error opening files"), + metaInformationResolver->errorString()); + while (!sources.isEmpty() && + !(sources.takeLast() == metaInformationResolver->currentSource())) {} /* loop */; + return; + } + + if (newState != Phonon::StoppedState && newState != Phonon::PausedState) + return; + + if (metaInformationResolver->currentSource().type() == Phonon::MediaSource::Invalid) + return; + + QMap metaData = metaInformationResolver->metaData(); + + QString title = metaData.value("TITLE"); + if (title == "") + title = metaInformationResolver->currentSource().fileName(); + + QTableWidgetItem *titleItem = new QTableWidgetItem(title); + titleItem->setFlags(titleItem->flags() ^ Qt::ItemIsEditable); + QTableWidgetItem *artistItem = new QTableWidgetItem(metaData.value("ARTIST")); + artistItem->setFlags(artistItem->flags() ^ Qt::ItemIsEditable); + QTableWidgetItem *albumItem = new QTableWidgetItem(metaData.value("ALBUM")); + albumItem->setFlags(albumItem->flags() ^ Qt::ItemIsEditable); + QTableWidgetItem *yearItem = new QTableWidgetItem(metaData.value("DATE")); + yearItem->setFlags(yearItem->flags() ^ Qt::ItemIsEditable); +//![14] + + int currentRow = musicTable->rowCount(); + musicTable->insertRow(currentRow); + musicTable->setItem(currentRow, 0, titleItem); + musicTable->setItem(currentRow, 1, artistItem); + musicTable->setItem(currentRow, 2, albumItem); + musicTable->setItem(currentRow, 3, yearItem); + +//![15] + if (musicTable->selectedItems().isEmpty()) { + musicTable->selectRow(0); + mediaObject->setCurrentSource(metaInformationResolver->currentSource()); + } + + Phonon::MediaSource source = metaInformationResolver->currentSource(); + int index = sources.indexOf(metaInformationResolver->currentSource()) + 1; + if (sources.size() > index) { + metaInformationResolver->setCurrentSource(sources.at(index)); + } + else { + musicTable->resizeColumnsToContents(); + if (musicTable->columnWidth(0) > 300) + musicTable->setColumnWidth(0, 300); + } +} +//![15] + +//![16] +void MainWindow::aboutToFinish() +{ + int index = sources.indexOf(mediaObject->currentSource()) + 1; + if (sources.size() > index) { + mediaObject->enqueue(sources.at(index)); + } +} +//![16] + +void MainWindow::setupActions() +{ + playAction = new QAction(style()->standardIcon(QStyle::SP_MediaPlay), tr("Play"), this); + playAction->setShortcut(tr("Crl+P")); + playAction->setDisabled(true); + pauseAction = new QAction(style()->standardIcon(QStyle::SP_MediaPause), tr("Pause"), this); + pauseAction->setShortcut(tr("Ctrl+A")); + pauseAction->setDisabled(true); + stopAction = new QAction(style()->standardIcon(QStyle::SP_MediaStop), tr("Stop"), this); + stopAction->setShortcut(tr("Ctrl+S")); + stopAction->setDisabled(true); + nextAction = new QAction(style()->standardIcon(QStyle::SP_MediaSkipForward), tr("Next"), this); + nextAction->setShortcut(tr("Ctrl+N")); + previousAction = new QAction(style()->standardIcon(QStyle::SP_MediaSkipBackward), tr("Previous"), this); + previousAction->setShortcut(tr("Ctrl+R")); + addFilesAction = new QAction(tr("Add &Files"), this); + addFilesAction->setShortcut(tr("Ctrl+F")); + exitAction = new QAction(tr("E&xit"), this); + exitAction->setShortcuts(QKeySequence::Quit); + aboutAction = new QAction(tr("A&bout"), this); + aboutAction->setShortcut(tr("Ctrl+B")); + aboutQtAction = new QAction(tr("About &Qt"), this); + aboutQtAction->setShortcut(tr("Ctrl+Q")); + +//![5] + connect(playAction, SIGNAL(triggered()), mediaObject, SLOT(play())); + connect(pauseAction, SIGNAL(triggered()), mediaObject, SLOT(pause()) ); + connect(stopAction, SIGNAL(triggered()), mediaObject, SLOT(stop())); +//![5] + connect(addFilesAction, SIGNAL(triggered()), this, SLOT(addFiles())); + connect(exitAction, SIGNAL(triggered()), this, SLOT(close())); + connect(aboutAction, SIGNAL(triggered()), this, SLOT(about())); + connect(aboutQtAction, SIGNAL(triggered()), qApp, SLOT(aboutQt())); +} + +void MainWindow::setupMenus() +{ + QMenu *fileMenu = menuBar()->addMenu(tr("&File")); + fileMenu->addAction(addFilesAction); + fileMenu->addSeparator(); + fileMenu->addAction(exitAction); + + QMenu *aboutMenu = menuBar()->addMenu(tr("&Help")); + aboutMenu->addAction(aboutAction); + aboutMenu->addAction(aboutQtAction); +} + +//![3] +void MainWindow::setupUi() +{ +//![3] + QToolBar *bar = new QToolBar; + + bar->addAction(playAction); + bar->addAction(pauseAction); + bar->addAction(stopAction); + +//![4] + seekSlider = new Phonon::SeekSlider(this); + seekSlider->setMediaObject(mediaObject); + + volumeSlider = new Phonon::VolumeSlider(this); + volumeSlider->setAudioOutput(audioOutput); +//![4] + volumeSlider->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum); + + QLabel *volumeLabel = new QLabel; + volumeLabel->setPixmap(QPixmap("images/volume.png")); + + QPalette palette; + palette.setBrush(QPalette::Light, Qt::darkGray); + + timeLcd = new QLCDNumber; + timeLcd->setPalette(palette); + + QStringList headers; + headers << tr("Title") << tr("Artist") << tr("Album") << tr("Year"); + + musicTable = new QTableWidget(0, 4); + musicTable->setHorizontalHeaderLabels(headers); + musicTable->setSelectionMode(QAbstractItemView::SingleSelection); + musicTable->setSelectionBehavior(QAbstractItemView::SelectRows); + connect(musicTable, SIGNAL(cellPressed(int, int)), + this, SLOT(tableClicked(int, int))); + + QHBoxLayout *seekerLayout = new QHBoxLayout; + seekerLayout->addWidget(seekSlider); + seekerLayout->addWidget(timeLcd); + + QHBoxLayout *playbackLayout = new QHBoxLayout; + playbackLayout->addWidget(bar); + playbackLayout->addStretch(); + playbackLayout->addWidget(volumeLabel); + playbackLayout->addWidget(volumeSlider); + + QVBoxLayout *mainLayout = new QVBoxLayout; + mainLayout->addWidget(musicTable); + mainLayout->addLayout(seekerLayout); + mainLayout->addLayout(playbackLayout); + + QWidget *widget = new QWidget; + widget->setLayout(mainLayout); + + setCentralWidget(widget); + setWindowTitle("Phonon Music Player"); +} + diff --git a/examples/phonon/qmusicplayer/mainwindow.h b/examples/phonon/qmusicplayer/mainwindow.h new file mode 100644 index 0000000..41f8147 --- /dev/null +++ b/examples/phonon/qmusicplayer/mainwindow.h @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** 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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE +class QAction; +class QTableWidget; +class QLCDNumber; +QT_END_NAMESPACE + +//![0] + +class MainWindow : public QMainWindow +{ +//![0] + Q_OBJECT + +public: + MainWindow(); + + QSize sizeHint() const { + return QSize(500, 300); + } + +private slots: + void addFiles(); + void about(); +//![1] + void stateChanged(Phonon::State newState, Phonon::State oldState); + void tick(qint64 time); + void sourceChanged(const Phonon::MediaSource &source); + void metaStateChanged(Phonon::State newState, Phonon::State oldState); + void aboutToFinish(); + void tableClicked(int row, int column); +//![1] + +private: + void setupActions(); + void setupMenus(); + void setupUi(); + +//![2] + Phonon::SeekSlider *seekSlider; + Phonon::MediaObject *mediaObject; + Phonon::MediaObject *metaInformationResolver; + Phonon::AudioOutput *audioOutput; + Phonon::VolumeSlider *volumeSlider; + QList sources; +//![2] + + QAction *playAction; + QAction *pauseAction; + QAction *stopAction; + QAction *nextAction; + QAction *previousAction; + QAction *addFilesAction; + QAction *exitAction; + QAction *aboutAction; + QAction *aboutQtAction; + QLCDNumber *timeLcd; + QTableWidget *musicTable; +}; + +#endif diff --git a/examples/phonon/qmusicplayer/qmusicplayer.pro b/examples/phonon/qmusicplayer/qmusicplayer.pro new file mode 100644 index 0000000..25ab7eb --- /dev/null +++ b/examples/phonon/qmusicplayer/qmusicplayer.pro @@ -0,0 +1,17 @@ +QT += phonon + +HEADERS += mainwindow.h +SOURCES += main.cpp \ + mainwindow.cpp + +# install +target.path = $$[QT_INSTALL_EXAMPLES]/phonon/qmusicplayer +sources.files = $$SOURCES $$HEADERS $$FORMS $$RESOURCES *.pro *.png images +sources.path = $$[QT_INSTALL_EXAMPLES]/phonon/qmusicplayer +INSTALLS += target sources + +wince*{ +DEPLOYMENT_PLUGIN += phonon_ds9 phonon_waveout +} + +symbian:TARGET.UID3 = 0xA000CF6A -- cgit v0.12 From d66df793b88f9ba924a1fefcec325d7c04af3ac3 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Fri, 9 Oct 2009 15:11:26 +0300 Subject: Fixed miscellaneous minor problems with Symbian docs. Reviewed-by: Espen Riskedal --- doc/src/howtos/exceptionsafety.qdoc | 8 ++++---- doc/src/platforms/platform-notes.qdoc | 4 +++- doc/src/platforms/s60-introduction.qdoc | 4 ++-- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/doc/src/howtos/exceptionsafety.qdoc b/doc/src/howtos/exceptionsafety.qdoc index 23bedf5..fa1427b 100644 --- a/doc/src/howtos/exceptionsafety.qdoc +++ b/doc/src/howtos/exceptionsafety.qdoc @@ -144,12 +144,12 @@ \section1 Platform-Specific Exception Handling - \section2 Symbian (Qt for S60) + \section2 The Symbian platform The Symbian platform implements its own exception system that differs from the standard - C++ mechanism. When using Qt for S60, and especially when writing code to access Symbian - functionality directly, it may be necessary to know about the underlying implementation - and how it interacts with Qt. + C++ mechanism. When using Qt for Symbian platform, and especially when writing code to + access Symbian functionality directly, it may be necessary to know about the underlying + implementation and how it interacts with Qt. The \l{Exception Safety with Symbian} document shows how to use the facilities provided by Qt to use exceptions as safely as possible. diff --git a/doc/src/platforms/platform-notes.qdoc b/doc/src/platforms/platform-notes.qdoc index 5be66f8..9896b08 100644 --- a/doc/src/platforms/platform-notes.qdoc +++ b/doc/src/platforms/platform-notes.qdoc @@ -67,6 +67,8 @@ \tableofcontents{1 Platform Notes - Windows} \o \l{Platform Notes - Mac OS X} \tableofcontents{1 Platform Notes - Mac OS X} + \o \l{Platform Notes - Symbian} + \tableofcontents{1 Platform Notes - Symbian} \o \l{Platform Notes - Embedded Linux} \tableofcontents{1 Platform Notes - Embedded Linux} \o \l{Platform Notes - Windows CE} @@ -409,7 +411,7 @@ to run on. More information about the combinations of platforms and compilers supported by Qt can be found on the \l{Supported Platforms} page. - For information about mixing exceptions with symbian leaves, + For information about mixing exceptions with Symbian leaves, see \l{Exception Safety with Symbian} \section1 Multimedia and Phonon Support diff --git a/doc/src/platforms/s60-introduction.qdoc b/doc/src/platforms/s60-introduction.qdoc index d145a82..d27eb39 100644 --- a/doc/src/platforms/s60-introduction.qdoc +++ b/doc/src/platforms/s60-introduction.qdoc @@ -122,8 +122,8 @@ build targets, as shown in the table below: \row \o \c QT_SIS_OPTIONS \o Options accepted by \c .sis creation. -i, install the package right away using PC suite. -c=, read certificate information from a file. - Execute \c{perl createpackage.pl} for more information - about options. + Execute \c{createpackage.pl} script without any + parameters for more information about options. By default no otions are given. \row \o \c QT_SIS_TARGET \o Target for which \c .sis file is created. Accepted values are build targets listed in -- cgit v0.12