DITA_DOCS = $$replace(ONLINE_CONF, "/", "\\")
}
-online_docs.commands = $$QDOC $$ONLINE_CONF
-dita_docs.commands = $$QDOC $$DITA_CONF
+qtquick_online_docs.commands = $$QDOC $$ONLINE_CONF
+qtquick_dita_docs.commands = $$QDOC $$DITA_CONF
-docs.depends = dita_docs online_docs
-QMAKE_EXTRA_TARGETS = docs dita_docs online_docs
+qtquick_docs.depends = qtquick_dita_docs qtquick_online_docs
+QMAKE_EXTRA_TARGETS = qtquick_docs qtquick_dita_docs qtquick_online_docs
QMAKE_CLEAN += \
"-r $$PWD/html" \
"-r $$PWD/ditaxml"
footer: quitButtonDelegate
delegate: CategoryDelegate {}
highlight: Rectangle { color: "steelblue" }
- highlightMoveDuration: 50
+ highlightMoveVelocity: 9999999
}
ScrollBar {
scrollArea: categories; height: categories.height; width: 8
for (var i=0; i<particles.length; i++) {
var particle = particles[i];
particle.startSize = Math.max(02,Math.min(492,Math.tan(particle.t/2)*24));
- var theta = Math.floor(Math.random() * 6.0) / 6.0;
+ var theta = Math.floor(Math.random() * 6.0);
+ particle.red = theta == 0 || theta == 1 || theta == 2 ? 0.2 : 1;
+ particle.green = theta == 2 || theta == 3 || theta == 4 ? 0.2 : 1;
+ particle.blue = theta == 4 || theta == 5 || theta == 0 ? 0.2 : 1;
+ theta /= 6.0;
theta *= 2.0*Math.PI;
theta += sys.convert(sys.petalRotation);
particle.initialVX = petalLength * Math.cos(theta);
ImageParticle {
source: "../images/particle4.png"
alpha: 0.0
- redVariation: 0.6
- color: "white"
}
}
}
}
+ foreach (QQuickParticleData* d, toEmit)
+ m_system->emitParticle(d);
+
if (isEmitConnected()) {
+ //Done after emitParticle so that the Painter::load is done first, this allows you to customize its static variables
+ //We then don't need to request another reload, because the first reload isn't scheduled until we get back to the render thread
v8::HandleScope handle_scope;
v8::Context::Scope scope(QQmlEnginePrivate::getV8Engine(qmlEngine(this))->context());
v8::Handle<v8::Array> array = v8::Array::New(toEmit.size());
emitParticles(QQmlV8Handle::fromHandle(array));//A chance for arbitrary JS changes
}
- foreach (QQuickParticleData* d, toEmit)
- m_system->emitParticle(d);
m_last_emission = pt;
\qmlproperty real QtQuick.Particles2::TrailEmitter::emitRatePerParticle
*/
/*!
- \qmlsignal QtQuick.Particles2::TrailEmitter::emitFollowParticles(Array particles, real followed)
+ \qmlsignal QtQuick.Particles2::TrailEmitter::emitFollowParticles(Array particles, QtQuick.Particles2::Particle followed)
This handler is called when particles are emitted from the \a followed particle. \a particles contains an array of particle objects which can be directly manipulated.
}
}
+ foreach (QQuickParticleData* d, toEmit)
+ m_system->emitParticle(d);
+
if (isEmitConnected() || isEmitFollowConnected()) {
v8::HandleScope handle_scope;
v8::Context::Scope scope(QQmlEnginePrivate::getV8Engine(qmlEngine(this))->context());
else if (isEmitConnected())
emitParticles(QQmlV8Handle::fromHandle(array));//A chance for arbitrary JS changes
}
- foreach (QQuickParticleData* d, toEmit)
- m_system->emitParticle(d);
m_lastEmission[d->index] = pt;
}
+include(global/qt-html-templates-offline.qdocconf)
+include(global/qt-cpp-ignore.qdocconf)
+
project = QtQml
description = Qt QML Reference Documentation
url = http://qt-project.org/doc/qt-5.0/qtqml
naturallanguage = en_US
qhp.projects = QtCore
-depends += qtcore qtjsbackend qtxmlpatterns qtquick
+depends += qtcore qtxmlpatterns
qhp.QtQml.file = qtqml.qhp
qhp.QtQml.namespace = org.qt-project.qtqml.500
HTML.templatedir = .
-HTML.stylesheets = ../../../doc/global/style/offline.css
+HTML.stylesheets = global/style/offline.css
HTML.headerstyles = \
" <link rel=\"stylesheet\" type=\"text/css\" href=\"style/offline.css\" />\n"
\code
template<typename T, int metaObjectRevision>
int qmlRegisterRevision(const char *uri, int versionMajor, int versionMinor)
+
+ template<typename T, int metaObjectRevision>
+ int qmlRegisterUncreatableType(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& reason)
\endcode
For example, if \c BaseObject is changed and now has a revision 1, you can specify that
Usually you will only have to do this once, because relative URLs resolved from
that file will use the same protocol.
+ URLs may contain encoded characters using the 'percent-encoding' scheme
+ specified by \l {http://tools.ietf.org/html/rfc3986}{RFC 3986}. These characters
+ will be preserved within properties of type \c url, to allow QML code to
+ construct precise URL values. An exception to this rule is the preemptive
+ decoding of directory-separator characters (\c '/') - these characters are decoded
+ to allow the URL to be correctly classified.
+
+ For example, a local file containing a '#' character, which would normally be
+ interpreted as the beginning of the URL 'fragment' element, can be accessed by
+ encoding the characters of the file name:
+
+ \qml
+ Image { source: encodeURIComponent("/tmp/test#1.png") }
+ \endqml
+
\sa {QML Basic Types}
*/
MODULE_DEFINES = QQmlImageProvider=QQuickImageProvider
load(qt_module_config)
+QMAKE_DOCS = $$PWD/doc/qtqml.qdocconf
+
# private dependencies
QT += v8-private
QT_BEGIN_NAMESPACE
-template<class T, int Increment=1024>
-class QPODVector
+template<class T, int Increment>
+class QPODVector
{
public:
QPODVector()
: m_count(0), m_capacity(0), m_data(0) {}
- ~QPODVector() { if (m_data) ::free(m_data); }
+ ~QPODVector() { if (m_data) ::free(m_data); }
const T &at(int idx) const {
return m_data[idx];
int newSize = m_count + count;
reserve(newSize);
int moveCount = m_count - idx;
- if (moveCount)
- ::memmove(m_data + idx + count, m_data + idx,
+ if (moveCount)
+ ::memmove(m_data + idx + count, m_data + idx,
moveCount * sizeof(T));
m_count = newSize;
}
void remove(int idx, int count = 1) {
int moveCount = m_count - (idx + count);
if (moveCount)
- ::memmove(m_data + idx, m_data + idx + count,
+ ::memmove(m_data + idx, m_data + idx + count,
moveCount * sizeof(T));
m_count -= count;
}
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
}
+template<typename T, int metaObjectRevision>
+int qmlRegisterUncreatableType(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& reason)
+{
+ QML_GETTYPENAMES
+
+ QQmlPrivate::RegisterType type = {
+ 1,
+
+ qRegisterNormalizedMetaType<T *>(pointerName.constData()),
+ qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData()),
+ 0, 0,
+ reason,
+
+ uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject,
+
+ QQmlPrivate::attachedPropertiesFunc<T>(),
+ QQmlPrivate::attachedPropertiesMetaObject<T>(),
+
+ QQmlPrivate::StaticCastSelector<T,QQmlParserStatus>::cast(),
+ QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueSource>::cast(),
+ QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueInterceptor>::cast(),
+
+ 0, 0,
+
+ 0,
+ metaObjectRevision
+ };
+
+ return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
+}
+
template<typename T>
int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const char *qmlName)
{
{
Instruction::StoreUrl instr;
QString string = v->value.asString();
+ // Encoded dir-separators defeat QUrl processing - decode them first
+ string.replace(QLatin1String("%2f"), QLatin1String("/"), Qt::CaseInsensitive);
QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(QUrl(string));
instr.propertyIndex = prop->index;
instr.value = output->indexForUrl(u);
\class QQmlFile
\brief The QQmlFile class gives access to local and remote files.
-Supports file://, qrc://, bundle:// uris and whatever QNetworkAccessManager supports.
+Supports file://, qrc:/, bundle:// uris and whatever QNetworkAccessManager supports.
*/
#define QQMLFILE_MAX_REDIRECT_RECURSION 16
/*!
Returns true if QQmlFile will open \a url synchronously.
-Synchronous urls have a qrc://, file://, or bundle:// scheme.
+Synchronous urls have a qrc:/, file://, or bundle:// scheme.
*/
bool QQmlFile::isSynchronous(const QUrl &url)
{
/*!
Returns true if QQmlFile will open \a url synchronously.
-Synchronous urls have a qrc://, file://, or bundle:// scheme.
+Synchronous urls have a qrc:/, file://, or bundle:// scheme.
*/
bool QQmlFile::isSynchronous(const QString &url)
{
- if (url.length() < 6 /* qrc:// */)
+ if (url.length() < 5 /* qrc:/ */)
return false;
QChar f = url[0];
} else if (f == QLatin1Char('q') || f == QLatin1Char('Q')) {
- return url.length() >= 6 /* bundle:// */ &&
+ return url.length() >= 5 /* qrc:/ */ &&
url.startsWith(qrc_string, Qt::CaseInsensitive) &&
- url[3] == QLatin1Char(':') && url[4] == QLatin1Char('/') && url[5] == QLatin1Char('/');
+ url[3] == QLatin1Char(':') && url[4] == QLatin1Char('/');
}
/*!
Returns true if \a url is a local file that can be opened with QFile.
-Local file urls have either a qrc:// or file:// scheme.
+Local file urls have either a qrc:/ or file:// scheme.
*/
bool QQmlFile::isLocalFile(const QUrl &url)
{
/*!
Returns true if \a url is a local file that can be opened with QFile.
-Local file urls have either a qrc:// or file:// scheme.
+Local file urls have either a qrc:/ or file:// scheme.
*/
bool QQmlFile::isLocalFile(const QString &url)
{
- if (url.length() < 6 /* qrc:// */)
+ if (url.length() < 5 /* qrc:/ */)
return false;
QChar f = url[0];
} else if (f == QLatin1Char('q') || f == QLatin1Char('Q')) {
- return url.length() >= 6 /* bundle:// */ &&
+ return url.length() >= 5 /* qrc:/ */ &&
url.startsWith(qrc_string, Qt::CaseInsensitive) &&
- url[3] == QLatin1Char(':') && url[4] == QLatin1Char('/') && url[5] == QLatin1Char('/');
+ url[3] == QLatin1Char(':') && url[4] == QLatin1Char('/');
}
u = value.toUrl();
found = true;
} else if (variantType == QVariant::ByteArray) {
- u = QUrl(QString::fromUtf8(value.toByteArray()));
+ QString input(QString::fromUtf8(value.toByteArray()));
+ // Encoded dir-separators defeat QUrl processing - decode them first
+ input.replace(QLatin1String("%2f"), QLatin1String("/"), Qt::CaseInsensitive);
+ u = QUrl(input);
found = true;
} else if (variantType == QVariant::String) {
- u = QUrl(value.toString());
+ QString input(value.toString());
+ // Encoded dir-separators defeat QUrl processing - decode them first
+ input.replace(QLatin1String("%2f"), QLatin1String("/"), Qt::CaseInsensitive);
+ u = QUrl(input);
found = true;
}
propType = QMetaType::Void;
const char *returnType = m.typeName();
- Q_ASSERT(returnType != 0);
+ if (!returnType)
+ returnType = "\0";
if ((*returnType != 'v') || (qstrcmp(returnType+1, "oid") != 0)) {
propTypeName = returnType;
flags |= NotFullyResolved;
const ListModelData *lmd = (const ListModelData *)d.constData();
const char *data = ((const char *)lmd) + lmd->dataOffset;
+ bool setRoles = false;
+
QStack<DataStackElement> stack;
for (int ii = 0; ii < lmd->instrCount; ++ii) {
}
e1.model->setOrCreateProperty(e1.elementIndex, name, value);
+ setRoles = true;
}
break;
break;
}
}
+
+ if (setRoles == false)
+ qmlInfo(obj) << "All ListElement declarations are empty, no roles can be created unless dynamicRoles is set.";
}
bool QQuickListModelParser::definesEmptyList(const QString &s)
if (src.isUndefined()) {
output.setUndefined();
} else {
- const QString tmp(*src.getstringptr());
+ QString tmp(*src.getstringptr());
+ // Encoded dir-separators defeat QUrl processing - decode them first
+ tmp.replace(QLatin1String("%2f"), QLatin1String("/"), Qt::CaseInsensitive);
if (instr->unaryop.src == instr->unaryop.output) {
output.cleanupString();
MARK_CLEAN_REGISTER(instr->unaryop.output);
COLOR_REGISTER(instr->unaryop.output);
}
}
- QML_V4_END_INSTR(ConvertStringToUrl, unaryop)
+ QML_V4_END_INSTR(ConvertStringToColor, unaryop)
QML_V4_BEGIN_INSTR(ConvertStringToVariant, unaryop)
{
+include(global/qt-html-templates-offline.qdocconf)
+include(global/qt-cpp-ignore.qdocconf)
+
project = QtQuick
description = Qt Quick Reference Documentation
url = http://qt-project.org/doc/qt-5.0/qtquick
version = 5.0.0
-depends += qtqcore qtxmlpatterns qtjsbackend qtqml
+depends += qtqcore qtxmlpatterns qtqml
sourceencoding = UTF-8
outputencoding = UTF-8
HTML.templatedir = .
-HTML.stylesheets = ../../../doc/global/style/offline.css
+HTML.stylesheets = global/style/offline.css
HTML.headerstyles = \
" <link rel=\"stylesheet\" type=\"text/css\" href=\"style/offline.css\" />\n"
\inqmlmodule QtQuick.Particles 2.0
\title Using the Qt Quick Particle System
+ Documentation for all Particle System elements can be found on the \l{QML Module QtQuick.Particles 2}{QtQuick.Particles} module page.
Note that to use elements from the particles module, you will need to import the types with the following line:
\code
void QQuickBorderImage::setSource(const QUrl &url)
{
Q_D(QQuickBorderImage);
- //equality is fairly expensive, so we bypass for simple, common case
- if ((d->url.isEmpty() == url.isEmpty()) && url == d->url)
+
+ if (url == d->url)
return;
if (d->sciReply) {
setImplicitSize(0, 0);
emit statusChanged(d->status);
update();
+ return;
} else {
d->status = Loading;
if (d->url.path().endsWith(QLatin1String("sci"))) {
emit statusChanged(d->status);
emit progressChanged(d->progress);
update();
+ return;
}
}
}
d->clearHover();
d->lastMousePosition = QPoint();
break;
+#ifndef QT_NO_DRAGANDDROP
case QEvent::DragEnter:
case QEvent::DragLeave:
case QEvent::DragMove:
case QEvent::Drop:
d->deliverDragEvent(&d->dragGrabber, e);
break;
+#endif
case QEvent::WindowDeactivate:
rootItem()->windowDeactivateEvent();
break;
return false;
}
+#ifndef QT_NO_DRAGANDDROP
void QQuickCanvasPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QEvent *event)
{
Q_Q(QQuickCanvas);
return accepted;
}
+#endif // QT_NO_DRAGANDDROP
bool QQuickCanvasPrivate::sendFilteredMouseEvent(QQuickItem *target, QQuickItem *item, QEvent *event)
{
QQuickItemPrivate::get(item)->deliverTouchEvent(static_cast<QTouchEvent *>(e));
}
break;
+#ifndef QT_NO_DRAGANDDROP
case QEvent::DragEnter:
case QEvent::DragMove:
case QEvent::DragLeave:
case QEvent::Drop:
QQuickItemPrivate::get(item)->deliverDragEvent(e);
break;
+#endif
default:
break;
}
#include <qopenglcontext.h>
#include <QtGui/qopenglframebufferobject.h>
#include <QtGui/qevent.h>
-#include <QtGui/qinputpanel.h>
QT_BEGIN_NAMESPACE
QQuickItem *activeFocusItem;
QQuickItem *mouseGrabberItem;
+#ifndef QT_NO_DRAGANDDROP
QQuickDragGrabber dragGrabber;
+#endif
int touchMouseId;
ulong touchMousePressTimestamp;
bool sendHoverEvent(QEvent::Type, QQuickItem *, const QPointF &scenePos, const QPointF &lastScenePos,
Qt::KeyboardModifiers modifiers, bool accepted);
bool clearHover();
+#ifndef QT_NO_DRAGANDDROP
void deliverDragEvent(QQuickDragGrabber *, QEvent *);
bool deliverDragEvent(QQuickDragGrabber *, QQuickItem *, QDragMoveEvent *);
+#endif
QList<QQuickItem*> hoverItems;
enum FocusOption {
#include <QtQml/qqmlinfo.h>
#include <QtGui/qevent.h>
+#ifndef QT_NO_DRAGANDDROP
+
QT_BEGIN_NAMESPACE
class QQuickDragAttachedPrivate : public QObjectPrivate, public QQuickItemChangeListener
}
QT_END_NAMESPACE
+
+#endif // QT_NO_DRAGANDDROP
#include <QtCore/qmimedata.h>
#include <QtCore/qstringlist.h>
+#ifndef QT_NO_DRAGANDDROP
QT_BEGIN_HEADER
QT_END_HEADER
+#endif // QT_NO_DRAGANDDROP
+
#endif
#include <private/qqmlengine_p.h>
+#ifndef QT_NO_DRAGANDDROP
+
QT_BEGIN_NAMESPACE
QQuickDropAreaDrag::QQuickDropAreaDrag(QQuickDropAreaPrivate *d, QObject *parent)
QT_END_NAMESPACE
+#endif // QT_NO_DRAGANDDROP
#include <QtGui/qevent.h>
+#ifndef QT_NO_DRAGANDDROP
+
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
QT_END_HEADER
+#endif // QT_NO_DRAGANDDROP
+
#endif // QQUICKDROPAREA_P_H
void QQuickImageBase::setSource(const QUrl &url)
{
Q_D(QQuickImageBase);
- //equality is fairly expensive, so we bypass for simple, common case
- if ((d->url.isEmpty() == url.isEmpty()) && url == d->url)
+
+ if (url == d->url)
return;
d->url = url;
Q_UNUSED(event);
}
+#ifndef QT_NO_DRAGANDDROP
void QQuickItem::dragEnterEvent(QDragEnterEvent *event)
{
Q_UNUSED(event);
{
Q_UNUSED(event);
}
+#endif // QT_NO_DRAGANDDROP
bool QQuickItem::childMouseEventFilter(QQuickItem *, QEvent *)
{
}
}
+#ifndef QT_NO_DRAGANDDROP
void QQuickItemPrivate::deliverDragEvent(QEvent *e)
{
Q_Q(QQuickItem);
break;
}
}
+#endif // QT_NO_DRAGANDDROP
void QQuickItem::itemChange(ItemChange change, const ItemChangeData &value)
{
virtual void hoverEnterEvent(QHoverEvent *event);
virtual void hoverMoveEvent(QHoverEvent *event);
virtual void hoverLeaveEvent(QHoverEvent *event);
+#ifndef QT_NO_DRAGANDDROP
virtual void dragEnterEvent(QDragEnterEvent *);
virtual void dragMoveEvent(QDragMoveEvent *);
virtual void dragLeaveEvent(QDragLeaveEvent *);
virtual void dropEvent(QDropEvent *);
+#endif
virtual bool childMouseEventFilter(QQuickItem *, QEvent *);
virtual void windowDeactivateEvent();
void deliverWheelEvent(QWheelEvent *);
void deliverTouchEvent(QTouchEvent *);
void deliverHoverEvent(QHoverEvent *);
+#ifndef QT_NO_DRAGANDDROP
void deliverDragEvent(QEvent *);
+#endif
bool calcEffectiveVisible() const;
bool setEffectiveVisibleRecur(bool);
qmlRegisterType<QQuickPathAnimation>("QtQuick",2,0,"PathAnimation");
qmlRegisterType<QQuickPathInterpolator>("QtQuick",2,0,"PathInterpolator");
+#ifndef QT_NO_DRAGANDDROP
qmlRegisterType<QQuickDropArea>("QtQuick", 2, 0, "DropArea");
qmlRegisterType<QQuickDropEvent>();
qmlRegisterType<QQuickDropAreaDrag>();
qmlRegisterUncreatableType<QQuickDrag>("QtQuick", 2, 0, "Drag", QQuickDragAttached::tr("Drag is only available via attached properties"));
+#endif
qmlRegisterType<QQuickMultiPointTouchArea>("QtQuick", 2, 0, "MultiPointTouchArea");
qmlRegisterType<QQuickTouchPoint>("QtQuick", 2, 0, "TouchPoint");
virtual void updateSections();
QQuickItem *getSectionItem(const QString §ion);
void releaseSectionItem(QQuickItem *item);
+ void releaseSectionItems();
void updateInlineSection(FxListItemSG *);
void updateCurrentSection();
void updateStickySections();
QSmoothedAnimation *highlightPosAnimator;
QSmoothedAnimation *highlightSizeAnimator;
+ qreal highlightMoveVelocity;
+ qreal highlightResizeVelocity;
int highlightResizeDuration;
QQuickViewSection *sectionCriteria;
, averageSize(100.0), spacing(0.0)
, snapMode(QQuickListView::NoSnap)
, highlightPosAnimator(0), highlightSizeAnimator(0)
- , highlightResizeDuration(250)
+ , highlightMoveVelocity(400), highlightResizeVelocity(400), highlightResizeDuration(-1)
, sectionCriteria(0), currentSectionItem(0), nextSectionItem(0)
, overshootDist(0.0), correctFlick(false), inFlickCorrection(false)
{}
void QQuickViewSection::setDelegate(QQmlComponent *delegate)
{
if (delegate != m_delegate) {
+ if (m_delegate)
+ m_view->releaseSectionItems();
m_delegate = delegate;
emit delegateChanged();
m_view->updateSections();
const QLatin1String posProp(orient == QQuickListView::Vertical ? "y" : "x");
highlightPosAnimator = new QSmoothedAnimation;
highlightPosAnimator->target = QQmlProperty(item, posProp);
+ highlightPosAnimator->velocity = highlightMoveVelocity;
highlightPosAnimator->userDuration = highlightMoveDuration;
const QLatin1String sizeProp(orient == QQuickListView::Vertical ? "height" : "width");
highlightSizeAnimator = new QSmoothedAnimation;
+ highlightSizeAnimator->velocity = highlightResizeVelocity;
highlightSizeAnimator->userDuration = highlightResizeDuration;
highlightSizeAnimator->target = QQmlProperty(item, sizeProp);
delete item;
}
+
+void QQuickListViewPrivate::releaseSectionItems()
+{
+ for (int i = 0; i < visibleItems.count(); ++i) {
+ FxListItemSG *listItem = static_cast<FxListItemSG *>(visibleItems.at(i));
+ if (listItem->section()) {
+ qreal pos = listItem->position();
+ releaseSectionItem(listItem->section());
+ listItem->setSection(0);
+ listItem->setPosition(pos);
+ }
+ }
+ for (int i = 0; i < sectionCacheSize; ++i) {
+ delete sectionCache[i];
+ sectionCache[i] = 0;
+ }
+}
+
void QQuickListViewPrivate::updateInlineSection(FxListItemSG *listItem)
{
if (!sectionCriteria || !sectionCriteria->delegate())
lastVisibleSection = QString();
updateCurrentSection();
updateStickySections();
+ forceLayout = true;
+ q->polish();
}
void QQuickListViewPrivate::updateCurrentSection()
is scrolled. This is because the view moves to maintain the
highlight within the preferred highlight range (or visible viewport).
- \sa highlight
+ \sa highlight, highlightMoveVelocity
*/
//###Possibly rename these properties, since they are very useful even without a highlight?
/*!
}
/*!
+ \qmlproperty real QtQuick2::ListView::highlightMoveVelocity
\qmlproperty int QtQuick2::ListView::highlightMoveDuration
+ \qmlproperty real QtQuick2::ListView::highlightResizeVelocity
\qmlproperty int QtQuick2::ListView::highlightResizeDuration
- These properties hold the move and resize animation duration of
- the highlight delegate.
+ These properties control the speed of the move and resize animations for the
+ highlight delegate.
\l highlightFollowsCurrentItem must be true for these properties
to have effect.
- The default value for highlightMoveDuration is 150ms and the
- default value for highlightResizeDuration is 250ms.
+ The default value for the velocity properties is 400 pixels/second.
+ The default value for the duration properties is -1, i.e. the
+ highlight will take as much time as necessary to move at the set speed.
+
+ These properties have the same characteristics as a SmoothedAnimation.
\sa highlightFollowsCurrentItem
*/
+qreal QQuickListView::highlightMoveVelocity() const
+{
+ Q_D(const QQuickListView);
+ return d->highlightMoveVelocity;
+}
+
+void QQuickListView::setHighlightMoveVelocity(qreal speed)
+{
+ Q_D(QQuickListView);
+ if (d->highlightMoveVelocity != speed) {
+ d->highlightMoveVelocity = speed;
+ if (d->highlightPosAnimator)
+ d->highlightPosAnimator->velocity = d->highlightMoveVelocity;
+ emit highlightMoveVelocityChanged();
+ }
+}
+
void QQuickListView::setHighlightMoveDuration(int duration)
{
Q_D(QQuickListView);
}
}
+qreal QQuickListView::highlightResizeVelocity() const
+{
+ Q_D(const QQuickListView);
+ return d->highlightResizeVelocity;
+}
+
+void QQuickListView::setHighlightResizeVelocity(qreal speed)
+{
+ Q_D(QQuickListView);
+ if (d->highlightResizeVelocity != speed) {
+ d->highlightResizeVelocity = speed;
+ if (d->highlightSizeAnimator)
+ d->highlightSizeAnimator->velocity = d->highlightResizeVelocity;
+ emit highlightResizeVelocityChanged();
+ }
+}
+
int QQuickListView::highlightResizeDuration() const
{
Q_D(const QQuickListView);
Q_OBJECT
Q_DECLARE_PRIVATE(QQuickListView)
+ Q_PROPERTY(qreal highlightMoveVelocity READ highlightMoveVelocity WRITE setHighlightMoveVelocity NOTIFY highlightMoveVelocityChanged)
+ Q_PROPERTY(qreal highlightResizeVelocity READ highlightResizeVelocity WRITE setHighlightResizeVelocity NOTIFY highlightResizeVelocityChanged)
Q_PROPERTY(int highlightResizeDuration READ highlightResizeDuration WRITE setHighlightResizeDuration NOTIFY highlightResizeDurationChanged)
Q_PROPERTY(qreal spacing READ spacing WRITE setSpacing NOTIFY spacingChanged)
virtual void setHighlightFollowsCurrentItem(bool);
+ qreal highlightMoveVelocity() const;
+ void setHighlightMoveVelocity(qreal);
+
+ qreal highlightResizeVelocity() const;
+ void setHighlightResizeVelocity(qreal);
+
int highlightResizeDuration() const;
void setHighlightResizeDuration(int);
void spacingChanged();
void orientationChanged();
void currentSectionChanged();
+ void highlightMoveVelocityChanged();
+ void highlightResizeVelocityChanged();
void highlightResizeDurationChanged();
void snapModeChanged();
static const int PressAndHoldDelay = 800;
+#ifndef QT_NO_DRAGANDDROP
+
QQuickDrag::QQuickDrag(QObject *parent)
: QObject(parent), _target(0), _axis(XandYAxis), _xmin(-FLT_MAX),
_xmax(FLT_MAX), _ymin(-FLT_MAX), _ymax(FLT_MAX), _active(false), _filterChildren(false)
return new QQuickDragAttached(obj);
}
+#endif // QT_NO_DRAGANDDROP
+
QQuickMouseAreaPrivate::QQuickMouseAreaPrivate()
: enabled(true), hovered(false), pressed(false), longPress(false),
moved(false), dragX(true), dragY(true), stealMouse(false), doubleClick(false), preventStealing(false),
- propagateComposedEvents(false), drag(0)
+ propagateComposedEvents(false)
+#ifndef QT_NO_DRAGANDDROP
+ , drag(0)
+#endif
+#ifndef QT_NO_CURSOR
+ , cursor(0)
+#endif
{
}
QQuickMouseAreaPrivate::~QQuickMouseAreaPrivate()
{
+#ifndef QT_NO_DRAGANDDROP
delete drag;
+#endif
+#ifndef QT_NO_CURSOR
+ delete cursor;
+#endif
}
void QQuickMouseAreaPrivate::init()
else {
d->longPress = false;
d->saveEvent(event);
+#ifndef QT_NO_DRAGANDDROP
if (d->drag)
d->drag->setActive(false);
+#endif
setHovered(true);
d->startScene = event->windowPos();
d->pressAndHoldTimer.start(PressAndHoldDelay, this);
setKeepMouseGrab(d->stealMouse);
event->setAccepted(setPressed(true));
+#ifndef QT_NO_DRAGANDDROP
if (d->drag) {
d->dragX = drag()->axis() & QQuickDrag::XAxis;
d->dragY = drag()->axis() & QQuickDrag::YAxis;
}
+#endif
}
}
else if (!d->hovered && isInside)
setHovered(true);
+#ifndef QT_NO_DRAGANDDROP
if (d->drag && d->drag->target()) {
if (!d->moved) {
d->targetStartPos = d->drag->target()->parentItem()
d->moved = true;
}
+#endif
+
QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, false, d->longPress);
emit mouseXChanged(&me);
me.setPosition(d->lastPos);
} else {
d->saveEvent(event);
setPressed(false);
+#ifndef QT_NO_DRAGANDDROP
if (d->drag)
d->drag->setActive(false);
+#endif
// If we don't accept hover, we need to reset containsMouse.
if (!acceptHoverEvents())
setHovered(false);
bool QQuickMouseArea::childMouseEventFilter(QQuickItem *i, QEvent *e)
{
Q_D(QQuickMouseArea);
- if (!d->pressed && (!d->enabled || !isVisible() || !d->drag || !d->drag->filterChildren()))
+ if (!d->pressed &&
+ (!d->enabled || !isVisible()
+#ifndef QT_NO_DRAGANDDROP
+ || !d->drag || !d->drag->filterChildren()
+#endif
+ )
+ )
return QQuickItem::childMouseEventFilter(i, e);
switch (e->type()) {
case QEvent::MouseButtonPress:
Q_D(QQuickMouseArea);
if (event->timerId() == d->pressAndHoldTimer.timerId()) {
d->pressAndHoldTimer.stop();
+#ifndef QT_NO_DRAGANDDROP
bool dragged = d->drag && d->drag->active();
+#else
+ bool dragged = false;
+#endif
if (d->pressed && dragged == false && d->hovered == true) {
d->longPress = true;
QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, false, d->longPress);
d->hovered = h;
emit hoveredChanged();
d->hovered ? emit entered() : emit exited();
+#ifndef QT_NO_CURSOR
+ if (d->cursor) {
+ if (d->hovered) {
+ canvas()->setCursor(QCursor(*d->cursor));
+ } else {
+ canvas()->unsetCursor();
+ }
+ }
+#endif
}
}
+
/*!
\qmlproperty QtQuick2::Qt::MouseButtons MouseArea::acceptedButtons
This property holds the mouse buttons that the mouse area reacts to.
bool QQuickMouseArea::setPressed(bool p)
{
Q_D(QQuickMouseArea);
+#ifndef QT_NO_DRAGANDDROP
bool dragged = d->drag && d->drag->active();
+#else
+ bool dragged = false;
+#endif
bool isclick = d->pressed == true && p == false && dragged == false && d->hovered == true;
if (d->pressed != p) {
return false;
}
+
+/*!
+ \qmlproperty QtQuick2::Qt::CursorShape MouseArea::cursorShape
+ This property holds the cursor shape for this mouse area.
+ Note that on platforms that do not display a mouse cursor this may have
+ no effect.
+
+ The available cursor shapes are:
+ \list
+ \li Qt.ArrowCursor
+ \li Qt.UpArrowCursor
+ \li Qt.CrossCursor
+ \li Qt.WaitCursor
+ \li Qt.IBeamCursor
+ \li Qt.SizeVerCursor
+ \li Qt.SizeHorCursor
+ \li Qt.SizeBDiagCursor
+ \li Qt.SizeFDiagCursor
+ \li Qt.SizeAllCursor
+ \li Qt.BlankCursor
+ \li Qt.SplitVCursor
+ \li Qt.SplitHCursor
+ \li Qt.PointingHandCursor
+ \li Qt.ForbiddenCursor
+ \li Qt.WhatsThisCursor
+ \li Qt.BusyCursor
+ \li Qt.OpenHandCursor
+ \li Qt.ClosedHandCursor
+ \li Qt.DragCopyCursor
+ \li Qt.DragMoveCursor
+ \li Qt.DragLinkCursor
+ \endlist
+
+ In order to only set a mouse cursor shape for a region without reacting
+ to mouse events set the acceptedButtons to none:
+
+ \code
+ MouseArea { cursorShape: Qt.IBeamCursor; acceptedButtons: Qt.NoButton }
+ \endcode
+
+ The default value is \c Qt.ArrowCursor.
+ \sa Qt::CursorShape
+*/
+
+#ifndef QT_NO_CURSOR
+Qt::CursorShape QQuickMouseArea::cursorShape() const
+{
+ Q_D(const QQuickMouseArea);
+ if (d->cursor)
+ return d->cursor->shape();
+ return Qt::ArrowCursor;
+}
+
+void QQuickMouseArea::setCursorShape(Qt::CursorShape shape)
+{
+ Q_D(QQuickMouseArea);
+ setHoverEnabled(true);
+ delete d->cursor;
+ d->cursor = new QCursor(shape);
+}
+#endif
+
/*!
\qmlproperty Item QtQuick2::MouseArea::drag.target
\qmlproperty bool QtQuick2::MouseArea::drag.active
*/
+#ifndef QT_NO_DRAGANDDROP
QQuickDrag *QQuickMouseArea::drag()
{
Q_D(QQuickMouseArea);
d->drag = new QQuickDrag;
return d->drag;
}
+#endif
QSGNode *QQuickMouseArea::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
{
QT_BEGIN_NAMESPACE
-class QQuickDragAttached;
class QQuickMouseEvent;
+
+#ifndef QT_NO_DRAGANDDROP
+
+class QQuickDragAttached;
class Q_AUTOTEST_EXPORT QQuickDrag : public QObject
{
Q_OBJECT
Q_DISABLE_COPY(QQuickDrag)
};
+#endif // QT_NO_DRAGANDDROP
+
class QQuickMouseAreaPrivate;
class QQuickWheelEvent;
// used in QtLocation
Q_PROPERTY(Qt::MouseButtons pressedButtons READ pressedButtons NOTIFY pressedChanged)
Q_PROPERTY(Qt::MouseButtons acceptedButtons READ acceptedButtons WRITE setAcceptedButtons NOTIFY acceptedButtonsChanged)
Q_PROPERTY(bool hoverEnabled READ hoverEnabled WRITE setHoverEnabled NOTIFY hoverEnabledChanged)
+#ifndef QT_NO_DRAGANDDROP
Q_PROPERTY(QQuickDrag *drag READ drag CONSTANT) //### add flicking to QQuickDrag or add a QQuickFlick ???
+#endif
Q_PROPERTY(bool preventStealing READ preventStealing WRITE setPreventStealing NOTIFY preventStealingChanged)
Q_PROPERTY(bool propagateComposedEvents READ propagateComposedEvents WRITE setPropagateComposedEvents NOTIFY propagateComposedEventsChanged)
+#ifndef QT_NO_CURSOR
+ Q_PROPERTY(Qt::CursorShape cursorShape READ cursorShape WRITE setCursorShape NOTIFY cursorShapeChanged)
+#endif
public:
QQuickMouseArea(QQuickItem *parent=0);
bool hoverEnabled() const;
void setHoverEnabled(bool h);
+#ifndef QT_NO_DRAGANDDROP
QQuickDrag *drag();
+#endif
bool preventStealing() const;
void setPreventStealing(bool prevent);
bool propagateComposedEvents() const;
void setPropagateComposedEvents(bool propagate);
+#ifndef QT_NO_CURSOR
+ Qt::CursorShape cursorShape() const;
+ void setCursorShape(Qt::CursorShape shape);
+#endif
+
Q_SIGNALS:
void hoveredChanged();
void pressedChanged();
void enabledChanged();
void acceptedButtonsChanged();
void hoverEnabledChanged();
+#ifndef QT_NO_CURSOR
+ void cursorShapeChanged();
+#endif
void positionChanged(QQuickMouseEvent *mouse);
void mouseXChanged(QQuickMouseEvent *mouse);
void mouseYChanged(QQuickMouseEvent *mouse);
QT_END_NAMESPACE
+#ifndef QT_NO_DRAGANDDROP
QML_DECLARE_TYPE(QQuickDrag)
QML_DECLARE_TYPEINFO(QQuickDrag, QML_HAS_ATTACHED_PROPERTIES)
+#endif
QML_DECLARE_TYPE(QQuickMouseArea)
QT_END_HEADER
bool doubleClick : 1;
bool preventStealing : 1;
bool propagateComposedEvents : 1;
+#ifndef QT_NO_DRAGANDDROP
QQuickDrag *drag;
+#endif
QPointF startScene;
QPointF targetStartPos;
QPointF lastPos;
Qt::MouseButtons lastButtons;
Qt::KeyboardModifiers lastModifiers;
QBasicTimer pressAndHoldTimer;
+#ifndef QT_NO_CURSOR
+ QCursor *cursor;
+#endif
};
QT_END_NAMESPACE
#include <private/qsgadaptationlayer_p.h>
#include "qquicktextnode_p.h"
#include "qquickimage_p_p.h"
+#include "qquicktextutil_p.h"
+
#include <QtQuick/private/qsgtexture_p.h>
#include <QtQml/qqmlinfo.h>
Q_D(const QQuickText);
QRectF rect = d->layedOutTextRect;
+ rect.moveLeft(QQuickTextUtil::alignedX(rect, width(), d->hAlign));
+ rect.moveTop(QQuickTextUtil::alignedY(rect, height(), d->vAlign));
+
if (d->style != Normal)
rect.adjust(-1, 0, 1, 2);
-
// Could include font max left/right bearings to either side of rectangle.
- qreal w = width();
- switch (d->hAlign) {
- case AlignLeft:
- case AlignJustify:
- break;
- case AlignRight:
- rect.moveLeft(w - rect.width());
- break;
- case AlignHCenter:
- rect.moveLeft((w - rect.width()) / 2);
- break;
- }
-
- qreal h = height();
- switch (d->vAlign) {
- case AlignTop:
- break;
- case AlignBottom:
- rect.moveTop(h - rect.height());
- break;
- case AlignVCenter:
- rect.moveTop((h - rect.height()) / 2);
- break;
- }
-
return rect;
}
d->updateType = QQuickTextPrivate::UpdateNone;
- QRectF bounds = boundingRect();
+ const qreal dy = QQuickTextUtil::alignedY(d->layedOutTextRect, height(), d->vAlign);
// We need to make sure the layout is done in the current thread
#if defined(Q_OS_MAC)
if (d->richText) {
d->ensureDoc();
- node->addTextDocument(bounds.topLeft(), d->extra->doc, color, d->style, styleColor, linkColor);
- } else if (d->elideMode == QQuickText::ElideNone || bounds.width() > 0.) {
+ const qreal dx = QQuickTextUtil::alignedX(d->layedOutTextRect, width(), d->hAlign);
+ node->addTextDocument(QPointF(dx, dy), d->extra->doc, color, d->style, styleColor, linkColor);
+ } else if (d->elideMode == QQuickText::ElideNone || d->layedOutTextRect.width() > 0.) {
int unelidedLineCount = d->lineCount;
if (d->elideLayout)
unelidedLineCount -= 1;
if (unelidedLineCount > 0) {
node->addTextLayout(
- QPoint(0, bounds.y()),
+ QPoint(0, dy),
&d->layout,
color, d->style, styleColor, linkColor,
QColor(), QColor(), -1, -1,
0, unelidedLineCount);
}
if (d->elideLayout)
- node->addTextLayout(QPoint(0, bounds.y()), d->elideLayout, color, d->style, styleColor, linkColor);
+ node->addTextLayout(QPoint(0, dy), d->elideLayout, color, d->style, styleColor, linkColor);
}
foreach (QQuickStyledTextImgTag *img, d->visibleImgTags) {
QQuickPixmap *pix = img->pix;
if (pix && pix->isReady())
- node->addImage(QRectF(img->pos.x(), img->pos.y() + bounds.y(), pix->width(), pix->height()), pix->image());
+ node->addImage(QRectF(img->pos.x(), img->pos.y() + dy, pix->width(), pix->height()), pix->image());
}
return node;
}
d->updateLayout();
}
-
-QString QQuickTextPrivate::anchorAt(const QPointF &mousePos)
+QString QQuickTextPrivate::anchorAt(const QTextLayout *layout, const QPointF &mousePos)
{
- if (styledText) {
- for (int i = 0; i < layout.lineCount(); ++i) {
- QTextLine line = layout.lineAt(i);
- if (line.naturalTextRect().contains(mousePos)) {
- int charPos = line.xToCursor(mousePos.x());
- foreach (const QTextLayout::FormatRange &formatRange, layout.additionalFormats()) {
- if (formatRange.format.isAnchor()
- && charPos >= formatRange.start
- && charPos <= formatRange.start + formatRange.length) {
- return formatRange.format.anchorHref();
- }
+ for (int i = 0; i < layout->lineCount(); ++i) {
+ QTextLine line = layout->lineAt(i);
+ if (line.naturalTextRect().contains(mousePos)) {
+ int charPos = line.xToCursor(mousePos.x(), QTextLine::CursorOnCharacter);
+ foreach (const QTextLayout::FormatRange &formatRange, layout->additionalFormats()) {
+ if (formatRange.format.isAnchor()
+ && charPos >= formatRange.start
+ && charPos < formatRange.start + formatRange.length) {
+ return formatRange.format.anchorHref();
}
- break;
}
+ break;
}
}
return QString();
}
+QString QQuickTextPrivate::anchorAt(const QPointF &mousePos) const
+{
+ Q_Q(const QQuickText);
+ QPointF translatedMousePos = mousePos;
+ translatedMousePos.ry() -= QQuickTextUtil::alignedY(layedOutTextRect, q->height(), vAlign);
+ if (styledText) {
+ QString link = anchorAt(&layout, translatedMousePos);
+ if (link.isEmpty() && elideLayout)
+ link = anchorAt(elideLayout, translatedMousePos);
+ return link;
+ } else if (richText && extra.isAllocated() && extra->doc) {
+ translatedMousePos.rx() -= QQuickTextUtil::alignedX(layedOutTextRect, q->width(), hAlign);
+ return extra->doc->documentLayout()->anchorAt(translatedMousePos);
+ }
+ return QString();
+}
+
bool QQuickTextPrivate::isLinkActivatedConnected()
{
Q_Q(QQuickText);
Q_D(QQuickText);
QString link;
- if (d->isLinkActivatedConnected()) {
- if (d->styledText)
- link = d->anchorAt(event->localPos());
- else if (d->richText) {
- d->ensureDoc();
- link = d->extra->doc->documentLayout()->anchorAt(event->localPos());
- }
- }
+ if (d->isLinkActivatedConnected())
+ link = d->anchorAt(event->localPos());
if (link.isEmpty()) {
event->setAccepted(false);
if (!event->isAccepted())
QQuickItem::mousePressEvent(event);
-
}
+
/*! \internal */
void QQuickText::mouseReleaseEvent(QMouseEvent *event)
{
// ### confirm the link, and send a signal out
QString link;
- if (d->isLinkActivatedConnected()) {
- if (d->styledText)
- link = d->anchorAt(event->localPos());
- else if (d->richText) {
- d->ensureDoc();
- link = d->extra->doc->documentLayout()->anchorAt(event->localPos());
- }
- }
+ if (d->isLinkActivatedConnected())
+ link = d->anchorAt(event->localPos());
if (!link.isEmpty() && d->extra.isAllocated() && d->extra->activeLink == link)
emit linkActivated(d->extra->activeLink);
QRectF setupTextLayout(qreal *const naturalWidth, qreal * const baseline);
void setupCustomLineGeometry(QTextLine &line, qreal &height, int lineOffset = 0);
bool isLinkActivatedConnected();
- QString anchorAt(const QPointF &pos);
+ static QString anchorAt(const QTextLayout *layout, const QPointF &mousePos);
+ QString anchorAt(const QPointF &pos) const;
inline qreal lineHeight() const { return extra.isAllocated() ? extra->lineHeight : 1.0; }
inline int maximumLineCount() const { return extra.isAllocated() ? extra->maximumLineCount : INT_MAX; }
{
Q_D(QQuickTextInput);
if (!d->inLayout) {
- if (newGeometry.width() != oldGeometry.width() && d->wrapMode != NoWrap)
+ if (newGeometry.width() != oldGeometry.width())
d->updateLayout();
updateCursorRectangle();
}
return item;
}
+qreal QQuickTextUtil::alignedX(const QRectF &rect, qreal width, int alignment)
+{
+ qreal x = 0;
+ switch (alignment) {
+ case Qt::AlignLeft:
+ case Qt::AlignJustify:
+ break;
+ case Qt::AlignRight:
+ x = width - rect.width();
+ break;
+ case Qt::AlignHCenter:
+ x = (width - rect.width()) / 2;
+ break;
+ }
+ return x;
+}
+
+qreal QQuickTextUtil::alignedY(const QRectF &rect, const qreal height, int alignment)
+{
+ qreal y = 0;
+ switch (alignment) {
+ case Qt::AlignTop:
+ break;
+ case Qt::AlignBottom:
+ y = height - rect.height();
+ break;
+ case Qt::AlignVCenter:
+ y = (height - rect.height()) / 2;
+ break;
+ }
+ return y;
+}
+
QT_END_NAMESPACE
template <typename Private> static void setCursorDelegate(Private *d, QQmlComponent *delegate);
template <typename Private> static void createCursor(Private *d);
+ static qreal alignedX(const QRectF &rect, qreal width, int alignment);
+ static qreal alignedY(const QRectF &rect, qreal height, int alignment);
+
private:
static QQuickItem *createCursor(
QQmlComponent *component,
QQuickItem *parent,
const QRectF &cursorRectangle,
const char *className);
+
};
template <typename Private>
load(qt_module_config)
+QMAKE_DOCS = $$PWD/doc/qtquick.qdocconf
+QMAKE_DOCS_INDEX = ../../doc
+
# private dependencies
QT += v8-private network
qquicklistmodelworkerscript \
qquickworkerscript \
qqmlbundle \
+ qrcqml \
v4
!contains(QT_CONFIG, no-widgets) {
qmlRegisterType<MyEnumDerivedClass>("Test",1,0,"MyEnumDerivedClass");
qmlRegisterType<MyReceiversTestObject>("Test",1,0,"MyReceiversTestObject");
+
+ qmlRegisterUncreatableType<MyUncreateableBaseClass>("Test", 1, 0, "MyUncreateableBaseClass", "Cannot create MyUncreateableBaseClass");
+ qmlRegisterType<MyCreateableDerivedClass>("Test", 1, 0, "MyCreateableDerivedClass");
+
+ qmlRegisterUncreatableType<MyUncreateableBaseClass,1>("Test", 1, 1, "MyUncreateableBaseClass", "Cannot create MyUncreateableBaseClass");
+ qmlRegisterType<MyCreateableDerivedClass,1>("Test", 1, 1, "MyCreateableDerivedClass");
}
QVariant myCustomVariantTypeConverter(const QString &data)
qreal m_p5;
};
+class MyUncreateableBaseClass : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(bool prop1 READ prop1 WRITE setprop1)
+ Q_PROPERTY(bool prop2 READ prop2 WRITE setprop2 REVISION 1)
+ Q_PROPERTY(bool prop3 READ prop3 WRITE setprop3 REVISION 1)
+public:
+ explicit MyUncreateableBaseClass(bool arg, QObject *parent = 0)
+ : QObject(parent), _prop1(false), _prop2(false), _prop3(false)
+ {
+ }
+
+ bool _prop1;
+ bool prop1() const { return _prop1; }
+ void setprop1(bool p) { _prop1 = p; }
+ bool _prop2;
+ bool prop2() const { return _prop2; }
+ void setprop2(bool p) { _prop2 = p; }
+ bool _prop3;
+ bool prop3() const { return _prop3; }
+ void setprop3(bool p) { _prop3 = p; }
+};
+
+class MyCreateableDerivedClass : public MyUncreateableBaseClass
+{
+ Q_OBJECT
+ Q_PROPERTY(bool prop2 READ prop2 WRITE setprop2 REVISION 1)
+
+public:
+ MyCreateableDerivedClass(QObject *parent = 0)
+ : MyUncreateableBaseClass(true, parent)
+ {
+ }
+};
+
class MyVersion2Class : public QObject
{
Q_OBJECT
void revisions();
void revisionOverloads();
+ void subclassedUncreateableRevision_data();
+ void subclassedUncreateableRevision();
+
void propertyInit();
void remoteLoadCrash();
void signalWithDefaultArg();
}
}
+void tst_qqmllanguage::subclassedUncreateableRevision_data()
+{
+ QTest::addColumn<QString>("version");
+ QTest::addColumn<QString>("prop");
+ QTest::addColumn<bool>("shouldWork");
+
+ QTest::newRow("prop1 exists in 1.0") << "1.0" << "prop1" << true;
+ QTest::newRow("prop2 does not exist in 1.0") << "1.0" << "prop2" << false;
+ QTest::newRow("prop3 does not exist in 1.0") << "1.0" << "prop3" << false;
+
+ QTest::newRow("prop1 exists in 1.1") << "1.1" << "prop1" << true;
+ QTest::newRow("prop2 works because it's re-declared in Derived") << "1.1" << "prop2" << true;
+ QTest::newRow("prop3 only works if the Base REVISION 1 is picked up") << "1.1" << "prop3" << true;
+
+}
+
+void tst_qqmllanguage::subclassedUncreateableRevision()
+{
+ QFETCH(QString, version);
+ QFETCH(QString, prop);
+ QFETCH(bool, shouldWork);
+
+ {
+ QQmlEngine engine;
+ QString qml = QString("import QtQuick 2.0\nimport Test %1\nMyUncreateableBaseClass {}").arg(version);
+ QQmlComponent c(&engine);
+ QTest::ignoreMessage(QtWarningMsg, "QQmlComponent: Component is not ready");
+ c.setData(qml.toUtf8(), QUrl::fromLocalFile(QDir::currentPath()));
+ QObject *obj = c.create();
+ QCOMPARE(obj, static_cast<QObject*>(0));
+ QCOMPARE(c.errors().count(), 1);
+ QCOMPARE(c.errors().first().description(), QString("Cannot create MyUncreateableBaseClass"));
+ }
+
+ QQmlEngine engine;
+ QString qml = QString("import QtQuick 2.0\nimport Test %1\nMyCreateableDerivedClass {\n%3: true\n}").arg(version).arg(prop);
+ QQmlComponent c(&engine);
+ if (!shouldWork)
+ QTest::ignoreMessage(QtWarningMsg, "QQmlComponent: Component is not ready");
+ c.setData(qml.toUtf8(), QUrl::fromLocalFile(QDir::currentPath()));
+ QObject *obj = c.create();
+ if (!shouldWork) {
+ QCOMPARE(obj, static_cast<QObject*>(0));
+ return;
+ }
+
+ QVERIFY(obj);
+ MyUncreateableBaseClass *base = qobject_cast<MyUncreateableBaseClass*>(obj);
+ QVERIFY(base);
+ QCOMPARE(base->property(prop.toLatin1()).toBool(), true);
+ delete obj;
+}
+
void tst_qqmllanguage::initTestCase()
{
QString testdataDir = QFileInfo(QFINDTESTDATA("data")).absolutePath();
<< QString("/main.qml")
<< QByteArray("http://www.example.com/main.qml?type=text/qml&comment=now%20working?");
+ // Although 'text%2Fqml' is pre-encoded, it will be decoded to allow correct QUrl classification
QTest::newRow("preencodedQuery")
<< QByteArray("http://www.example.com/main.qml?type=text%2Fqml&comment=now working%3F")
<< QString("http")
<< QString("/main.qml")
- << QByteArray("http://www.example.com/main.qml?type=text%2Fqml&comment=now%20working%3F");
+ << QByteArray("http://www.example.com/main.qml?type=text/qml&comment=now%20working%3F");
QTest::newRow("encodableFragment")
<< QByteArray("http://www.example.com/main.qml?type=text/qml#start+30000|volume+50%")
void role_mode_data();
void role_mode();
void string_to_list_crash();
+ void empty_element_warning();
+ void empty_element_warning_data();
};
bool tst_qquicklistmodel::compareVariantList(const QVariantList &testList, QVariant object)
e.evaluate();
}
+void tst_qquicklistmodel::empty_element_warning_data()
+{
+ QTest::addColumn<QString>("qml");
+ QTest::addColumn<bool>("warning");
+
+ QTest::newRow("empty") << "import QtQuick 2.0\nListModel {}" << false;
+ QTest::newRow("withid") << "import QtQuick 2.0\nListModel { id: model }" << false;
+ QTest::newRow("emptyElement") << "import QtQuick 2.0\nListModel { ListElement {} }" << true;
+ QTest::newRow("emptyElements") << "import QtQuick 2.0\nListModel { ListElement {} ListElement {} }" << true;
+ QTest::newRow("role1") << "import QtQuick 2.0\nListModel { ListElement {a:1} }" << false;
+ QTest::newRow("role2") << "import QtQuick 2.0\nListModel { ListElement {} ListElement {a:1} ListElement {} }" << false;
+ QTest::newRow("role3") << "import QtQuick 2.0\nListModel { ListElement {} ListElement {a:1} ListElement {b:2} }" << false;
+}
+
+void tst_qquicklistmodel::empty_element_warning()
+{
+ QFETCH(QString, qml);
+ QFETCH(bool, warning);
+
+ if (warning) {
+ QString warningString = QLatin1String("file:dummy.qml:2:1: QML ListModel: All ListElement declarations are empty, no roles can be created unless dynamicRoles is set.");
+ QTest::ignoreMessage(QtWarningMsg, warningString.toLatin1());
+ }
+
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.setData(qml.toUtf8(), QUrl::fromLocalFile(QString("dummy.qml")));
+ QVERIFY(!component.isError());
+
+ QObject *obj = component.create();
+ QVERIFY(obj != 0);
+
+ delete obj;
+}
+
QTEST_MAIN(tst_qquicklistmodel)
#include "tst_qquicklistmodel.moc"
{
QQmlEngine e;
QQmlComponent c(&e, QUrl("qrc:/main.qml"));
- if (c.isError())
- qDebug() << "Error: " << c.errors();
- QEXPECT_FAIL("", "QTBUG-25937", Abort);
QVERIFY(c.isReady());
QObject* o = c.create();
QVERIFY(o);
// not active
QVERIFY(!item->property("active").toBool());
QVERIFY(!item->property("active2").toBool());
- QCOMPARE(item->property("active").toBool(), QGuiApplication::activeWindow() != 0);
+ QCOMPARE(item->property("active").toBool(), QGuiApplication::focusWindow() != 0);
// active
view.show();
QTest::qWait(50);
QEXPECT_FAIL("", "QTBUG-21573", Abort);
QTRY_COMPARE(view.status(), QQuickView::Ready);
- QCOMPARE(item->property("active").toBool(), QGuiApplication::activeWindow() != 0);
- QCOMPARE(item->property("active2").toBool(), QGuiApplication::activeWindow() != 0);
+ QCOMPARE(item->property("active").toBool(), QGuiApplication::focusWindow() != 0);
+ QCOMPARE(item->property("active2").toBool(), QGuiApplication::focusWindow() != 0);
#if 0
// QGuiApplication has no equivalent of setActiveWindow(0). QTBUG-21573
// not active again
QGuiApplication::setActiveWindow(0);
QVERIFY(!item->property("active").toBool());
- QCOMPARE(item->property("active").toBool(), QGuiApplication::activeWindow() != 0);
+ QCOMPARE(item->property("active").toBool(), QGuiApplication::focusWindow() != 0);
#endif
}
#include <QTcpSocket>
#include <QDir>
#include <QPainter>
+#include <QSignalSpy>
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlcomponent.h>
#define SERVER_PORT 14446
#define SERVER_ADDR "http://127.0.0.1:14446"
+Q_DECLARE_METATYPE(QQuickImageBase::Status)
+
class tst_qquickborderimage : public QQmlDataTest
{
void pendingRemoteRequest();
void pendingRemoteRequest_data();
+ void statusChanges();
+ void statusChanges_data();
+
private:
QQmlEngine engine;
};
QTest::newRow("sci file") << "http://localhost/none.sci";
}
+//QTBUG-26155
+void tst_qquickborderimage::statusChanges_data()
+{
+ QTest::addColumn<QString>("source");
+ QTest::addColumn<int>("emissions");
+ QTest::addColumn<bool>("remote");
+ QTest::addColumn<QQuickImageBase::Status>("finalStatus");
+
+ QTest::newRow("localfile") << testFileUrl("colors.png").toString() << 1 << false << QQuickImageBase::Ready;
+ QTest::newRow("nofile") << "" << 0 << false << QQuickImageBase::Null;
+ QTest::newRow("nonexistent") << testFileUrl("thisfiledoesnotexist.png").toString() << 1 << false << QQuickImageBase::Error;
+ QTest::newRow("noprotocol") << QString("thisfiledoesnotexisteither.png") << 2 << false << QQuickImageBase::Error;
+ QTest::newRow("remote") << "http://localhost:14446/colors.png" << 2 << true << QQuickImageBase::Ready;
+}
+
+void tst_qquickborderimage::statusChanges()
+{
+ QFETCH(QString, source);
+ QFETCH(int, emissions);
+ QFETCH(bool, remote);
+ QFETCH(QQuickImageBase::Status, finalStatus);
+
+ TestHTTPServer *server = 0;
+ if (remote) {
+ server = new TestHTTPServer(SERVER_PORT);
+ QVERIFY(server->isValid());
+ server->serveDirectory(dataDirectory(), TestHTTPServer::Delay);
+ }
+
+ QString componentStr = "import QtQuick 2.0\nBorderImage { width: 300; height: 300 }";
+ QQmlComponent component(&engine);
+ component.setData(componentStr.toLatin1(), QUrl(""));
+
+ QQuickBorderImage *obj = qobject_cast<QQuickBorderImage*>(component.create());
+ qRegisterMetaType<QQuickImageBase::Status>();
+ QSignalSpy spy(obj, SIGNAL(statusChanged(QQuickImageBase::Status)));
+ QVERIFY(obj != 0);
+ obj->setSource(source);
+ QTRY_VERIFY(obj->status() == finalStatus);
+ QCOMPARE(spy.count(), emissions);
+
+ delete obj;
+ delete server;
+}
+
QTEST_MAIN(tst_qquickborderimage)
#include "tst_qquickborderimage.moc"
private slots:
void init();
+ void cleanupTestCase();
void items();
void changed();
void inserted_basic();
#endif
}
+void tst_QQuickGridView::cleanupTestCase()
+{
+#ifdef SHARE_VIEWS
+ testForView = QString();
+ delete m_view;
+ m_view = 0;
+#endif
+}
+
void tst_QQuickGridView::items()
{
QQuickView *canvas = createView();
model: testModel
delegate: myDelegate
highlight: myHighlight
+ highlightMoveVelocity: 1000
+ highlightResizeVelocity: 1000
}
}
height: 320
model: 2
delegate: myDelegate
+ highlightMoveVelocity: 1000
+ highlightResizeVelocity: 1000
cacheBuffer: 400
}
Text { anchors.bottom: parent.bottom; text: list.contentY }
height: 320
keyNavigationWraps: testWrap
delegate: myDelegate
+ highlightMoveVelocity: 1000
model: testModel
header: root.showHeader ? headerFooter : null
footer: root.showFooter ? headerFooter : null
height: 320
cacheBuffer: 0
delegate: myDelegate
+ highlightMoveVelocity: 1000
model: testModel
}
}
height: 320
model: visualModel.parts.package
highlight: testObject.invalidHighlight ? invalidHl : myHighlight
+ highlightMoveVelocity: 1000
+ highlightResizeVelocity: 1000
cacheBuffer: testObject.cacheBuffer
header: root.showHeader ? headerFooter : null
footer: root.showFooter ? headerFooter : null
model: testModel
delegate: testObject.animate ? animatedDelegate : myDelegate
highlight: testObject.invalidHighlight ? invalidHl : myHighlight
+ highlightMoveVelocity: 1000
+ highlightResizeVelocity: 1000
cacheBuffer: testObject.cacheBuffer
header: root.showHeader ? headerFooter : null
footer: root.showFooter ? headerFooter : null
--- /dev/null
+import QtQuick 2.0
+
+ListView {
+ width: 240
+ height: 320
+
+ function switchDelegates() {
+ section.delegate = section.delegate === delegate1
+ ? delegate2
+ : delegate1
+ }
+
+ Component {
+ id: delegate1
+
+ Rectangle {
+ objectName: "section1"
+ color: "lightsteelblue"
+ border.width: 1;
+ width: 240
+ height: 25
+
+ Text {
+ anchors.centerIn: parent
+ text: section
+ }
+ }
+ }
+ Component {
+ id: delegate2
+
+ Rectangle {
+ objectName: "section2"
+ color: "yellow"
+ border.width: 1;
+ width: 240
+ height: 50
+
+ Text {
+ anchors.centerIn: parent
+ text: section
+ }
+ }
+ }
+
+ section.property: "modelData"
+ section.delegate: delegate1
+
+ model: 20
+ delegate: Rectangle {
+ objectName: "item"
+ border.width: 1
+ width: 240
+ height: 25
+
+ Text {
+ anchors.centerIn: parent
+ text: modelData
+ }
+ }
+}
}
function switchGroups() {
+ myListView.model.move(0,1,1)
if ("title" === myListView.groupBy)
myListView.groupBy = "genre"
else
myListView.groupBy = "title"
}
+ function switchGrouped() {
+ if ("pageCount" === myListView.groupBy)
+ myListView.groupBy = "genre"
+ else
+ myListView.groupBy = "pageCount"
+ }
+
Component.onCompleted: {
myListView.model = generateModel(myListView)
}
Text { text: parent.y; anchors.right: parent.right }
}
- onGroupByChanged: {
- model.move(0,1,1)
- section.property = groupBy
- }
-
section {
criteria: ViewSection.FullString
delegate: Rectangle { width: 320; height: 25; color: "lightblue"
Text {text: section }
Text { text: parent.y; anchors.right: parent.right }
}
- property: "title"
+ property: myListView.groupBy
}
}
function generateModel(theParent)
{
var books = [
- { "author": "Billy Bob", "genre": "Anarchism", "title": "Frogs and Love" },
- { "author": "Lefty Smith", "genre": "Horror", "title": "Chainsaws for Noobs" }
+ { "author": "Billy Bob", "genre": "Anarchism", "title": "Frogs and Love", "pageCount": 80 },
+ { "author": "Lefty Smith", "genre": "Horror", "title": "Chainsaws for Noobs", "pageCount": 80 }
];
var model = Qt.createQmlObject("import QtQuick 2.0; ListModel {}", theParent);
TESTDATA = data/*
QT += core-private gui-private qml-private quick-private v8-private testlib
-mac: CONFIG += insignificant_test # QTBUG-26244 (exit crash)
private slots:
void init();
+ void cleanupTestCase();
// Test both QListModelInterface and QAbstractItemModel model types
void qListModelInterface_items();
void qListModelInterface_package_items();
void sectionsDelegate();
void sectionsDragOutsideBounds_data();
void sectionsDragOutsideBounds();
+ void sectionsDelegate_headerVisibility();
void sectionPropertyChange();
+ void sectionDelegateChange();
void cacheBuffer();
void positionViewAtIndex();
void resetModel();
#endif
}
+void tst_QQuickListView::cleanupTestCase()
+{
+#ifdef SHARE_VIEWS
+ testForView = QString();
+ delete m_view;
+ m_view = 0;
+#endif
+}
+
template <class T>
void tst_QQuickListView::items(const QUrl &source, bool forceLayout)
{
int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
QTRY_VERIFY(itemCount == 0);
+ QTRY_COMPARE(listview->highlightResizeVelocity(), 1000.0);
+ QTRY_COMPARE(listview->highlightMoveVelocity(), 1000.0);
+
delete canvas;
delete testObject;
}
void tst_QQuickListView::sectionsDelegate()
{
- QSKIP("QTBUG-24395");
-
QQuickView *canvas = createView();
QmlListModel model;
QTRY_COMPARE(item->y(), qreal(i*20*6));
}
- // ensure section header is maintained in view
- listview->setCurrentIndex(20);
- QTRY_VERIFY(listview->contentY() >= 200.0);
- listview->setCurrentIndex(0);
- QTRY_COMPARE(listview->contentY(), 0.0);
-
// change section
model.modifyItem(0, "One", "aaa");
model.modifyItem(1, "Two", "aaa");
releaseView(canvas);
}
+void tst_QQuickListView::sectionsDelegate_headerVisibility()
+{
+ QSKIP("QTBUG-24395");
+
+ QQuickView *canvas = createView();
+
+ QmlListModel model;
+ for (int i = 0; i < 30; i++)
+ model.addItem("Item" + QString::number(i), QString::number(i/5));
+
+ canvas->rootContext()->setContextProperty("testModel", &model);
+ canvas->setSource(testFileUrl("listview-sections_delegate.qml"));
+ canvas->show();
+ qApp->processEvents();
+
+ QQuickListView *listview = findItem<QQuickListView>(canvas->rootObject(), "list");
+ QTRY_VERIFY(listview != 0);
+
+ QQuickItem *contentItem = listview->contentItem();
+ QTRY_VERIFY(contentItem != 0);
+ QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false);
+
+ // ensure section header is maintained in view
+ listview->setCurrentIndex(20);
+ QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false);
+ QTRY_COMPARE(listview->contentY(), 200.0);
+ QTRY_VERIFY(listview->isMoving() == false);
+ listview->setCurrentIndex(0);
+ QTRY_COMPARE(listview->contentY(), 0.0);
+
+ delete canvas;
+}
+
void tst_QQuickListView::sectionsPositioning()
{
QQuickView *canvas = createView();
QTRY_COMPARE(item->y(), qreal(25. + i*75.));
}
+ QMetaObject::invokeMethod(canvas->rootObject(), "switchGrouped");
+ QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false);
+
+ // Confirm items positioned correctly
+ for (int i = 0; i < 2; ++i) {
+ QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
+ QTRY_VERIFY(item);
+ QTRY_COMPARE(item->y(), qreal(25. + i*50.));
+ }
+
+ QMetaObject::invokeMethod(canvas->rootObject(), "switchGrouped");
+ QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false);
+
+ // Confirm items positioned correctly
+ for (int i = 0; i < 2; ++i) {
+ QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
+ QTRY_VERIFY(item);
+ QTRY_COMPARE(item->y(), qreal(25. + i*75.));
+ }
+
+ delete canvas;
+}
+
+void tst_QQuickListView::sectionDelegateChange()
+{
+ QQuickView *canvas = createView();
+
+ canvas->setSource(testFileUrl("sectiondelegatechange.qml"));
+ canvas->show();
+ qApp->processEvents();
+
+ QQuickListView *listview = qobject_cast<QQuickListView *>(canvas->rootObject());
+ QVERIFY(listview != 0);
+
+ QQuickItem *contentItem = listview->contentItem();
+ QVERIFY(contentItem != 0);
+
+ QQUICK_VERIFY_POLISH(listview);
+
+ QVERIFY(findItems<QQuickItem>(contentItem, "section1").count() > 0);
+ QCOMPARE(findItems<QQuickItem>(contentItem, "section2").count(), 0);
+
+ for (int i = 0; i < 3; ++i) {
+ QQuickItem *item = findItem<QQuickItem>(contentItem, "item", i);
+ QTRY_VERIFY(item);
+ QTRY_COMPARE(item->y(), qreal(25. + i*50.));
+ }
+
+ QMetaObject::invokeMethod(canvas->rootObject(), "switchDelegates");
+ QQUICK_VERIFY_POLISH(listview);
+
+ QCOMPARE(findItems<QQuickItem>(contentItem, "section1").count(), 0);
+ QVERIFY(findItems<QQuickItem>(contentItem, "section2").count() > 0);
+
+ for (int i = 0; i < 3; ++i) {
+ QQuickItem *item = findItem<QQuickItem>(contentItem, "item", i);
+ QVERIFY(item);
+ QTRY_COMPARE(item->y(), qreal(50. + i*75.));
+ }
+
delete canvas;
}
QVERIFY(!m_errorCount);
qInstallMsgHandler(old);
+
+ delete canvas;
}
QTEST_MAIN(tst_QQuickListView)
--- /dev/null
+import QtQuick 2.0
+
+Item {
+ id: test
+}
QTest::addColumn<QString>("errorString");
QTest::newRow("source") << "source" << "source: 'Rect120x60.qml'\n" << testFileUrl("Rect120x60.qml") << "";
+ QTest::newRow("source with subdir") << "source" << "source: 'subdir/Test.qml'\n" << testFileUrl("subdir/Test.qml") << "";
+ QTest::newRow("source with encoded subdir literal") << "source" << "source: 'subdir%2fTest.qml'\n" << testFileUrl("subdir/Test.qml") << "";
+ QTest::newRow("source with encoded subdir optimized binding") << "source" << "source: 'subdir' + '%2fTest.qml'\n" << testFileUrl("subdir/Test.qml") << "";
+ QTest::newRow("source with encoded subdir binding") << "source" << "source: encodeURIComponent('subdir/Test.qml')\n" << testFileUrl("subdir/Test.qml") << "";
QTest::newRow("sourceComponent") << "component" << "Component { id: comp; Rectangle { width: 100; height: 50 } }\n sourceComponent: comp\n" << QUrl() << "";
QTest::newRow("invalid source") << "source" << "source: 'IDontExist.qml'\n" << testFileUrl("IDontExist.qml")
<< QString(testFileUrl("IDontExist.qml").toString() + ": File not found");
void letterSpacing();
void wordSpacing();
+ void clickLink_data();
void clickLink();
void implicitSize_data();
mousePressEvent(event);
else if (event->type() == QEvent::MouseButtonRelease)
mouseReleaseEvent(event);
+ else if (event->type() == QEvent::MouseMove)
+ mouseMoveEvent(event);
else
qWarning() << "Trying to send unsupported event type";
}
void linkClicked(QString l) { link = l; }
};
-void tst_qquicktext::clickLink()
+class TextMetrics
{
+public:
+ TextMetrics(const QString &text, Qt::TextElideMode elideMode = Qt::ElideNone)
{
- QString componentStr = "import QtQuick 2.0\nText { text: \"<a href=\\\"http://qt.nokia.com\\\">Hello world!</a>\" }";
- QQmlComponent textComponent(&engine);
- textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
- QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
-
- QVERIFY(textObject != 0);
+ QString adjustedText = text;
+ adjustedText.replace(QLatin1Char('\n'), QChar(QChar::LineSeparator));
+ if (elideMode == Qt::ElideLeft)
+ adjustedText = QChar(0x2026) + adjustedText;
+ else if (elideMode == Qt::ElideRight)
+ adjustedText = adjustedText + QChar(0x2026);
+
+ layout.setText(adjustedText);
+ QTextOption option;
+ option.setUseDesignMetrics(true);
+ layout.setTextOption(option);
- LinkTest test;
- QObject::connect(textObject, SIGNAL(linkActivated(QString)), &test, SLOT(linkClicked(QString)));
+ layout.beginLayout();
+ qreal height = 0;
+ QTextLine line = layout.createLine();
+ while (line.isValid()) {
+ line.setLineWidth(FLT_MAX);
+ line.setPosition(QPointF(0, height));
+ height += line.height();
+ line = layout.createLine();
+ }
+ layout.endLayout();
+ }
- {
- QMouseEvent me(QEvent::MouseButtonPress,QPointF(textObject->x()/2, textObject->y()/2), Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
- static_cast<EventSender*>(static_cast<QQuickItem*>(textObject))->sendEvent(&me);
+ qreal width() const { return layout.maximumWidth(); }
+ QRectF characterRectangle(
+ int position,
+ int hAlign = Qt::AlignLeft,
+ int vAlign = Qt::AlignTop,
+ const QSizeF &bounds = QSizeF(240, 320)) const
+ {
+ qreal dy = 0;
+ switch (vAlign) {
+ case Qt::AlignBottom:
+ dy = bounds.height() - layout.boundingRect().height();
+ break;
+ case Qt::AlignVCenter:
+ dy = (bounds.height() - layout.boundingRect().height()) / 2;
+ break;
+ default:
+ break;
}
- {
- QMouseEvent me(QEvent::MouseButtonRelease,QPointF(textObject->x()/2, textObject->y()/2), Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
- static_cast<EventSender*>(static_cast<QQuickItem*>(textObject))->sendEvent(&me);
+ for (int i = 0; i < layout.lineCount(); ++i) {
+ QTextLine line = layout.lineAt(i);
+ if (position >= line.textStart() + line.textLength())
+ continue;
+ qreal dx = 0;
+ switch (hAlign) {
+ case Qt::AlignRight:
+ dx = bounds.width() - line.naturalTextWidth();
+ break;
+ case Qt::AlignHCenter:
+ dx = (bounds.width() - line.naturalTextWidth()) / 2;
+ break;
+ default:
+ break;
+ }
+ QRectF rect;
+ rect.setLeft(dx + line.cursorToX(position, QTextLine::Leading));
+ rect.setRight(dx + line.cursorToX(position, QTextLine::Trailing));
+ rect.setTop(dy + line.y());
+ rect.setBottom(dy + line.y() + line.height());
+
+ return rect;
}
+ return QRectF();
+ }
+ QTextLayout layout;
+};
- QCOMPARE(test.link, QLatin1String("http://qt.nokia.com"));
- delete textObject;
+typedef QVector<QPointF> PointVector;
+Q_DECLARE_METATYPE(PointVector);
+
+void tst_qquicktext::clickLink_data()
+{
+ QTest::addColumn<QString>("text");
+ QTest::addColumn<qreal>("width");
+ QTest::addColumn<QString>("bindings");
+ QTest::addColumn<PointVector>("mousePositions");
+ QTest::addColumn<QString>("link");
+
+ const QString singleLineText = "this text has a <a href=\\\"http://qt-project.org/single\\\">link</a> in it";
+ const QString singleLineLink = "http://qt-project.org/single";
+ const QString multipleLineText = "this text<br/>has <a href=\\\"http://qt-project.org/multiple\\\">multiple<br/>lines</a> in it";
+ const QString multipleLineLink = "http://qt-project.org/multiple";
+ const QString nestedText = "this text has a <a href=\\\"http://qt-project.org/outer\\\">nested <a href=\\\"http://qt-project.org/inner\\\">link</a> in it</a>";
+ const QString outerLink = "http://qt-project.org/outer";
+ const QString innerLink = "http://qt-project.org/inner";
+
+ {
+ const TextMetrics metrics("this text has a link in it");
+
+ QTest::newRow("click on link")
+ << singleLineText << 240.
+ << ""
+ << (PointVector() << metrics.characterRectangle(18).center())
+ << singleLineLink;
+ QTest::newRow("click on text")
+ << singleLineText << 240.
+ << ""
+ << (PointVector() << metrics.characterRectangle(13).center())
+ << QString();
+ QTest::newRow("drag within link")
+ << singleLineText << 240.
+ << ""
+ << (PointVector()
+ << metrics.characterRectangle(17).center()
+ << metrics.characterRectangle(19).center())
+ << singleLineLink;
+ QTest::newRow("drag away from link")
+ << singleLineText << 240.
+ << ""
+ << (PointVector()
+ << metrics.characterRectangle(18).center()
+ << metrics.characterRectangle(13).center())
+ << QString();
+ QTest::newRow("drag on to link")
+ << singleLineText << 240.
+ << ""
+ << (PointVector()
+ << metrics.characterRectangle(13).center()
+ << metrics.characterRectangle(18).center())
+ << QString();
+ QTest::newRow("click on bottom right aligned link")
+ << singleLineText << 240.
+ << "horizontalAlignment: Text.AlignRight; verticalAlignment: Text.AlignBottom"
+ << (PointVector() << metrics.characterRectangle(18, Qt::AlignRight, Qt::AlignBottom).center())
+ << singleLineLink;
+ QTest::newRow("click on center aligned link")
+ << singleLineText << 240.
+ << "horizontalAlignment: Text.AlignHCenter; verticalAlignment: Text.AlignVCenter"
+ << (PointVector() << metrics.characterRectangle(18, Qt::AlignHCenter, Qt::AlignVCenter).center())
+ << singleLineLink;
+ QTest::newRow("click on rich text link")
+ << singleLineText << 240.
+ << "textFormat: Text.RichText"
+ << (PointVector() << metrics.characterRectangle(18).center())
+ << singleLineLink;
+ QTest::newRow("click on rich text")
+ << singleLineText << 240.
+ << "textFormat: Text.RichText"
+ << (PointVector() << metrics.characterRectangle(13).center())
+ << QString();
+ QTest::newRow("click on bottom right aligned rich text link")
+ << singleLineText << 240.
+ << "textFormat: Text.RichText; horizontalAlignment: Text.AlignRight; verticalAlignment: Text.AlignBottom"
+ << (PointVector() << metrics.characterRectangle(18, Qt::AlignRight, Qt::AlignBottom).center())
+ << singleLineLink;
+ QTest::newRow("click on center aligned rich text link")
+ << singleLineText << 240.
+ << "textFormat: Text.RichText; horizontalAlignment: Text.AlignHCenter; verticalAlignment: Text.AlignVCenter"
+ << (PointVector() << metrics.characterRectangle(18, Qt::AlignHCenter, Qt::AlignVCenter).center())
+ << singleLineLink;
+ } {
+ const TextMetrics metrics("this text has a li", Qt::ElideRight);
+ QTest::newRow("click on right elided link")
+ << singleLineText << metrics.width() + 2
+ << "elide: Text.ElideRight"
+ << (PointVector() << metrics.characterRectangle(17).center())
+ << singleLineLink;
+ } {
+ const TextMetrics metrics("ink in it", Qt::ElideLeft);
+ QTest::newRow("click on left elided link")
+ << singleLineText << metrics.width() + 2
+ << "elide: Text.ElideLeft"
+ << (PointVector() << metrics.characterRectangle(2).center())
+ << singleLineLink;
+ } {
+ const TextMetrics metrics("this text\nhas multiple\nlines in it");
+ QTest::newRow("click on second line")
+ << multipleLineText << 240.
+ << ""
+ << (PointVector() << metrics.characterRectangle(18).center())
+ << multipleLineLink;
+ QTest::newRow("click on third line")
+ << multipleLineText << 240.
+ << ""
+ << (PointVector() << metrics.characterRectangle(25).center())
+ << multipleLineLink;
+ QTest::newRow("drag from second line to third")
+ << multipleLineText << 240.
+ << ""
+ << (PointVector()
+ << metrics.characterRectangle(18).center()
+ << metrics.characterRectangle(25).center())
+ << multipleLineLink;
+ QTest::newRow("click on rich text second line")
+ << multipleLineText << 240.
+ << "textFormat: Text.RichText"
+ << (PointVector() << metrics.characterRectangle(18).center())
+ << multipleLineLink;
+ QTest::newRow("click on rich text third line")
+ << multipleLineText << 240.
+ << "textFormat: Text.RichText"
+ << (PointVector() << metrics.characterRectangle(25).center())
+ << multipleLineLink;
+ QTest::newRow("drag rich text from second line to third")
+ << multipleLineText << 240.
+ << "textFormat: Text.RichText"
+ << (PointVector()
+ << metrics.characterRectangle(18).center()
+ << metrics.characterRectangle(25).center())
+ << multipleLineLink;
+ } {
+ const TextMetrics metrics("this text has a nested link in it");
+ QTest::newRow("click on left outer link")
+ << nestedText << 240.
+ << ""
+ << (PointVector() << metrics.characterRectangle(22).center())
+ << outerLink;
+ QTest::newRow("click on right outer link")
+ << nestedText << 240.
+ << ""
+ << (PointVector() << metrics.characterRectangle(27).center())
+ << outerLink;
+ QTest::newRow("click on inner link left")
+ << nestedText << 240.
+ << ""
+ << (PointVector() << metrics.characterRectangle(23).center())
+ << innerLink;
+ QTest::newRow("click on inner link right")
+ << nestedText << 240.
+ << ""
+ << (PointVector() << metrics.characterRectangle(26).center())
+ << innerLink;
+ QTest::newRow("drag from inner to outer link")
+ << nestedText << 240.
+ << ""
+ << (PointVector()
+ << metrics.characterRectangle(25).center()
+ << metrics.characterRectangle(30).center())
+ << QString();
+ QTest::newRow("drag from outer to inner link")
+ << nestedText << 240.
+ << ""
+ << (PointVector()
+ << metrics.characterRectangle(30).center()
+ << metrics.characterRectangle(25).center())
+ << QString();
+ QTest::newRow("click on left outer rich text link")
+ << nestedText << 240.
+ << "textFormat: Text.RichText"
+ << (PointVector() << metrics.characterRectangle(22).center())
+ << outerLink;
+ QTest::newRow("click on right outer rich text link")
+ << nestedText << 240.
+ << "textFormat: Text.RichText"
+ << (PointVector() << metrics.characterRectangle(27).center())
+ << outerLink;
+ QTest::newRow("click on inner rich text link left")
+ << nestedText << 240.
+ << "textFormat: Text.RichText"
+ << (PointVector() << metrics.characterRectangle(23).center())
+ << innerLink;
+ QTest::newRow("click on inner rich text link right")
+ << nestedText << 240.
+ << "textFormat: Text.RichText"
+ << (PointVector() << metrics.characterRectangle(26).center())
+ << innerLink;
+ QTest::newRow("drag from inner to outer rich text link")
+ << nestedText << 240.
+ << "textFormat: Text.RichText"
+ << (PointVector()
+ << metrics.characterRectangle(25).center()
+ << metrics.characterRectangle(30).center())
+ << QString();
+ QTest::newRow("drag from outer to inner rich text link")
+ << nestedText << 240.
+ << "textFormat: Text.RichText"
+ << (PointVector()
+ << metrics.characterRectangle(30).center()
+ << metrics.characterRectangle(25).center())
+ << QString();
+ }
+}
+
+void tst_qquicktext::clickLink()
+{
+ QFETCH(QString, text);
+ QFETCH(qreal, width);
+ QFETCH(QString, bindings);
+ QFETCH(PointVector, mousePositions);
+ QFETCH(QString, link);
+
+ QString componentStr =
+ "import QtQuick 2.0\nText {\n"
+ "width: " + QString::number(width) + "\n"
+ "height: 320\n"
+ "text: \"" + text + "\"\n"
+ "" + bindings + "\n"
+ "}";
+ QQmlComponent textComponent(&engine);
+ textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
+
+ QVERIFY(textObject != 0);
+
+ LinkTest test;
+ QObject::connect(textObject, SIGNAL(linkActivated(QString)), &test, SLOT(linkClicked(QString)));
+
+ QVERIFY(mousePositions.count() > 0);
+
+ QPointF mousePosition = mousePositions.first();
+ {
+ QMouseEvent me(QEvent::MouseButtonPress, mousePosition, Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
+ static_cast<EventSender*>(static_cast<QQuickItem*>(textObject))->sendEvent(&me);
}
+
+ for (int i = 1; i < mousePositions.count(); ++i) {
+ mousePosition = mousePositions.at(i);
+
+ QMouseEvent me(QEvent::MouseMove, mousePosition, Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
+ static_cast<EventSender*>(static_cast<QQuickItem*>(textObject))->sendEvent(&me);
+ }
+
+ {
+ QMouseEvent me(QEvent::MouseButtonRelease, mousePosition, Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
+ static_cast<EventSender*>(static_cast<QQuickItem*>(textObject))->sendEvent(&me);
+ }
+
+ QCOMPARE(test.link, link);
+
+ delete textObject;
}
void tst_qquicktext::baseUrl()
TextInput {
id: text
objectName: "text"
- anchors.fill: parent
+ anchors.left: parent.left
+ anchors.top: parent.top
+ width: 180
text: top.text
focus: true
QCOMPARE(textInput->effectiveHAlign(), QQuickTextInput::AlignLeft);
platformInputContext.setInputDirection(Qt::RightToLeft);
QCOMPARE(textInput->effectiveHAlign(), QQuickTextInput::AlignRight);
+
+ // changing width keeps right aligned cursor on proper position
+ textInput->setText("");
+ textInput->setWidth(500);
+ QVERIFY(textInput->positionToRectangle(0).x() > textInput->width() / 2);
}
void tst_qquicktextinput::verticalAlignment()
displayFileDialog(&options);
#endif
- QWindow *window = 0;
QQmlEngine *engine = 0;
int exitCode = 0;
if (!options.file.isEmpty()) {
if (!options.versionDetection || checkVersion(options.file)) {
- QQuickView *qxView = new QQuickView();
- engine = qxView->engine();
+ QQuickView qxView;
+ engine = qxView.engine();
for (int i = 0; i < imports.size(); ++i)
engine->addImportPath(imports.at(i));
for (int i = 0; i < bundles.size(); ++i)
engine->addNamedBundle(bundles.at(i).first, bundles.at(i).second);
- window = qxView;
if (options.file.isLocalFile()) {
QFileInfo fi(options.file.toLocalFile());
loadDummyDataFiles(*engine, fi.path());
}
- qxView->setSource(options.file);
+ qxView.setSource(options.file);
QObject::connect(engine, SIGNAL(quit()), QCoreApplication::instance(), SLOT(quit()));
if (options.resizeViewToRootItem)
- qxView->setResizeMode(QQuickView::SizeViewToRootObject);
+ qxView.setResizeMode(QQuickView::SizeViewToRootObject);
else
- qxView->setResizeMode(QQuickView::SizeRootObjectToView);
+ qxView.setResizeMode(QQuickView::SizeRootObjectToView);
if (options.transparent) {
QSurfaceFormat surfaceFormat;
surfaceFormat.setAlphaBufferSize(8);
- qxView->setFormat(surfaceFormat);
- qxView->setClearBeforeRendering(true);
- qxView->setClearColor(QColor(Qt::transparent));
- qxView->setWindowFlags(Qt::FramelessWindowHint);
+ qxView.setFormat(surfaceFormat);
+ qxView.setClearBeforeRendering(true);
+ qxView.setClearColor(QColor(Qt::transparent));
+ qxView.setWindowFlags(Qt::FramelessWindowHint);
}
- window->setWindowFlags(Qt::Window | Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint);
+ qxView.setWindowFlags(Qt::Window | Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint);
+
if (options.fullscreen)
- window->showFullScreen();
+ qxView.showFullScreen();
else if (options.maximized)
- window->showMaximized();
+ qxView.showMaximized();
else
- window->show();
+ qxView.show();
if (options.quitImmediately)
QMetaObject::invokeMethod(QCoreApplication::instance(), "quit", Qt::QueuedConnection);
exitCode = app.exec();
- delete window;
-
#ifdef QML_RUNTIME_TESTING
RenderStatistics::printTotalStats();
#endif