diff options
Diffstat (limited to 'src')
38 files changed, 651 insertions, 289 deletions
diff --git a/src/3rdparty/phonon/ds9/qpin.cpp b/src/3rdparty/phonon/ds9/qpin.cpp index 3762a90..68a4ec0 100644 --- a/src/3rdparty/phonon/ds9/qpin.cpp +++ b/src/3rdparty/phonon/ds9/qpin.cpp @@ -303,9 +303,7 @@ namespace Phonon setConnected(0); setConnectedType(defaultMediaType); - if (m_direction == PINDIR_INPUT) { - setMemoryAllocator(0); - } + setMemoryAllocator(0); return S_OK; } diff --git a/src/corelib/animation/qabstractanimation.cpp b/src/corelib/animation/qabstractanimation.cpp index 75decf8..cf3e62d 100644 --- a/src/corelib/animation/qabstractanimation.cpp +++ b/src/corelib/animation/qabstractanimation.cpp @@ -620,8 +620,8 @@ void QAbstractAnimation::start(DeletionPolicy policy) Q_D(QAbstractAnimation); if (d->state == Running) return; - d->setState(Running); d->deleteWhenStopped = policy; + d->setState(Running); } /*! diff --git a/src/corelib/global/qnamespace.h b/src/corelib/global/qnamespace.h index 077e4ef..7770fd6 100644 --- a/src/corelib/global/qnamespace.h +++ b/src/corelib/global/qnamespace.h @@ -1411,7 +1411,7 @@ public: ToolButtonTextOnly, ToolButtonTextBesideIcon, ToolButtonTextUnderIcon, - ToolButtonSystemDefault + ToolButtonFollowStyle }; enum LayoutDirection { diff --git a/src/corelib/kernel/qcoreevent.cpp b/src/corelib/kernel/qcoreevent.cpp index c636716..a682fad9 100644 --- a/src/corelib/kernel/qcoreevent.cpp +++ b/src/corelib/kernel/qcoreevent.cpp @@ -219,6 +219,7 @@ QT_BEGIN_NAMESPACE \value WindowStateChange The \l{QWidget::windowState()}{window's state} (minimized, maximized or full-screen) has changed (QWindowStateChangeEvent). \value WindowTitleChange The window title has changed. \value WindowUnblocked The window is unblocked after a modal dialog exited. + \value Wrapped The event is a wrapper for, i.e., contains, another event (QWrappedEvent). \value ZOrderChange The widget's z-order has changed. This event is never sent to top level windows. \value KeyboardLayoutChange The keyboard layout has changed. \value DynamicPropertyChange A dynamic property was added, changed or removed from the object. @@ -267,7 +268,6 @@ QT_BEGIN_NAMESPACE \omitvalue NetworkReplyUpdated \omitvalue FutureCallOut \omitvalue CocoaRequestModal - \omitvalue Wrapped \omitvalue Signal \omitvalue WinGesture */ diff --git a/src/corelib/statemachine/qabstracttransition.cpp b/src/corelib/statemachine/qabstracttransition.cpp index 670aa7d..c040c58 100644 --- a/src/corelib/statemachine/qabstracttransition.cpp +++ b/src/corelib/statemachine/qabstracttransition.cpp @@ -330,6 +330,18 @@ QList<QAbstractAnimation*> QAbstractTransition::animations() const This function is called to determine whether the given \a event should cause this transition to trigger. Reimplement this function and return true if the event should trigger the transition, otherwise return false. + + + Note that \a event is a QWrappedEvent, which contains a clone of + the event generated by Qt. For instance, if you want to check a + key press event, do the following: + + \snippet doc/src/snippets/statemachine/eventtest.cpp 0 + + You need to check if \a event is a QWrappedEvent because Qt also + uses other events for internal reasons; you don't need to concern + yourself with these in any case. + */ /*! diff --git a/src/corelib/tools/qbytedata_p.h b/src/corelib/tools/qbytedata_p.h new file mode 100644 index 0000000..e8a4ddd --- /dev/null +++ b/src/corelib/tools/qbytedata_p.h @@ -0,0 +1,200 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QBYTEDATA_H +#define QBYTEDATA_H + +#include <qbytearray.h> + + +// this class handles a list of QByteArrays. It is a variant of QRingBuffer +// that avoid malloc/realloc/memcpy. +class QByteDataBuffer +{ +private: + QList<QByteArray> buffers; + qint64 bufferCompleteSize; +public: + QByteDataBuffer() : bufferCompleteSize(0) + { + } + + ~QByteDataBuffer() + { + clear(); + } + + inline void append(QByteDataBuffer& other) + { + if (other.isEmpty()) + return; + + buffers.append(other.buffers); + bufferCompleteSize += other.byteAmount(); + } + + + inline void append(QByteArray& bd) + { + if (bd.isEmpty()) + return; + + buffers.append(bd); + bufferCompleteSize += bd.size(); + } + + inline void prepend(QByteArray& bd) + { + if (bd.isEmpty()) + return; + + buffers.prepend(bd); + bufferCompleteSize += bd.size(); + } + + // return the first QByteData. User of this function has to qFree() its .data! + // preferably use this function to read data. + inline QByteArray read() + { + bufferCompleteSize -= buffers.first().size(); + return buffers.takeFirst(); + } + + // return everything. User of this function has to qFree() its .data! + // avoid to use this, it might malloc and memcpy. + inline QByteArray readAll() + { + return read(byteAmount()); + } + + // return amount. User of this function has to qFree() its .data! + // avoid to use this, it might malloc and memcpy. + inline QByteArray read(qint64 amount) + { + amount = qMin(byteAmount(), amount); + QByteArray byteData; + byteData.resize(amount); + read(byteData.data(), byteData.size()); + return byteData; + } + + // return amount bytes. User of this function has to qFree() its .data! + // avoid to use this, it will memcpy. + qint64 read(char* dst, qint64 amount) + { + amount = qMin(amount, byteAmount()); + qint64 originalAmount = amount; + char *writeDst = dst; + + while (amount > 0) { + QByteArray first = buffers.takeFirst(); + if (amount >= first.size()) { + // take it completely + bufferCompleteSize -= first.size(); + amount -= first.size(); + memcpy(writeDst, first.constData(), first.size()); + writeDst += first.size(); + first.clear(); + } else { + // take a part of it & it is the last one to take + bufferCompleteSize -= amount; + memcpy(writeDst, first.constData(), amount); + + qint64 newFirstSize = first.size() - amount; + QByteArray newFirstData; + newFirstData.resize(newFirstSize); + memcpy(newFirstData.data(), first.constData() + amount, newFirstSize); + buffers.prepend(newFirstData); + + amount = 0; + first.clear(); + } + } + + return originalAmount; + } + + inline char getChar() + { + char c; + read(&c, 1); + return c; + } + + inline void clear() + { + buffers.clear(); + bufferCompleteSize = 0; + } + + // The byte count of all QByteArrays + inline qint64 byteAmount() const + { + return bufferCompleteSize; + } + + // the number of QByteArrays + inline qint64 bufferCount() const + { + return buffers.length(); + } + + inline bool isEmpty() const + { + return byteAmount() == 0; + } + + inline qint64 sizeNextBlock() const + { + if(buffers.isEmpty()) + return 0; + else + return buffers.first().size(); + } + + inline QByteArray& operator[](int i) + { + return buffers[i]; + } +}; + + +#endif // QBYTEDATA_H diff --git a/src/corelib/tools/tools.pri b/src/corelib/tools/tools.pri index c93a065..08c94ac 100644 --- a/src/corelib/tools/tools.pri +++ b/src/corelib/tools/tools.pri @@ -5,6 +5,7 @@ HEADERS += \ tools/qbitarray.h \ tools/qbytearray.h \ tools/qbytearraymatcher.h \ + tools/qbytedata_p.h \ tools/qcache.h \ tools/qchar.h \ tools/qcontainerfwd.h \ diff --git a/src/gui/image/qpixmap_mac.cpp b/src/gui/image/qpixmap_mac.cpp index c281fe9..25ef8ba 100644 --- a/src/gui/image/qpixmap_mac.cpp +++ b/src/gui/image/qpixmap_mac.cpp @@ -1169,25 +1169,6 @@ IconRef qt_mac_create_iconref(const QPixmap &px) } #endif -QPixmap qt_mac_convert_iconref(const IconRef icon, int width, int height) -{ - QPixmap ret(width, height); - ret.fill(QColor(0, 0, 0, 0)); - - CGRect rect = CGRectMake(0, 0, width, height); - - CGContextRef ctx = qt_mac_cg_context(&ret); - CGAffineTransform old_xform = CGContextGetCTM(ctx); - CGContextConcatCTM(ctx, CGAffineTransformInvert(old_xform)); - CGContextConcatCTM(ctx, CGAffineTransformIdentity); - - ::RGBColor b; - b.blue = b.green = b.red = 255*255; - PlotIconRefInContext(ctx, &rect, kAlignNone, kTransformNone, &b, kPlotIconRefNormalFlags, icon); - CGContextRelease(ctx); - return ret; -} - /*! \internal */ QPaintEngine* QMacPixmapData::paintEngine() const { diff --git a/src/gui/itemviews/qfileiconprovider.cpp b/src/gui/itemviews/qfileiconprovider.cpp index 1856f4d..53608e7 100644 --- a/src/gui/itemviews/qfileiconprovider.cpp +++ b/src/gui/itemviews/qfileiconprovider.cpp @@ -53,7 +53,7 @@ #include <private/qpixmapdata_p.h> #include <qpixmapcache.h> #elif defined(Q_WS_MAC) -#include <private/qt_mac_p.h> +#include <private/qt_cocoa_helpers_mac_p.h> #endif #include <private/qfunctions_p.h> @@ -326,10 +326,11 @@ QIcon QFileIconProviderPrivate::getMacIcon(const QFileInfo &fi) const return retIcon; IconRef iconRef; SInt16 iconLabel; - status = GetIconRefFromFileInfo(&macRef, macName.length, macName.unicode, kIconServicesCatalogInfoMask, &info, kIconServicesNormalUsageFlag, &iconRef, &iconLabel); + status = GetIconRefFromFileInfo(&macRef, macName.length, macName.unicode, + kIconServicesCatalogInfoMask, &info, kIconServicesNormalUsageFlag, + &iconRef, &iconLabel); if (status != noErr) return retIcon; - extern void qt_mac_constructQIconFromIconRef(const IconRef, const IconRef, QIcon*, QStyle::StandardPixmap = QStyle::SP_CustomBase); // qmacstyle_mac.cpp qt_mac_constructQIconFromIconRef(iconRef, 0, &retIcon); ReleaseIconRef(iconRef); return retIcon; diff --git a/src/gui/itemviews/qitemdelegate.cpp b/src/gui/itemviews/qitemdelegate.cpp index a285113..336ca79 100644 --- a/src/gui/itemviews/qitemdelegate.cpp +++ b/src/gui/itemviews/qitemdelegate.cpp @@ -861,6 +861,8 @@ void QItemDelegate::drawBackground(QPainter *painter, /*! \internal + + Code duplicated in QCommonStylePrivate::viewItemLayout */ void QItemDelegate::doLayout(const QStyleOptionViewItem &option, @@ -882,8 +884,10 @@ void QItemDelegate::doLayout(const QStyleOptionViewItem &option, int w, h; textRect->adjust(-textMargin, 0, textMargin, 0); // add width padding - if (textRect->height() == 0 && !hasPixmap) + if (textRect->height() == 0 && (!hasPixmap || !hint)) { + //if there is no text, we still want to have a decent height for the item sizeHint and the editor size textRect->setHeight(option.fontMetrics.height()); + } QSize pm(0, 0); if (hasPixmap) { diff --git a/src/gui/itemviews/qsortfilterproxymodel.cpp b/src/gui/itemviews/qsortfilterproxymodel.cpp index 30a8c96..fdc09ca 100644 --- a/src/gui/itemviews/qsortfilterproxymodel.cpp +++ b/src/gui/itemviews/qsortfilterproxymodel.cpp @@ -146,6 +146,7 @@ public: const QModelIndex &source_parent) const; QModelIndex proxy_to_source(const QModelIndex &proxyIndex) const; QModelIndex source_to_proxy(const QModelIndex &sourceIndex) const; + bool can_create_mapping(const QModelIndex &source_parent) const; void remove_from_mapping(const QModelIndex &source_parent); @@ -354,6 +355,25 @@ QModelIndex QSortFilterProxyModelPrivate::source_to_proxy(const QModelIndex &sou return create_index(proxy_row, proxy_column, it); } +bool QSortFilterProxyModelPrivate::can_create_mapping(const QModelIndex &source_parent) const +{ + if (source_parent.isValid()) { + QModelIndex source_grand_parent = source_parent.parent(); + IndexMap::const_iterator it = source_index_mapping.constFind(source_grand_parent); + if (it == source_index_mapping.constEnd()) { + // Don't care, since we don't have mapping for the grand parent + return false; + } + Mapping *gm = it.value(); + if (gm->proxy_rows.at(source_parent.row()) == -1 || + gm->proxy_columns.at(source_parent.column()) == -1) { + // Don't care, since parent is filtered + return false; + } + } + return true; +} + /*! \internal @@ -659,20 +679,8 @@ void QSortFilterProxyModelPrivate::source_items_inserted( return; IndexMap::const_iterator it = source_index_mapping.constFind(source_parent); if (it == source_index_mapping.constEnd()) { - if (source_parent.isValid()) { - QModelIndex source_grand_parent = source_parent.parent(); - it = source_index_mapping.constFind(source_grand_parent); - if (it == source_index_mapping.constEnd()) { - // Don't care, since we don't have mapping for the grand parent - return; - } - Mapping *gm = it.value(); - if (gm->proxy_rows.at(source_parent.row()) == -1 || - gm->proxy_columns.at(source_parent.column()) == -1) { - // Don't care, since parent is filtered - return; - } - } + if (!can_create_mapping(source_parent)) + return; it = create_mapping(source_parent); Mapping *m = it.value(); QModelIndex proxy_parent = q->mapFromSource(source_parent); @@ -1186,7 +1194,8 @@ void QSortFilterProxyModelPrivate::_q_sourceRowsAboutToBeInserted( Q_UNUSED(end); //Force the creation of a mapping now, even if its empty. //We need it because the proxy can be acessed at the moment it emits rowsAboutToBeInserted in insert_source_items - create_mapping(source_parent); + if (can_create_mapping(source_parent)) + create_mapping(source_parent); } void QSortFilterProxyModelPrivate::_q_sourceRowsInserted( @@ -1217,7 +1226,8 @@ void QSortFilterProxyModelPrivate::_q_sourceColumnsAboutToBeInserted( Q_UNUSED(end); //Force the creation of a mapping now, even if its empty. //We need it because the proxy can be acessed at the moment it emits columnsAboutToBeInserted in insert_source_items - create_mapping(source_parent); + if (can_create_mapping(source_parent)) + create_mapping(source_parent); } void QSortFilterProxyModelPrivate::_q_sourceColumnsInserted( diff --git a/src/gui/kernel/qaction.cpp b/src/gui/kernel/qaction.cpp index 4ee17f4..09ba6cc 100644 --- a/src/gui/kernel/qaction.cpp +++ b/src/gui/kernel/qaction.cpp @@ -81,7 +81,7 @@ static QString qt_strippedText(QString s) QActionPrivate::QActionPrivate() : group(0), enabled(1), forceDisabled(0), visible(1), forceInvisible(0), checkable(0), checked(0), separator(0), fontSet(false), - menuRole(QAction::TextHeuristicRole), iconVisibleInMenu(-1) + menuRole(QAction::TextHeuristicRole), priority(QAction::NormalPriority), iconVisibleInMenu(-1) { #ifdef QT3_SUPPORT static int qt_static_action_id = -1; @@ -909,6 +909,31 @@ QString QAction::whatsThis() const return d->whatsthis; } +/*! + \property QAction::priority + \since 4.6 + + \brief tells collapsible layouts how the action should be prioritized + + This property can be set to indicate that an action should be prioritied + in a layout. For instance when toolbars have the Qt::ToolButtonTextBesideIcon + mode is set, lower priority actions will hide text labels to preserve space. +*/ +void QAction::setPriority(Priority priority) +{ + Q_D(QAction); + if (d->priority == priority) + return; + + d->priority = priority; + d->sendDataChanged(); +} + +QAction::Priority QAction::priority() const +{ + Q_D(const QAction); + return d->priority; +} /*! \property QAction::checkable diff --git a/src/gui/kernel/qaction.h b/src/gui/kernel/qaction.h index 6920ec5..133fab4 100644 --- a/src/gui/kernel/qaction.h +++ b/src/gui/kernel/qaction.h @@ -67,6 +67,7 @@ class Q_GUI_EXPORT QAction : public QObject Q_DECLARE_PRIVATE(QAction) Q_ENUMS(MenuRole) + Q_ENUMS(Priority) Q_PROPERTY(bool checkable READ isCheckable WRITE setCheckable) Q_PROPERTY(bool checked READ isChecked WRITE setChecked DESIGNABLE isCheckable NOTIFY toggled) Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled) @@ -85,10 +86,14 @@ class Q_GUI_EXPORT QAction : public QObject Q_PROPERTY(bool visible READ isVisible WRITE setVisible) Q_PROPERTY(MenuRole menuRole READ menuRole WRITE setMenuRole) Q_PROPERTY(bool iconVisibleInMenu READ isIconVisibleInMenu WRITE setIconVisibleInMenu) + Q_PROPERTY(Priority priority READ priority WRITE setPriority) public: enum MenuRole { NoRole, TextHeuristicRole, ApplicationSpecificRole, AboutQtRole, AboutRole, PreferencesRole, QuitRole }; + enum Priority { LowPriority = 0, + NormalPriority = 128, + HighPriority = 256}; explicit QAction(QObject* parent); QAction(const QString &text, QObject* parent); QAction(const QIcon &icon, const QString &text, QObject* parent); @@ -123,6 +128,9 @@ public: void setWhatsThis(const QString &what); QString whatsThis() const; + void setPriority(Priority priority); + Priority priority() const; + #ifndef QT_NO_MENU QMenu *menu() const; void setMenu(QMenu *menu); diff --git a/src/gui/kernel/qaction_p.h b/src/gui/kernel/qaction_p.h index bae9bbf..4745ed1 100644 --- a/src/gui/kernel/qaction_p.h +++ b/src/gui/kernel/qaction_p.h @@ -102,6 +102,7 @@ public: uint separator : 1; uint fontSet : 1; QAction::MenuRole menuRole; + QAction::Priority priority; int iconVisibleInMenu : 3; // Only has values -1, 0, and 1 QList<QWidget *> widgets; #ifndef QT_NO_GRAPHICSVIEW diff --git a/src/gui/kernel/qapplication_x11.cpp b/src/gui/kernel/qapplication_x11.cpp index a07ccdd..76138f8 100644 --- a/src/gui/kernel/qapplication_x11.cpp +++ b/src/gui/kernel/qapplication_x11.cpp @@ -1396,6 +1396,18 @@ static void qt_set_x11_resources(const char* font = 0, const char* fg = 0, color = kdeColor(QLatin1String("Colors:Button/ForegroundNormal"), theKdeSettings); if (color.isValid()) pal.setColor(QPalette::ButtonText, color); + + color = kdeColor(QLatin1String("linkColor"), theKdeSettings); + if (!color.isValid()) + color = kdeColor(QLatin1String("Colors:View/ForegroundLink"), theKdeSettings); + if (color.isValid()) + pal.setColor(QPalette::Link, color); + + color = kdeColor(QLatin1String("visitedLinkColor"), theKdeSettings); + if (!color.isValid()) + color = kdeColor(QLatin1String("Colors:View/ForegroundVisited"), theKdeSettings); + if (color.isValid()) + pal.setColor(QPalette::LinkVisited, color); } if (highlight.isValid() && highlightText.isValid()) { diff --git a/src/gui/kernel/qdesktopwidget_mac.mm b/src/gui/kernel/qdesktopwidget_mac.mm index 7dd74da..11aa7cf 100644 --- a/src/gui/kernel/qdesktopwidget_mac.mm +++ b/src/gui/kernel/qdesktopwidget_mac.mm @@ -233,8 +233,8 @@ void QDesktopWidget::resizeEvent(QResizeEvent *) QDesktopWidgetImplementation *d = qdesktopWidgetImplementation(); const int oldScreenCount = d->screenCount; - const QVector<QRect> oldRects(d->screenRects); - const QVector<QRect> oldWorks(d->availableRects); + const QVector<QRectF> oldRects(d->screenRects); + const QVector<QRectF> oldWorks(d->availableRects); d->onResize(); diff --git a/src/gui/kernel/qt_cocoa_helpers_mac.mm b/src/gui/kernel/qt_cocoa_helpers_mac.mm index a98a7f8..223e36b 100644 --- a/src/gui/kernel/qt_cocoa_helpers_mac.mm +++ b/src/gui/kernel/qt_cocoa_helpers_mac.mm @@ -77,6 +77,7 @@ #include <qwidget.h> #include <qdesktopwidget.h> #include <qevent.h> +#include <qpixmapcache.h> #include <private/qevent_p.h> #include <private/qt_cocoa_helpers_mac_p.h> #include <private/qt_mac_p.h> @@ -1147,4 +1148,49 @@ QString qt_mac_get_pasteboardString() } } +QPixmap qt_mac_convert_iconref(const IconRef icon, int width, int height) +{ + QPixmap ret(width, height); + ret.fill(QColor(0, 0, 0, 0)); + + CGRect rect = CGRectMake(0, 0, width, height); + + CGContextRef ctx = qt_mac_cg_context(&ret); + CGAffineTransform old_xform = CGContextGetCTM(ctx); + CGContextConcatCTM(ctx, CGAffineTransformInvert(old_xform)); + CGContextConcatCTM(ctx, CGAffineTransformIdentity); + + ::RGBColor b; + b.blue = b.green = b.red = 255*255; + PlotIconRefInContext(ctx, &rect, kAlignNone, kTransformNone, &b, kPlotIconRefNormalFlags, icon); + CGContextRelease(ctx); + return ret; +} + +void qt_mac_constructQIconFromIconRef(const IconRef icon, const IconRef overlayIcon, QIcon *retIcon, QStyle::StandardPixmap standardIcon) +{ + int size = 16; + while (size <= 128) { + + const QString cacheKey = QLatin1String("qt_mac_constructQIconFromIconRef") + QString::number(standardIcon) + QString::number(size); + QPixmap mainIcon; + if (standardIcon >= QStyle::SP_CustomBase) { + mainIcon = qt_mac_convert_iconref(icon, size, size); + } else if (QPixmapCache::find(cacheKey, mainIcon) == false) { + mainIcon = qt_mac_convert_iconref(icon, size, size); + QPixmapCache::insert(cacheKey, mainIcon); + } + + if (overlayIcon) { + int littleSize = size / 2; + QPixmap overlayPix = qt_mac_convert_iconref(overlayIcon, littleSize, littleSize); + QPainter painter(&mainIcon); + painter.drawPixmap(size - littleSize, size - littleSize, overlayPix); + } + + retIcon->addPixmap(mainIcon); + size += size; // 16 -> 32 -> 64 -> 128 + } +} + QT_END_NAMESPACE diff --git a/src/gui/kernel/qt_cocoa_helpers_mac_p.h b/src/gui/kernel/qt_cocoa_helpers_mac_p.h index 5f6204f..99f058b 100644 --- a/src/gui/kernel/qt_cocoa_helpers_mac_p.h +++ b/src/gui/kernel/qt_cocoa_helpers_mac_p.h @@ -143,6 +143,9 @@ struct ::TabletProximityRec; void qt_dispatchTabletProximityEvent(const ::TabletProximityRec &proxRec); Qt::KeyboardModifiers qt_cocoaModifiers2QtModifiers(ulong modifierFlags); Qt::KeyboardModifiers qt_cocoaDragOperation2QtModifiers(uint dragOperations); +QPixmap qt_mac_convert_iconref(const IconRef icon, int width, int height); +void qt_mac_constructQIconFromIconRef(const IconRef icon, const IconRef overlayIcon, QIcon *retIcon, + QStyle::StandardPixmap standardIcon = QStyle::SP_CustomBase); inline int flipYCoordinate(int y) { return QApplication::desktop()->screenGeometry(0).height() - y; diff --git a/src/gui/styles/qcommonstyle.cpp b/src/gui/styles/qcommonstyle.cpp index 29176c3..308a0b8 100644 --- a/src/gui/styles/qcommonstyle.cpp +++ b/src/gui/styles/qcommonstyle.cpp @@ -84,6 +84,8 @@ #ifdef Q_WS_X11 # include <private/qt_x11_p.h> +#elif defined(Q_WS_MAC) +# include <private/qt_cocoa_helpers_mac_p.h> #endif QT_BEGIN_NAMESPACE @@ -1182,8 +1184,14 @@ void QCommonStylePrivate::viewItemDrawText(QPainter *p, const QStyleOptionViewIt } } -/* Set sizehint to false to layout the elements inside opt->rect. Set sizehint to true to ignore - opt->rect and return rectangles in infinite space */ +/*! \internal + compute the position for the different component of an item (pixmap, text, checkbox) + + Set sizehint to false to layout the elements inside opt->rect. Set sizehint to true to ignore + opt->rect and return rectangles in infinite space + + Code duplicated in QItemDelegate::doLayout +*/ void QCommonStylePrivate::viewItemLayout(const QStyleOptionViewItemV4 *opt, QRect *checkRect, QRect *pixmapRect, QRect *textRect, bool sizehint) const { @@ -1204,8 +1212,10 @@ void QCommonStylePrivate::viewItemLayout(const QStyleOptionViewItemV4 *opt, QRe int y = opt->rect.top(); int w, h; - if (textRect->height() == 0 && !hasPixmap) + if (textRect->height() == 0 && (!hasPixmap || !sizehint)) { + //if there is no text, we still want to have a decent height for the item sizeHint and the editor size textRect->setHeight(opt->fontMetrics.height()); + } QSize pm(0, 0); if (hasPixmap) { @@ -4868,7 +4878,14 @@ int QCommonStyle::pixelMetric(PixelMetric m, const QStyleOption *opt, const QWid ret = int(QStyleHelper::dpiScaled(13.)); break; case PM_MessageBoxIconSize: - ret = int(QStyleHelper::dpiScaled(32.)); +#ifdef Q_WS_MAC + if (QApplication::desktopSettingsAware()) { + ret = 64; // No DPI scaling, it's handled elsewhere. + } else +#endif + { + ret = int(QStyleHelper::dpiScaled(32.)); + } break; case PM_TextCursorWidth: ret = 1; @@ -5766,9 +5783,9 @@ QIcon QCommonStyle::standardIconImplementation(StandardPixmap standardIcon, cons const QWidget *widget) const { QIcon icon; -#ifdef Q_WS_X11 - Q_D(const QCommonStyle); if (QApplication::desktopSettingsAware()) { +#ifdef Q_WS_X11 + Q_D(const QCommonStyle); d->lookupIconTheme(); QPixmap pixmap; switch (standardIcon) { @@ -5787,6 +5804,7 @@ QIcon QCommonStyle::standardIconImplementation(StandardPixmap standardIcon, cons case SP_MessageBoxWarning: { icon = d->createIcon(QLatin1String("dialog-warning.png")); + icon = d->createIcon(QLatin1String("dialog-warning.png")); if (icon.isNull()) icon = d->createIcon(QLatin1String("messagebox_warning.png")); break; @@ -6012,8 +6030,101 @@ QIcon QCommonStyle::standardIconImplementation(StandardPixmap standardIcon, cons } if (!icon.isNull()) return icon; +#elif defined(Q_WS_MAC) + OSType iconType = 0; + switch (standardIcon) { + case QStyle::SP_MessageBoxQuestion: + case QStyle::SP_MessageBoxInformation: + case QStyle::SP_MessageBoxWarning: + case QStyle::SP_MessageBoxCritical: + iconType = kGenericApplicationIcon; + break; + case SP_DesktopIcon: + iconType = kDesktopIcon; + break; + case SP_TrashIcon: + iconType = kTrashIcon; + break; + case SP_ComputerIcon: + iconType = kComputerIcon; + break; + case SP_DriveFDIcon: + iconType = kGenericFloppyIcon; + break; + case SP_DriveHDIcon: + iconType = kGenericHardDiskIcon; + break; + case SP_DriveCDIcon: + case SP_DriveDVDIcon: + iconType = kGenericCDROMIcon; + break; + case SP_DriveNetIcon: + iconType = kGenericNetworkIcon; + break; + case SP_DirOpenIcon: + iconType = kOpenFolderIcon; + break; + case SP_DirClosedIcon: + case SP_DirLinkIcon: + iconType = kGenericFolderIcon; + break; + case SP_FileLinkIcon: + case SP_FileIcon: + iconType = kGenericDocumentIcon; + break; + case SP_DirIcon: { + // A rather special case + QIcon closeIcon = QStyle::standardIcon(SP_DirClosedIcon, option, widget); + QIcon openIcon = QStyle::standardIcon(SP_DirOpenIcon, option, widget); + closeIcon.addPixmap(openIcon.pixmap(16, 16), QIcon::Normal, QIcon::On); + closeIcon.addPixmap(openIcon.pixmap(32, 32), QIcon::Normal, QIcon::On); + closeIcon.addPixmap(openIcon.pixmap(64, 64), QIcon::Normal, QIcon::On); + closeIcon.addPixmap(openIcon.pixmap(128, 128), QIcon::Normal, QIcon::On); + return closeIcon; + } + case SP_TitleBarNormalButton: + case SP_TitleBarCloseButton: { + QIcon titleBarIcon; + if (standardIcon == SP_TitleBarCloseButton) { + titleBarIcon.addFile(QLatin1String(":/trolltech/styles/macstyle/images/closedock-16.png")); + titleBarIcon.addFile(QLatin1String(":/trolltech/styles/macstyle/images/closedock-down-16.png"), QSize(16, 16), QIcon::Normal, QIcon::On); + } else { + titleBarIcon.addFile(QLatin1String(":/trolltech/styles/macstyle/images/dockdock-16.png")); + titleBarIcon.addFile(QLatin1String(":/trolltech/styles/macstyle/images/dockdock-down-16.png"), QSize(16, 16), QIcon::Normal, QIcon::On); + } + return titleBarIcon; + } + default: + break; + } + if (iconType != 0) { + QIcon retIcon; + IconRef icon; + IconRef overlayIcon = 0; + if (iconType != kGenericApplicationIcon) { + GetIconRef(kOnSystemDisk, kSystemIconsCreator, iconType, &icon); + } else { + FSRef fsRef; + ProcessSerialNumber psn = { 0, kCurrentProcess }; + GetProcessBundleLocation(&psn, &fsRef); + GetIconRefFromFileInfo(&fsRef, 0, 0, 0, 0, kIconServicesNormalUsageFlag, &icon, 0); + if (standardIcon == SP_MessageBoxCritical) { + overlayIcon = icon; + GetIconRef(kOnSystemDisk, kSystemIconsCreator, kAlertCautionIcon, &icon); + } + } + if (icon) { + qt_mac_constructQIconFromIconRef(icon, overlayIcon, &retIcon, standardIcon); + ReleaseIconRef(icon); + } + if (overlayIcon) + ReleaseIconRef(overlayIcon); + return retIcon; } -#endif//Q_WS_X11 + +#endif //Q_WS_X11 || Q_WS_MAC + } + switch (standardIcon) { #ifndef QT_NO_IMAGEFORMAT_PNG diff --git a/src/gui/styles/qmacstyle_mac.mm b/src/gui/styles/qmacstyle_mac.mm index 5d75392..2f93034 100644 --- a/src/gui/styles/qmacstyle_mac.mm +++ b/src/gui/styles/qmacstyle_mac.mm @@ -558,7 +558,6 @@ QT_END_INCLUDE_NAMESPACE External functions *****************************************************************************/ extern CGContextRef qt_mac_cg_context(const QPaintDevice *); //qpaintdevice_mac.cpp -extern QPixmap qt_mac_convert_iconref(const IconRef, int, int); //qpixmap_mac.cpp extern QRegion qt_mac_convert_mac_region(HIShapeRef); //qregion_mac.cpp void qt_mac_dispose_rgn(RgnHandle r); //qregion_mac.cpp extern QPaintDevice *qt_mac_safe_pdev; //qapplication_mac.cpp @@ -2303,9 +2302,6 @@ int QMacStyle::pixelMetric(PixelMetric metric, const QStyleOption *opt, const QW case PM_ToolBarItemSpacing: ret = 4; break; - case PM_MessageBoxIconSize: - ret = 64; - break; case PM_SplitterWidth: ret = qMax(7, QApplication::globalStrut().width()); break; @@ -3361,6 +3357,9 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter } proxy()->drawItemPixmap(p, pr, Qt::AlignCenter, pixmap); break; } + default: + Q_ASSERT(false); + break; } if (needText) { @@ -5855,76 +5854,12 @@ bool QMacStyle::event(QEvent *e) return false; } -void qt_mac_constructQIconFromIconRef(const IconRef icon, const IconRef overlayIcon, QIcon *retIcon, QStyle::StandardPixmap standardIcon = QStyle::SP_CustomBase) -{ - int size = 16; - while (size <= 128) { - - const QString cacheKey = QLatin1String("qt_mac_constructQIconFromIconRef") + QString::number(standardIcon) + QString::number(size); - QPixmap mainIcon; - if (standardIcon >= QStyle::SP_CustomBase) { - mainIcon = qt_mac_convert_iconref(icon, size, size); - } else if (QPixmapCache::find(cacheKey, mainIcon) == false) { - mainIcon = qt_mac_convert_iconref(icon, size, size); - QPixmapCache::insert(cacheKey, mainIcon); - } - - if (overlayIcon) { - int littleSize = size / 2; - QPixmap overlayPix = qt_mac_convert_iconref(overlayIcon, littleSize, littleSize); - QPainter painter(&mainIcon); - painter.drawPixmap(size - littleSize, size - littleSize, overlayPix); - } - - retIcon->addPixmap(mainIcon); - size += size; // 16 -> 32 -> 64 -> 128 - } -} - QIcon QMacStyle::standardIconImplementation(StandardPixmap standardIcon, const QStyleOption *opt, const QWidget *widget) const { - OSType iconType = 0; switch (standardIcon) { - case QStyle::SP_MessageBoxQuestion: - case QStyle::SP_MessageBoxInformation: - case QStyle::SP_MessageBoxWarning: - case QStyle::SP_MessageBoxCritical: - iconType = kGenericApplicationIcon; - break; - case SP_DesktopIcon: - iconType = kDesktopIcon; - break; - case SP_TrashIcon: - iconType = kTrashIcon; - break; - case SP_ComputerIcon: - iconType = kComputerIcon; - break; - case SP_DriveFDIcon: - iconType = kGenericFloppyIcon; - break; - case SP_DriveHDIcon: - iconType = kGenericHardDiskIcon; - break; - case SP_DriveCDIcon: - case SP_DriveDVDIcon: - iconType = kGenericCDROMIcon; - break; - case SP_DriveNetIcon: - iconType = kGenericNetworkIcon; - break; - case SP_DirOpenIcon: - iconType = kOpenFolderIcon; - break; - case SP_DirClosedIcon: - case SP_DirLinkIcon: - iconType = kGenericFolderIcon; - break; - case SP_FileLinkIcon: - case SP_FileIcon: - iconType = kGenericDocumentIcon; - break; + default: + return QWindowsStyle::standardIconImplementation(standardIcon, opt, widget); case SP_ToolBarHorizontalExtensionButton: case SP_ToolBarVerticalExtensionButton: { QPixmap pixmap(qt_mac_toolbar_ext); @@ -5938,58 +5873,8 @@ QIcon QMacStyle::standardIconImplementation(StandardPixmap standardIcon, const Q return pix2; } return pixmap; - } - break; - case SP_DirIcon: { - // A rather special case - QIcon closeIcon = QStyle::standardIcon(SP_DirClosedIcon, opt, widget); - QIcon openIcon = QStyle::standardIcon(SP_DirOpenIcon, opt, widget); - closeIcon.addPixmap(openIcon.pixmap(16, 16), QIcon::Normal, QIcon::On); - closeIcon.addPixmap(openIcon.pixmap(32, 32), QIcon::Normal, QIcon::On); - closeIcon.addPixmap(openIcon.pixmap(64, 64), QIcon::Normal, QIcon::On); - closeIcon.addPixmap(openIcon.pixmap(128, 128), QIcon::Normal, QIcon::On); - return closeIcon; - } - case SP_TitleBarNormalButton: - case SP_TitleBarCloseButton: { - QIcon titleBarIcon; - if (standardIcon == SP_TitleBarCloseButton) { - titleBarIcon.addFile(QLatin1String(":/trolltech/styles/macstyle/images/closedock-16.png")); - titleBarIcon.addFile(QLatin1String(":/trolltech/styles/macstyle/images/closedock-down-16.png"), QSize(16, 16), QIcon::Normal, QIcon::On); - } else { - titleBarIcon.addFile(QLatin1String(":/trolltech/styles/macstyle/images/dockdock-16.png")); - titleBarIcon.addFile(QLatin1String(":/trolltech/styles/macstyle/images/dockdock-down-16.png"), QSize(16, 16), QIcon::Normal, QIcon::On); - } - return titleBarIcon; - } - default: - break; } - if (iconType != 0) { - QIcon retIcon; - IconRef icon; - IconRef overlayIcon = 0; - if (iconType != kGenericApplicationIcon) { - GetIconRef(kOnSystemDisk, kSystemIconsCreator, iconType, &icon); - } else { - FSRef fsRef; - ProcessSerialNumber psn = { 0, kCurrentProcess }; - GetProcessBundleLocation(&psn, &fsRef); - GetIconRefFromFileInfo(&fsRef, 0, 0, 0, 0, kIconServicesNormalUsageFlag, &icon, 0); - if (standardIcon == SP_MessageBoxCritical) { - overlayIcon = icon; - GetIconRef(kOnSystemDisk, kSystemIconsCreator, kAlertCautionIcon, &icon); - } - } - if (icon) { - qt_mac_constructQIconFromIconRef(icon, overlayIcon, &retIcon, standardIcon); - ReleaseIconRef(icon); - } - if (overlayIcon) - ReleaseIconRef(overlayIcon); - return retIcon; } - return QWindowsStyle::standardIconImplementation(standardIcon, opt, widget); } int QMacStyle::layoutSpacingImplementation(QSizePolicy::ControlType control1, diff --git a/src/gui/styles/qstyle.cpp b/src/gui/styles/qstyle.cpp index bccd766..d47c610 100644 --- a/src/gui/styles/qstyle.cpp +++ b/src/gui/styles/qstyle.cpp @@ -1865,7 +1865,7 @@ void QStyle::drawItemPixmap(QPainter *painter, const QRect &rect, int alignment, \value SH_DockWidget_ButtonsHaveFrame Determines if dockwidget buttons should have frames. Default is true. - \value SH_ToolButtonStyle Determines the default system style for tool buttons that uses Qt::ToolButtonSystemDefault. + \value SH_ToolButtonStyle Determines the default system style for tool buttons that uses Qt::ToolButtonFollowStyle. \omitvalue SH_UnderlineAccelerator diff --git a/src/gui/util/qcompleter.cpp b/src/gui/util/qcompleter.cpp index d68e309..bf1fa6a 100644 --- a/src/gui/util/qcompleter.cpp +++ b/src/gui/util/qcompleter.cpp @@ -134,7 +134,7 @@ To provide completions, QCompleter needs to know the path from an index. This is provided by pathFromIndex(). The default implementation of - pathFromIndex(), returns the data for the \l{Qt::EditRole}{edit role} + pathFromIndex(), returns the data for the \l{Qt::EditRole}{edit role} for list models and the absolute file path if the mode is a QDirModel. \sa QAbstractItemModel, QLineEdit, QComboBox, {Completer Example} @@ -772,7 +772,7 @@ QMatchData QUnsortedModelEngine::filter(const QString& part, const QModelIndex& /////////////////////////////////////////////////////////////////////////////// QCompleterPrivate::QCompleterPrivate() : widget(0), proxy(0), popup(0), cs(Qt::CaseSensitive), role(Qt::EditRole), column(0), - sorting(QCompleter::UnsortedModel), wrap(true), eatFocusOut(true) + sorting(QCompleter::UnsortedModel), wrap(true), maxVisibleItems(7), eatFocusOut(true) { } @@ -861,7 +861,7 @@ void QCompleterPrivate::showPopup(const QRect& rect) Qt::LayoutDirection dir = widget->layoutDirection(); QPoint pos; int rw, rh, w; - int h = (popup->sizeHintForRow(0) * qMin(7, popup->model()->rowCount()) + 3) + 3; + int h = (popup->sizeHintForRow(0) * qMin(maxVisibleItems, popup->model()->rowCount()) + 3) + 3; QScrollBar *hsb = popup->horizontalScrollBar(); if (hsb && hsb->isVisible()) h += popup->horizontalScrollBar()->sizeHint().height(); @@ -1510,6 +1510,30 @@ bool QCompleter::wrapAround() const } /*! + \property QCompleter::maxVisibleItems + \brief the maximum allowed size on screen of the completer, measured in items + \since 4.6 + + By default, this property has a value of 7. +*/ +int QCompleter::maxVisibleItems() const +{ + Q_D(const QCompleter); + return d->maxVisibleItems; +} + +void QCompleter::setMaxVisibleItems(int maxItems) +{ + Q_D(QCompleter); + if (maxItems < 0) { + qWarning("QCompleter::setMaxVisibleItems: " + "Invalid max visible items (%d) must be >= 0", maxItems); + return; + } + d->maxVisibleItems = maxItems; +} + +/*! \property QCompleter::caseSensitivity \brief the case sensitivity of the matching diff --git a/src/gui/util/qcompleter.h b/src/gui/util/qcompleter.h index c1169ef..a419154 100644 --- a/src/gui/util/qcompleter.h +++ b/src/gui/util/qcompleter.h @@ -69,6 +69,7 @@ class Q_GUI_EXPORT QCompleter : public QObject Q_PROPERTY(CompletionMode completionMode READ completionMode WRITE setCompletionMode) Q_PROPERTY(int completionColumn READ completionColumn WRITE setCompletionColumn) Q_PROPERTY(int completionRole READ completionRole WRITE setCompletionRole) + Q_PROPERTY(int maxVisibleItems READ maxVisibleItems WRITE setMaxVisibleItems) Q_PROPERTY(Qt::CaseSensitivity caseSensitivity READ caseSensitivity WRITE setCaseSensitivity) Q_PROPERTY(bool wrapAround READ wrapAround WRITE setWrapAround) @@ -118,6 +119,9 @@ public: bool wrapAround() const; + int maxVisibleItems() const; + void setMaxVisibleItems(int maxItems); + int completionCount() const; bool setCurrentRow(int row); int currentRow() const; diff --git a/src/gui/util/qcompleter_p.h b/src/gui/util/qcompleter_p.h index dc4189f..288f531 100644 --- a/src/gui/util/qcompleter_p.h +++ b/src/gui/util/qcompleter_p.h @@ -87,6 +87,7 @@ public: Qt::CaseSensitivity cs; int role; int column; + int maxVisibleItems; QCompleter::ModelSorting sorting; bool wrap; diff --git a/src/gui/widgets/qtoolbutton.cpp b/src/gui/widgets/qtoolbutton.cpp index 5d0a98a..3901245 100644 --- a/src/gui/widgets/qtoolbutton.cpp +++ b/src/gui/widgets/qtoolbutton.cpp @@ -378,11 +378,17 @@ void QToolButton::initStyleOption(QStyleOptionToolButton *option) const if (d->hasMenu()) option->features |= QStyleOptionToolButton::HasMenu; #endif - if (d->toolButtonStyle == Qt::ToolButtonSystemDefault) { + if (d->toolButtonStyle == Qt::ToolButtonFollowStyle) { option->toolButtonStyle = Qt::ToolButtonStyle(style()->styleHint(QStyle::SH_ToolButtonStyle, option, this)); } else option->toolButtonStyle = d->toolButtonStyle; + if (option->toolButtonStyle == Qt::ToolButtonTextBesideIcon) { + // If the action is not prioritized, remove the text label to save space + if (d->defaultAction && d->defaultAction->priority() < QAction::NormalPriority) + option->toolButtonStyle = Qt::ToolButtonIconOnly; + } + if (d->icon.isNull() && d->arrowType == Qt::NoArrow && !forceNoText) { if (!d->text.isEmpty()) option->toolButtonStyle = Qt::ToolButtonTextOnly; @@ -482,7 +488,7 @@ QSize QToolButton::minimumSizeHint() const If you want your toolbars to depend on system settings, as is possible in GNOME and KDE desktop environments you should - use the ToolButtonSystemDefault. + use the ToolButtonFollowStyle. QToolButton automatically connects this slot to the relevant signal in the QMainWindow in which is resides. diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp index f1da244..afcdf17 100644 --- a/src/network/access/qhttpnetworkconnection.cpp +++ b/src/network/access/qhttpnetworkconnection.cpp @@ -175,26 +175,43 @@ bool QHttpNetworkConnectionPrivate::isSocketReading(QAbstractSocket *socket) con return (i != -1 && (channels[i].state & ReadingState)); } +void QHttpNetworkConnectionPrivate::appendUncompressedData(QHttpNetworkReply &reply, QByteArray &qba) +{ + reply.d_func()->responseData.append(qba); + + // clear the original! helps with implicit sharing and + // avoiding memcpy when the user is reading the data + qba.clear(); +} -void QHttpNetworkConnectionPrivate::appendUncompressedData(QHttpNetworkReply &reply, const QByteArray &fragment) +void QHttpNetworkConnectionPrivate::appendUncompressedData(QHttpNetworkReply &reply, QByteDataBuffer &data) { - char *dst = reply.d_func()->responseData.reserve(fragment.size()); - qMemCopy(dst, fragment.constData(), fragment.size()); + reply.d_func()->responseData.append(data); + + // clear the original! helps with implicit sharing and + // avoiding memcpy when the user is reading the data + data.clear(); } -void QHttpNetworkConnectionPrivate::appendCompressedData(QHttpNetworkReply &reply, const QByteArray &fragment) +void QHttpNetworkConnectionPrivate::appendCompressedData(QHttpNetworkReply &reply, QByteDataBuffer &data) { - reply.d_func()->compressedData.append(fragment); + // Work in progress: Later we will directly use a list of QByteArray or a QRingBuffer + // instead of one QByteArray. + for(int i = 0; i < data.bufferCount(); i++) { + QByteArray &byteData = data[i]; + reply.d_func()->compressedData.append(byteData.constData(), byteData.size()); + } + data.clear(); } qint64 QHttpNetworkConnectionPrivate::uncompressedBytesAvailable(const QHttpNetworkReply &reply) const { - return reply.d_func()->responseData.size(); + return reply.d_func()->responseData.byteAmount(); } qint64 QHttpNetworkConnectionPrivate::uncompressedBytesAvailableNextBlock(const QHttpNetworkReply &reply) const { - return reply.d_func()->responseData.nextDataBlockSize(); + return reply.d_func()->responseData.sizeNextBlock(); } qint64 QHttpNetworkConnectionPrivate::compressedBytesAvailable(const QHttpNetworkReply &reply) const @@ -202,21 +219,6 @@ qint64 QHttpNetworkConnectionPrivate::compressedBytesAvailable(const QHttpNetwor return reply.d_func()->compressedData.size(); } -qint64 QHttpNetworkConnectionPrivate::read(QHttpNetworkReply &reply, QByteArray &data, qint64 maxSize) -{ - QRingBuffer *rb = &reply.d_func()->responseData; - if (maxSize == -1 || maxSize >= rb->size()) { - // read the whole data - data = rb->readAll(); - rb->clear(); - } else { - // read only the requested length - data.resize(maxSize); - rb->read(data.data(), maxSize); - } - return data.size(); -} - void QHttpNetworkConnectionPrivate::eraseData(QHttpNetworkReply *reply) { reply->d_func()->compressedData.clear(); @@ -556,6 +558,8 @@ bool QHttpNetworkConnectionPrivate::expand(QAbstractSocket *socket, QHttpNetwork reply->d_func()->totalProgress += inflated.size(); appendUncompressedData(*reply, inflated); if (shouldEmitSignals(reply)) { + // important: At the point of this readyRead(), inflated must be cleared, + // else implicit sharing will trigger memcpy when the user is reading data! emit reply->readyRead(); // make sure that the reply is valid if (channels[i].reply != reply) @@ -672,18 +676,19 @@ void QHttpNetworkConnectionPrivate::receiveReply(QAbstractSocket *socket, QHttpN { // use the traditional slower reading (for compressed encoding, chunked encoding, // no content-length etc) - QBuffer fragment; - fragment.open(QIODevice::WriteOnly); - bytes = reply->d_func()->readBody(socket, &fragment); + QByteDataBuffer byteDatas; + bytes = reply->d_func()->readBody(socket, &byteDatas); if (bytes) { if (reply->d_func()->autoDecompress) - appendCompressedData(*reply, fragment.data()); + appendCompressedData(*reply, byteDatas); else - appendUncompressedData(*reply, fragment.data()); + appendUncompressedData(*reply, byteDatas); if (!reply->d_func()->autoDecompress) { - reply->d_func()->totalProgress += fragment.size(); + reply->d_func()->totalProgress += bytes; if (shouldEmitSignals(reply)) { + // important: At the point of this readyRead(), the byteDatas list must be empty, + // else implicit sharing will trigger memcpy when the user is reading data! emit reply->readyRead(); // make sure that the reply is valid if (channels[i].reply != reply) diff --git a/src/network/access/qhttpnetworkconnection_p.h b/src/network/access/qhttpnetworkconnection_p.h index a0813d4..842a2f4 100644 --- a/src/network/access/qhttpnetworkconnection_p.h +++ b/src/network/access/qhttpnetworkconnection_p.h @@ -79,6 +79,7 @@ QT_BEGIN_NAMESPACE class QHttpNetworkRequest; class QHttpNetworkReply; +class QByteArray; class QHttpNetworkConnectionPrivate; class Q_AUTOTEST_EXPORT QHttpNetworkConnection : public QObject @@ -255,15 +256,14 @@ public: bool pendingAuthSignal; // there is an incomplete authentication signal bool pendingProxyAuthSignal; // there is an incomplete proxy authentication signal - void appendUncompressedData(QHttpNetworkReply &reply, const QByteArray &fragment); - void appendCompressedData(QHttpNetworkReply &reply, const QByteArray &fragment); + void appendUncompressedData(QHttpNetworkReply &reply, QByteArray &qba); + void appendUncompressedData(QHttpNetworkReply &reply, QByteDataBuffer &data); + void appendCompressedData(QHttpNetworkReply &reply, QByteDataBuffer &data); qint64 uncompressedBytesAvailable(const QHttpNetworkReply &reply) const; qint64 uncompressedBytesAvailableNextBlock(const QHttpNetworkReply &reply) const; qint64 compressedBytesAvailable(const QHttpNetworkReply &reply) const; - qint64 read(QHttpNetworkReply &reply, QByteArray &data, qint64 maxSize); - void emitReplyError(QAbstractSocket *socket, QHttpNetworkReply *reply, QNetworkReply::NetworkError errorCode); bool handleAuthenticateChallenge(QAbstractSocket *socket, QHttpNetworkReply *reply, bool isProxy, bool &resend); void allDone(QAbstractSocket *socket, QHttpNetworkReply *reply); diff --git a/src/network/access/qhttpnetworkreply.cpp b/src/network/access/qhttpnetworkreply.cpp index 7a616aa..2fe0d78 100644 --- a/src/network/access/qhttpnetworkreply.cpp +++ b/src/network/access/qhttpnetworkreply.cpp @@ -176,15 +176,6 @@ qint64 QHttpNetworkReply::bytesAvailableNextBlock() const return -1; } -QByteArray QHttpNetworkReply::read(qint64 maxSize) -{ - Q_D(QHttpNetworkReply); - QByteArray data; - if (d->connection) - d->connection->d_func()->read(*this, data, maxSize); - return data; -} - QByteArray QHttpNetworkReply::readAny() { Q_D(QHttpNetworkReply); @@ -203,7 +194,7 @@ QHttpNetworkReplyPrivate::QHttpNetworkReplyPrivate(const QUrl &newUrl) majorVersion(0), minorVersion(0), bodyLength(0), contentRead(0), totalProgress(0), chunkedTransferEncoding(0), currentChunkSize(0), currentChunkRead(0), connection(0), initInflate(false), - autoDecompress(false), responseData(0), requestIsPrepared(false) + autoDecompress(false), responseData(), requestIsPrepared(false) { } @@ -561,17 +552,19 @@ bool QHttpNetworkReplyPrivate::connectionCloseEnabled() // note this function can only be used for non-chunked, non-compressed with // known content length -qint64 QHttpNetworkReplyPrivate::readBodyFast(QAbstractSocket *socket, QRingBuffer *rb) -{ - quint64 toBeRead = qMin(socket->bytesAvailable(), bodyLength - contentRead); - char* dst = rb->reserve(toBeRead); - qint64 haveRead = socket->read(dst, toBeRead); +qint64 QHttpNetworkReplyPrivate::readBodyFast(QAbstractSocket *socket, QByteDataBuffer *rb) +{ + qint64 toBeRead = qMin(socket->bytesAvailable(), bodyLength - contentRead); + QByteArray bd; + bd.resize(toBeRead); + qint64 haveRead = socket->read(bd.data(), bd.size()); if (haveRead == -1) { - rb->chop(toBeRead); + bd.clear(); return 0; // ### error checking here; } + bd.resize(haveRead); - rb->chop(toBeRead - haveRead); + rb->append(bd); if (contentRead + haveRead == bodyLength) { state = AllDoneState; @@ -583,7 +576,7 @@ qint64 QHttpNetworkReplyPrivate::readBodyFast(QAbstractSocket *socket, QRingBuff } -qint64 QHttpNetworkReplyPrivate::readBody(QAbstractSocket *socket, QIODevice *out) +qint64 QHttpNetworkReplyPrivate::readBody(QAbstractSocket *socket, QByteDataBuffer *out) { qint64 bytes = 0; if (isChunked()) { @@ -601,33 +594,35 @@ qint64 QHttpNetworkReplyPrivate::readBody(QAbstractSocket *socket, QIODevice *ou return bytes; } -qint64 QHttpNetworkReplyPrivate::readReplyBodyRaw(QIODevice *in, QIODevice *out, qint64 size) +qint64 QHttpNetworkReplyPrivate::readReplyBodyRaw(QIODevice *in, QByteDataBuffer *out, qint64 size) { qint64 bytes = 0; Q_ASSERT(in); Q_ASSERT(out); int toBeRead = qMin<qint64>(128*1024, qMin<qint64>(size, in->bytesAvailable())); - QByteArray raw(toBeRead, 0); - while (size > 0) { - qint64 read = in->read(raw.data(), raw.size()); - if (read == 0) - return bytes; - // ### error checking here - qint64 written = out->write(raw.data(), read); - if (written == 0) + while (toBeRead > 0) { + QByteArray byteData; + byteData.resize(toBeRead); + qint64 haveRead = in->read(byteData.data(), byteData.size()); + if (haveRead <= 0) { + // ### error checking here + byteData.clear(); return bytes; - if (read != written) - qDebug() << "### read" << read << "written" << written; - bytes += read; - size -= read; - out->waitForBytesWritten(-1); // throttle + } + + byteData.resize(haveRead); + out->append(byteData); + bytes += haveRead; + size -= haveRead; + + toBeRead = qMin<qint64>(128*1024, qMin<qint64>(size, in->bytesAvailable())); } return bytes; } -qint64 QHttpNetworkReplyPrivate::readReplyBodyChunked(QIODevice *in, QIODevice *out) +qint64 QHttpNetworkReplyPrivate::readReplyBodyChunked(QIODevice *in, QByteDataBuffer *out) { qint64 bytes = 0; while (in->bytesAvailable()) { // while we can read from input @@ -648,17 +643,14 @@ qint64 QHttpNetworkReplyPrivate::readReplyBodyChunked(QIODevice *in, QIODevice * state = AllDoneState; break; } - // otherwise, read data - qint64 readSize = qMin(in->bytesAvailable(), currentChunkSize - currentChunkRead); - QByteArray buffer(readSize, 0); - qint64 read = in->read(buffer.data(), readSize); - bytes += read; - currentChunkRead += read; - qint64 written = out->write(buffer); - Q_UNUSED(written); // Avoid compile warning when building release - Q_ASSERT(read == written); + + // otherwise, try to read what is missing for this chunk + qint64 haveRead = readReplyBodyRaw (in, out, currentChunkSize - currentChunkRead); + currentChunkRead += haveRead; + bytes += haveRead; + // ### error checking here - out->waitForBytesWritten(-1); + } return bytes; } diff --git a/src/network/access/qhttpnetworkreply_p.h b/src/network/access/qhttpnetworkreply_p.h index 5eb70ce..fbbee12 100644 --- a/src/network/access/qhttpnetworkreply_p.h +++ b/src/network/access/qhttpnetworkreply_p.h @@ -80,6 +80,7 @@ static const unsigned char gz_magic[2] = {0x1f, 0x8b}; // gzip magic header #include <private/qhttpnetworkrequest_p.h> #include <private/qauthenticator_p.h> #include <private/qringbuffer_p.h> +#include <private/qbytedata_p.h> QT_BEGIN_NAMESPACE @@ -122,7 +123,6 @@ public: qint64 bytesAvailable() const; qint64 bytesAvailableNextBlock() const; - QByteArray read(qint64 maxSize = -1); QByteArray readAny(); bool isFinished() const; @@ -160,14 +160,14 @@ public: bool parseStatus(const QByteArray &status); qint64 readHeader(QAbstractSocket *socket); void parseHeader(const QByteArray &header); - qint64 readBody(QAbstractSocket *socket, QIODevice *out); - qint64 readBodyFast(QAbstractSocket *socket, QRingBuffer *rb); + qint64 readBody(QAbstractSocket *socket, QByteDataBuffer *out); + qint64 readBodyFast(QAbstractSocket *socket, QByteDataBuffer *rb); bool findChallenge(bool forProxy, QByteArray &challenge) const; QAuthenticatorPrivate::Method authenticationMethod(bool isProxy) const; void clear(); - qint64 readReplyBodyRaw(QIODevice *in, QIODevice *out, qint64 size); - qint64 readReplyBodyChunked(QIODevice *in, QIODevice *out); + qint64 readReplyBodyRaw(QIODevice *in, QByteDataBuffer *out, qint64 size); + qint64 readReplyBodyChunked(QIODevice *in, QByteDataBuffer *out); qint64 getChunkSize(QIODevice *in, qint64 *chunkSize); qint64 bytesAvailable() const; @@ -209,7 +209,7 @@ public: #endif bool autoDecompress; - QRingBuffer responseData; // uncompressed body + QByteDataBuffer responseData; // uncompressed body QByteArray compressedData; // compressed body (temporary) bool requestIsPrepared; }; diff --git a/src/network/access/qnetworkaccessbackend.cpp b/src/network/access/qnetworkaccessbackend.cpp index 88ae894..9e17b54 100644 --- a/src/network/access/qnetworkaccessbackend.cpp +++ b/src/network/access/qnetworkaccessbackend.cpp @@ -217,9 +217,9 @@ qint64 QNetworkAccessBackend::nextDownstreamBlockSize() const return reply->nextDownstreamBlockSize(); } -void QNetworkAccessBackend::writeDownstreamData(const QByteArray &data) +void QNetworkAccessBackend::writeDownstreamData(QByteDataBuffer &list) { - reply->appendDownstreamData(data); + reply->appendDownstreamData(list); } void QNetworkAccessBackend::writeDownstreamData(QIODevice *data) diff --git a/src/network/access/qnetworkaccessbackend_p.h b/src/network/access/qnetworkaccessbackend_p.h index 21cb4a6..553b795 100644 --- a/src/network/access/qnetworkaccessbackend_p.h +++ b/src/network/access/qnetworkaccessbackend_p.h @@ -166,7 +166,7 @@ protected: // these functions control the downstream mechanism // that is, data that has come via the connection and is going out the backend qint64 nextDownstreamBlockSize() const; - void writeDownstreamData(const QByteArray &data); + void writeDownstreamData(QByteDataBuffer &list); public slots: // for task 251801, needs to be a slot to be called asynchronously diff --git a/src/network/access/qnetworkaccessdatabackend.cpp b/src/network/access/qnetworkaccessdatabackend.cpp index 609f0c5..4436cf4 100644 --- a/src/network/access/qnetworkaccessdatabackend.cpp +++ b/src/network/access/qnetworkaccessdatabackend.cpp @@ -117,7 +117,11 @@ void QNetworkAccessDataBackend::open() setHeader(QNetworkRequest::ContentLengthHeader, payload.size()); emit metaDataChanged(); - writeDownstreamData(payload); + QByteDataBuffer list; + list.append(payload); + payload.clear(); // important because of implicit sharing! + writeDownstreamData(list); + finished(); return; } diff --git a/src/network/access/qnetworkaccessdebugpipebackend.cpp b/src/network/access/qnetworkaccessdebugpipebackend.cpp index 54fcddd..2b3c128 100644 --- a/src/network/access/qnetworkaccessdebugpipebackend.cpp +++ b/src/network/access/qnetworkaccessdebugpipebackend.cpp @@ -155,7 +155,11 @@ void QNetworkAccessDebugPipeBackend::pushFromSocketToDownstream() // have read something buffer.resize(haveRead); bytesDownloaded += haveRead; - writeDownstreamData(buffer); + + QByteDataBuffer list; + list.append(buffer); + buffer.clear(); // important because of implicit sharing! + writeDownstreamData(list); } } } diff --git a/src/network/access/qnetworkaccessfilebackend.cpp b/src/network/access/qnetworkaccessfilebackend.cpp index e3fc8bf..533fc75 100644 --- a/src/network/access/qnetworkaccessfilebackend.cpp +++ b/src/network/access/qnetworkaccessfilebackend.cpp @@ -263,7 +263,11 @@ bool QNetworkAccessFileBackend::readMoreFromFile() data.resize(actuallyRead); totalBytes += actuallyRead; - writeDownstreamData(data); + + QByteDataBuffer list; + list.append(data); + data.clear(); // important because of implicit sharing! + writeDownstreamData(list); } return true; } diff --git a/src/network/access/qnetworkaccessftpbackend.cpp b/src/network/access/qnetworkaccessftpbackend.cpp index d6276a3..911b31a 100644 --- a/src/network/access/qnetworkaccessftpbackend.cpp +++ b/src/network/access/qnetworkaccessftpbackend.cpp @@ -355,7 +355,11 @@ void QNetworkAccessFtpBackend::ftpDone() void QNetworkAccessFtpBackend::ftpReadyRead() { - writeDownstreamData(ftp->readAll()); + QByteArray data = ftp->readAll(); + QByteDataBuffer list; + list.append(data); + data.clear(); // important because of implicit sharing! + writeDownstreamData(list); } void QNetworkAccessFtpBackend::ftpRawCommandReply(int code, const QString &text) diff --git a/src/network/access/qnetworkaccesshttpbackend.cpp b/src/network/access/qnetworkaccesshttpbackend.cpp index db84e58..9c36026 100644 --- a/src/network/access/qnetworkaccesshttpbackend.cpp +++ b/src/network/access/qnetworkaccesshttpbackend.cpp @@ -653,10 +653,15 @@ void QNetworkAccessHttpBackend::readFromHttp() // this is not a critical thing since it is already in the // memory anyway - while (httpReply->bytesAvailable() != 0 && nextDownstreamBlockSize() != 0) { - const QByteArray data = httpReply->readAny(); - writeDownstreamData(data); + QByteDataBuffer list; + + while (httpReply->bytesAvailable() != 0 && nextDownstreamBlockSize() != 0 && nextDownstreamBlockSize() > list.byteAmount()) { + QByteArray data = httpReply->readAny(); + list.append(data); } + + if (!list.isEmpty()) + writeDownstreamData(list); } void QNetworkAccessHttpBackend::replyFinished() diff --git a/src/network/access/qnetworkreplyimpl.cpp b/src/network/access/qnetworkreplyimpl.cpp index 55b8b7f..44ae328 100644 --- a/src/network/access/qnetworkreplyimpl.cpp +++ b/src/network/access/qnetworkreplyimpl.cpp @@ -103,16 +103,17 @@ void QNetworkReplyImplPrivate::_q_copyReadyRead() break; bytesToRead = qBound<qint64>(1, bytesToRead, copyDevice->bytesAvailable()); - char *ptr = readBuffer.reserve(bytesToRead); - qint64 bytesActuallyRead = copyDevice->read(ptr, bytesToRead); + QByteArray byteData; + byteData.resize(bytesToRead); + qint64 bytesActuallyRead = copyDevice->read(byteData.data(), byteData.size()); if (bytesActuallyRead == -1) { - readBuffer.chop(bytesToRead); + byteData.clear(); backendNotify(NotifyCopyFinished); break; } - if (bytesActuallyRead != bytesToRead) - readBuffer.chop(bytesToRead - bytesActuallyRead); + byteData.resize(bytesActuallyRead); + readBuffer.append(byteData); if (!copyDevice->isSequential() && copyDevice->atEnd()) { backendNotify(NotifyCopyFinished); @@ -384,19 +385,17 @@ qint64 QNetworkReplyImplPrivate::nextDownstreamBlockSize() const if (readBufferMaxSize == 0) return DesiredBufferSize; - return qMax<qint64>(0, readBufferMaxSize - readBuffer.size()); + return qMax<qint64>(0, readBufferMaxSize - readBuffer.byteAmount()); } // we received downstream data and send this to the cache // and to our readBuffer (which in turn gets read by the user of QNetworkReply) -void QNetworkReplyImplPrivate::appendDownstreamData(const QByteArray &data) +void QNetworkReplyImplPrivate::appendDownstreamData(QByteDataBuffer &data) { Q_Q(QNetworkReplyImpl); if (!q->isOpen()) return; - readBuffer.append(data); - if (cacheEnabled && !cacheSaveDevice) { // save the meta data QNetworkCacheMetaData metaData; @@ -415,10 +414,19 @@ void QNetworkReplyImplPrivate::appendDownstreamData(const QByteArray &data) } } - if (cacheSaveDevice) - cacheSaveDevice->write(data); + qint64 bytesWritten = 0; + for (int i = 0; i < data.bufferCount(); i++) { + QByteArray item = data[i]; + + if (cacheSaveDevice) + cacheSaveDevice->write(item.constData(), item.size()); + readBuffer.append(item); + + bytesWritten += item.size(); + } + data.clear(); - bytesDownloaded += data.size(); + bytesDownloaded += bytesWritten; lastBytesDownloaded = bytesDownloaded; QPointer<QNetworkReplyImpl> qq = q; @@ -427,6 +435,8 @@ void QNetworkReplyImplPrivate::appendDownstreamData(const QByteArray &data) pauseNotificationHandling(); emit q->downloadProgress(bytesDownloaded, totalSize.isNull() ? Q_INT64_C(-1) : totalSize.toLongLong()); + // important: At the point of this readyRead(), the data parameter list must be empty, + // else implicit sharing will trigger memcpy when the user is reading data! emit q->readyRead(); // hopefully we haven't been deleted here @@ -602,14 +612,14 @@ void QNetworkReplyImpl::close() */ qint64 QNetworkReplyImpl::bytesAvailable() const { - return QNetworkReply::bytesAvailable() + d_func()->readBuffer.size(); + return QNetworkReply::bytesAvailable() + d_func()->readBuffer.byteAmount(); } void QNetworkReplyImpl::setReadBufferSize(qint64 size) { Q_D(QNetworkReplyImpl); if (size > d->readBufferMaxSize && - size == d->readBuffer.size()) + size > d->readBuffer.byteAmount()) d->backendNotify(QNetworkReplyImplPrivate::NotifyDownstreamReadyWrite); QNetworkReply::setReadBufferSize(size); @@ -657,7 +667,7 @@ qint64 QNetworkReplyImpl::readData(char *data, qint64 maxlen) return 1; } - maxlen = qMin<qint64>(maxlen, d->readBuffer.size()); + maxlen = qMin<qint64>(maxlen, d->readBuffer.byteAmount()); return d->readBuffer.read(data, maxlen); } diff --git a/src/network/access/qnetworkreplyimpl_p.h b/src/network/access/qnetworkreplyimpl_p.h index 454185a..83a8aca 100644 --- a/src/network/access/qnetworkreplyimpl_p.h +++ b/src/network/access/qnetworkreplyimpl_p.h @@ -61,6 +61,7 @@ #include "QtCore/qqueue.h" #include "QtCore/qbuffer.h" #include "private/qringbuffer_p.h" +#include "private/qbytedata_p.h" QT_BEGIN_NAMESPACE @@ -144,7 +145,7 @@ public: void consume(qint64 count); void emitUploadProgress(qint64 bytesSent, qint64 bytesTotal); qint64 nextDownstreamBlockSize() const; - void appendDownstreamData(const QByteArray &data); + void appendDownstreamData(QByteDataBuffer &data); void appendDownstreamData(QIODevice *data); void finished(); void error(QNetworkReply::NetworkError code, const QString &errorString); @@ -172,7 +173,7 @@ public: QList<QNetworkProxy> proxyList; #endif - QRingBuffer readBuffer; + QByteDataBuffer readBuffer; qint64 bytesDownloaded; qint64 lastBytesDownloaded; qint64 bytesUploaded; |