diff options
author | Qt Continuous Integration System <qt-info@nokia.com> | 2010-05-02 23:57:07 (GMT) |
---|---|---|
committer | Qt Continuous Integration System <qt-info@nokia.com> | 2010-05-02 23:57:07 (GMT) |
commit | e970b88cab8f071f3dbaac5f0d520d7196241ab7 (patch) | |
tree | 98ba73d7dd0f0b9127d6d3e116f35351a7ca3fd7 | |
parent | 32ecf8e8ad326ea13ec9a430c99ce540e8b4efac (diff) | |
parent | 2d6258a30f4326b600ccdd7cf1cbf9afcc0a7972 (diff) | |
download | Qt-e970b88cab8f071f3dbaac5f0d520d7196241ab7.zip Qt-e970b88cab8f071f3dbaac5f0d520d7196241ab7.tar.gz Qt-e970b88cab8f071f3dbaac5f0d520d7196241ab7.tar.bz2 |
Merge branch '4.7' of scm.dev.nokia.troll.no:qt/oslo-staging-2 into 4.7-integration
* '4.7' of scm.dev.nokia.troll.no:qt/oslo-staging-2:
Fix project file generation for MSVC 2010
Fix wrong translation and clip for the raster paint-engine on Mac
Return the correct library name in qt_gl_library_name for GLES*
qmake: remove useless evaluation of variables from VS project generators
Fix QT_NO_LIBRARY
Documentation for the Elastic Nodes example.
qmake: fix duplicate linker options in VS project files
Ensured that WA_InputMethodEnabled was set before FocusInEvent was sent.
qmake: fix duplicate compiler options in VS project files
Documentation for the Drag and Drop Robot example.
Fix crash in styles example when running with opengl graphicssystem
Fixed the sizehint for cols/rows in qtableview
QUrl: parsing of host name with an undercore.
Null pointer check
Revert "Try to use multisampled opengl graphicssystem on all platforms"
A small mistake when comparing the flag.
Add unit tests covering most of QVector's API.
Fix crash when CoreText fails to shape text for us
Fix crash when using opengl graphicssystem on desktop
Revert "Revert "Implement heightForWidth support for QTabWidget and QStackedLayout.""
56 files changed, 1886 insertions, 297 deletions
diff --git a/doc/src/examples/dragdroprobot.qdoc b/doc/src/examples/dragdroprobot.qdoc index 413f190..887b254 100644 --- a/doc/src/examples/dragdroprobot.qdoc +++ b/doc/src/examples/dragdroprobot.qdoc @@ -43,9 +43,337 @@ \example graphicsview/dragdroprobot \title Drag and Drop Robot Example - This GraphicsView example shows how to implement drag and drop in - a QGraphicsItem subclass, as well as how to animate items using - QGraphicsItemAnimation and QTimeLine. + This GraphicsView example shows how to implement Drag and Drop in a + QGraphicsItem subclass, as well as how to animate items using Qt's + \l{Animation Framework}. \image dragdroprobot-example.png + + Graphics View provides the QGraphicsScene class for managing and + interacting with a large number of custom-made 2D graphical items derived + from the QGraphicsItem class, and a QGraphicsView widget for visualizing + the items, with support for zooming and rotation. + + This example consists of a \c Robot class, a \c ColorItem class, and a main + function: the \c Robot class describes a simple robot consisting of several + \c RobotPart derived limbs, including \c RobotHead and \c RobotLimb, the \c + ColorItem class provides a draggable colored ellipse, and the \c main() + function provides the main application window. + + We will first review the \c Robot class to see how to assemble the + different parts so that they can be individually rotated and animated using + QPropertyAnimation, and we will then review the \c ColorItem class to + demonstrate how to implement Drag and Drop between items. Finally we will + review the main() function to see how we can put all the pieces together, + to form the final application. + + \section1 Robot Class Definition + + The robot consists of three main classes: the \c RobotHead, the \c + RobotTorso, and the \c RobotLimb, which is used for the upper and lower + arms and legs. All parts derive from the \c RobotPart class, which in turn + inherits \c QGraphicsObject. The \c Robot class itself has no visual + appearance and serves only as a root node for the robot. + + Let's start with the \c RobotPart class declaration. + + \snippet examples/graphicsview/dragdroprobot/robot.h 0 + + This base class inherits QGraphicsObject. QGraphicsObject provides signals + and slots through inheriting QObject, and it also declares QGraphicsItem's + properties using Q_PROPERTY, which makes the properties accessible for + QPropertyAnimation. + + RobotPart also implements the three most important event handlers for + accepting drop events: + \l{QGraphicsItem::dragEnterEvent()}{dragEnterEvent()}, + \l{QGraphicsItem::dragLeaveEvent()}{dragLeaveEvent()}, and + \l{QGraphicsItem::dropEvent()}{dropEvent()}. + + The color is stored as a member variable, along with the \c dragOver + variable, which we will use later to indicate visually that the limb can + accept colors that are is dragged onto it. + + \snippet examples/graphicsview/dragdroprobot/robot.cpp 0 + + \c RobotPart's constructor initializes the dragOver member and sets the + color to Qt::lightGray. In the constructor body we enable support for + accepting drop events by calling + \l{QGraphicsItem::setAcceptDrops()}{setAcceptDrops(true)}. + + The rest of this class's implementation is to support Drag and Drop. + + \snippet examples/graphicsview/dragdroprobot/robot.cpp 1 + + The \l{QGraphicsItem::dragEnterEvent()}{dragEnterEvent()} handler is called + when a Drag and Drop element is dragged into the robot part's area. + + The handler implementation determines whether or not this item as a whole + can accept the mime data assiciated with the incoming drag object. \c + RobotPart provides a base behavior for all parts that accepts color drops. + So if the incoming drag object contains a color, the event is accepted, we + set \c dragOver to \c true and call update() to help provide positive + visual feedback to the user; otherwise the event is ignored, which in turn + allows the event to propagate to parent elements. + + \snippet examples/graphicsview/dragdroprobot/robot.cpp 2 + + The \l{QGraphicsItem::dragLeaveEvent()}{dragLeaveEvent()} handler is called + when a Drag and Drop element is dragged away from the robot part's area. + Our implementation simply resets \e dragOver to false and calls + \l{QGraphicsItem::update()}{update()} to help provide visual feedback that + the drag has left this item. + + \snippet examples/graphicsview/dragdroprobot/robot.cpp 3 + + The \l{QGraphicsItem::dropEvent()}{dropEvent()} handler is called when a + Drag and Drop element is dropped onto an item (i.e., when the mouse button + is released over the item while dragging). + + We reset \c dragOver to false, assign the item's new color, and call + \l{QGraphicsItem::update()}{update()}. + + The declaration and implementation of \c RobotHead, \c RobotTorso, and \c + RobotLimb are practically identical. We will review \c RobotHead in detail, + as this class has one minor difference, and leave the other classes as an + exercise for the reader. + + \snippet examples/graphicsview/dragdroprobot/robot.h 1 + + The \c RobotHead class inherits \c RobotPart and provides the necessary + implementations of \l{QGraphicsItem::boundingRect()}{boundingRect()} and + \l{QGraphicsItem::paint()}{paint()}. It also reimplements + \l{QGraphicsItem::dragEnterEvent()}{dragEnterEvent()} and dropEvent() to + provide special handling of image drops. + + The class contains a private pixmap member that we can use to implement + support for accepting image drops. + + \snippet examples/graphicsview/dragdroprobot/robot.cpp 4 + + \c RobotHead has a rather plain constructor that simply forwards to + \c RobotPart's constructor. + + \snippet examples/graphicsview/dragdroprobot/robot.cpp 5 + + The \l{QGraphicsItem::boundingRect()}{boundingRect()} reimplementation + returns the extents for the head. Because we want the center of rotation to + be the bottom center of the item, we have chosen a bounding rectangle that + starts at (-15, -50) and extends to 30 units wide and 50 units tall. When + rotating the head, the "neck" will stay still while the top of the head + tilts from side to side. + + \snippet examples/graphicsview/dragdroprobot/robot.cpp 6 + + In \l{QGraphicsItem::paint()}{paint()} we draw the actual head. The + implementation is split into two sections; if an image has been dropped + onto the head, we draw the image, otherwise we draw a round rectangular + robot head with simple vector graphics. + + For performance reasons, depending on the complexity of what is painted, it + can often be faster to draw the head as an image rather than using a + sequence of vector operations. + + \snippet examples/graphicsview/dragdroprobot/robot.cpp 7 + + The robot head can accept image drops. In order to support this, its + reimplementation of \l{QGraphicsItem::dragEnterEvent()}{dragEnterEvent()} + checks if the drag object contains image data, and if it does, then the + event is accepted. Otherwise we fall back to the base \c RobotPart + implementation. + + \snippet examples/graphicsview/dragdroprobot/robot.cpp 8 + + To follow up on image support, we must also implement + \l{QGraphicsItem::dropEvent()}{dropEvent()}. We check if the drag object + contains image data, and if it does, we store this data as a member pixmap + and call \l{QGraphicsItem::update()}{update()}. This pixmap is used inside + the \l{QGraphicsItem::paint()}{paint()} implementation that we reviewed + before. + + \c RobotTorso and \c RobotLimb are similar to \c RobotHead, so let's + skip directly to the \c Robot class. + + \snippet examples/graphicsview/dragdroprobot/robot.h 4 + + The \c Robot class also inherits \c RobotPart, and like the other parts it + also implements \l{QGraphicsItem::boundingRect()}{boundingRect()} and + \l{QGraphicsItem::paint()}{paint()}. It provides a rather special + implementation, though: + + \snippet examples/graphicsview/dragdroprobot/robot.cpp 9 + + Because the \c Robot class is only used as a base node for the rest of the + robot, it has no visual representation. Its + \l{QGraphicsItem::boundingRect()}{boundingRect()} implementation can + therefore return a null QRectF, and its paint() function does nothing. + + \snippet examples/graphicsview/dragdroprobot/robot.cpp 10 + + The constuctor starts by setting the flag + \l{QGraphicsItem::ItemHasNoContents}{ItemHasNoContents}, which is a minor + optimization for items that have no visual appearance. + + We then construct all the robot parts (head, torso, and upper/lower arms + and legs). The stacking order is very important, and we use the + parent-child hierarchy to ensure the elements rotate and move properly. We + construct the torso first, as this is the root element. We then construct + the head and pass the torso to \c HeadItem's constructor. This will make + the head a child of the torso; if you rotate the torso, the head will + follow. The same pattern is applied to the rest of the limbs. + + \snippet examples/graphicsview/dragdroprobot/robot.cpp 11 + + Each robot part is carefully positioned. For example, the upper left arm is + moved precisely to the top-left area of the torso, and the upper right arm + is moved to the top-right area. + + \snippet examples/graphicsview/dragdroprobot/robot.cpp 12 + + The next section creates all animation objects. This snippet shows the two + animations that operate on the head's scale and rotation. The two + QPropertyAnimation instances simply set the object, property, and + respective start and end values. + + All animations are controlled by one top-level parallel animation group. + The scale and rotation animations are added to this group. + + The rest of the animations are defined in a similar way. + + \snippet examples/graphicsview/dragdroprobot/robot.cpp 13 + + Finally we set an easing curve and duration on each animation, ensure the + toplevel animation group loops forever, and start the toplevel animation. + + \section1 ColorItem Class Definition + + The \c ColorItem class represents a circular item that can be pressed to + drag colors onto robot parts. + + \snippet examples/graphicsview/dragdroprobot/coloritem.h 0 + + This class is very simple. It does not use animations, and has no need for + properties nor signals and slots, so to save resources, it's most natural + that it inherits QGraphicsItem (as opposed to QGraphicsObject). + + It declares the mandatory \l{QGraphicsItem::boundingRect()}{boundingRect()} + and \l{QGraphicsItem::paint()}{paint()} functions, and adds + reimplementations of + \l{QGraphicsItem::mousePressEvent()}{mousePressEvent()}, + \l{QGraphicsItem::mouseMoveEvent()}{mouseMoveEvent()}, and + \l{QGraphicsItem::mouseReleaseEvent()}{mouseReleaseEvent()}. It contains a + single private color member. + + Let's take a look at its implementation. + + \snippet examples/graphicsview/dragdroprobot/coloritem.cpp 0 + + \c ColorItem's constructor assigns an opaque random color to its color + member by making use of qrand(). For improved usability, it assigns a + tooltip that provides a useful hint to the user, and it also sets a + suitable cursor. This ensures that the cursor will chance to + Qt::OpenHandCursor when the mouse pointer hovers over the item. + + Finally, we call + \l{QGraphicsItem::setAcceptedMouseButtons()}{setAcceptedMouseButtons()} to + ensure that this item can only process Qt::LeftButton. This simplifies the + mouse event handlers greatly, as we can always assume that only the left + mouse button is pressed and released. + + \snippet examples/graphicsview/dragdroprobot/coloritem.cpp 1 + + The item's bounding rect is a fixed 30x30 units centered around the item's + origin (0, 0), and adjusted by 0.5 units in all directions to allow a + scalable pen to draw its outline. For a final visual touch the bounds + also compensate with a few units down and to the right to make room + for a simple dropshadow. + + \snippet examples/graphicsview/dragdroprobot/coloritem.cpp 2 + + The \l{QGraphicsItem::paint()}{paint()} implementation draws an ellipse + with a 1-unit black outline, a plain color fill, and a dark gray + dropshadow. + + \snippet examples/graphicsview/dragdroprobot/coloritem.cpp 3 + + The \l{QGraphicsItem::mousePressEvent()}{mousePressEvent()} handler is + called when you press the mouse button inside the item's area. Our + implementation simply sets the cursor to Qt::ClosedHandCursor. + + \snippet examples/graphicsview/dragdroprobot/coloritem.cpp 4 + + The \l{QGraphicsItem::mouseReleaseEvent()}{mouseReleaseEvent()} handler is + called when you release the mouse button after having pressed it inside an + item's area. Our implementation sets the cursor back to Qt::OpenHandCursor. + The mouse press and release event handlers together provide useful visual + feedback to the user: when you move the mouse pointer over a \c CircleItem, + the cursor changes to an open hand. Pressing the item will show a closed + hand cursor. Releasing will restore to an open hand cursor again. + + \snippet examples/graphicsview/dragdroprobot/coloritem.cpp 5 + + The \l{QGraphicsItem::mouseMoveEvent()}{mouseMoveEvent()} handler is called + when you move the mouse around after pressing the mouse button inside the + \c ColorItem's area. This implementation provides the most important piece + of logic for \c CircleItem: the code that starts and manages drags. + + The implementation starts by checking if the mouse has been dragged far + enough to eliminate mouse jitter noise. We only want to start a drag if the + mouse has been dragged farther than the application start drag distance. + + Continuing, we create a QDrag object, passing the event + \l{QGraphicsSceneEvent::widget()}{widget} (i.e., the QGraphicsView + viewport) to its constructor. Qt will ensure that this object is deleted at + the right time. We also create a QMimeData instance that can contain our + color or image data, and assign this to the drag object. + + \snippet examples/graphicsview/dragdroprobot/coloritem.cpp 6 + + This snippet has a somewhat random outcome: once in a while, a special + image is assigned to the drag object's mime data. The pixmap is also + assiged as the drag object's pixmap. This will ensure that you can see the + image that is being dragged as a pixmap under the mouse cursor. + + \snippet examples/graphicsview/dragdroprobot/coloritem.cpp 7 + + Otherwise, and this is the most common outcome, a simple color is assigned + to the drag object's mime data. We render this \c ColorItem into a new + pixmap to give the user visual feedback that the color is being "dragged". + + \snippet examples/graphicsview/dragdroprobot/coloritem.cpp 8 + + Finally we execute the drag. QDrag::exec() will reenter the event loop, and + only exit if the drag has either been dropped, or canceled. In any case we + reset the cursor to Qt::OpenHandCursor. + + \section1 The main() Function + + Now that the \c Robot and \c ColorItem classes are complete, we can put all + the pieces together inside the main() function. + + \snippet examples/graphicsview/dragdroprobot/main.cpp 0 + + We start off by constructing QApplication, and initializing the random + number generator. This ensures that the color items have different colors + every time the application starts. + + \snippet examples/graphicsview/dragdroprobot/main.cpp 1 + + We construct a fixed size scene, and create 10 \c ColorItem instances + arranged in a circle. Each item is added to the scene. + + In the center of this circle we create one \c Robot instance. The + robot is scaled and moved up a few units. It is then added to the scene. + + \snippet examples/graphicsview/dragdroprobot/main.cpp 2 + + Finally we create a QGraphicsView window, and assign the scene to it. + + For increased visual quality, we enable antialiasing. We also choose to use + bounding rectangle updates to simplify visual update handling. + The view is given a fixed sand-colored background, and a window title. + + We then show the view. The animations start immediately after + control enters the event loop. */ + diff --git a/doc/src/examples/elasticnodes.qdoc b/doc/src/examples/elasticnodes.qdoc index f7b1c37..edc62d8 100644 --- a/doc/src/examples/elasticnodes.qdoc +++ b/doc/src/examples/elasticnodes.qdoc @@ -43,7 +43,396 @@ \example graphicsview/elasticnodes \title Elastic Nodes Example - This GraphicsView example shows how to implement edges between nodes in a graph. + This GraphicsView example shows how to implement edges between nodes in a + graph, with basic interaction. You can click to drag a node around, and + zoom in and out using the mouse wheel or the keyboard. Hitting the space + bar will randomize the nodes. The example is also resolution independent; + as you zoom in, the graphics remain crisp. \image elasticnodes-example.png + + Graphics View provides the QGraphicsScene class for managing and + interacting with a large number of custom-made 2D graphical items derived + from the QGraphicsItem class, and a QGraphicsView widget for visualizing + the items, with support for zooming and rotation. + + This example consists of a \c Node class, an \c Edge class, a \c + GraphWidget test, and a \c main function: the \c Node class represents + draggable yellow nodes in a grid, the \c Edge class represents the lines + between the nodes, the \c GraphWidget class represents the application + window, and the \c main() function creates and shows this window, and runs + the event loop. + + \section1 Node Class Definition + + The \c Node class serves three purposes: + + \list + \o Painting a yellow gradient "ball" in two states: sunken and raised. + \o Managing connections to other nodes. + \o Calculating forces pulling and pushing the nodes in the grid. + \endlist + + Let's start by looking at the \c Node class declaration. + + \snippet examples/graphicsview/elasticnodes/node.h 0 + + The \c Node class inherits QGraphicsItem, and reimplements the two + mandatory functions \l{QGraphicsItem::boundingRect()}{boundingRect()} and + \l{QGraphicsItem::paint()}{paint()} to provide its visual appearance. It + also reimplements \l{QGraphicsItem::shape()}{shape()} to ensure its hit + area has an elliptic shape (as opposed to the default bounding rectangle). + + For edge management purposes the node provides a simple API for adding + edges to a node, and for listing all connected edges. + + The \l{QGraphicsItem::advance()}{advance()} reimplementation is called + whenever the scene's state advances by one step. The calculateForces() + function is called to calculate the forces that push and pull on this node + and its neighbors. + + The \c Node class also reimplements + \l{QGraphicsItem::itemChange()}{itemChange()} to react to state changes (in + this case, position changes), and + \l{QGraphicsItem::mousePressEvent()}{mousePressEvent()} and + \l{QGraphicsItem::mouseReleaseEvent()}{mouseReleaseEvent()} to update the + item's visual appearance. + + We will start reviewing the \c Node implementation by looking at its + constructor: + + \snippet examples/graphicsview/elasticnodes/node.cpp 0 + + In the constructor, we set the + \l{QGraphicsItem::ItemIsMovable}{ItemIsMovable} flag to allow the item to + move in response to mouse dragging, and + \l{QGraphicsItem::ItemSendsGeometryChanges}{ItemSendsGeometryChanges} to + enable \l{QGraphicsItem::itemChange()}{itemChange()} notifications for + position and transformation changes. We also enable + \l{QGraphicsItem::DeviceCoordinateCache}{DeviceCoordinateCache} to speed up + rendering performance. To ensure that the nodes are always stacked on top + of edges, we finally set the item's Z value to -1. + + \c Node's constructor takes a \c GraphWidget pointer and stores this as a + member variable. We will revisit this pointer later on. + + \snippet examples/graphicsview/elasticnodes/node.cpp 1 + + The addEdge() function adds the input edge to a list of attached edges. The + edge is then adjusted so that the end points for the edge match the + positions of the source and destination nodes. + + The edges() function simply returns the list of attached edges. + + \snippet examples/graphicsview/elasticnodes/node.cpp 2 + + The \e calculateForces() function implements the elastic forces effect that + pulls and pushes on nodes in the grid. In addition to this algorithm, the + user can move one node around with the mouse. Because we do not want the + two to interfere, we start by checking if this \c Node is the current mouse + grabber item (i.e., QGraphicsScene::mouseGrabberItem()). Because we need to + find all neighboring (but not necessarily connected) nodes, we also make + sure the item is part of a scene in the first place. + + \snippet examples/graphicsview/elasticnodes/node.cpp 3 + + The algorithm has two steps: the first is to calculate the forces that push + the nodes apart, and the second is to subtract the forces that pull the + nodes together. First we need to find all the nodes in the graph. We call + QGraphicsScene::items() to find all items in the scene, and then use + qgraphicsitem_cast() to look for \c Node instances. + + We make use of \l{QGraphicsItem::mapFromItem()}{mapFromItem()} to create a + vector pointing from this node to each other node, in \l{The Graphics View + Coordinate System}{local coordinates}. We use the decomposed components of + this vector to determine the direction and strength of force that apply to + the node. The forces are added up for each node, and weighted so that the + closest nodes are given the strongest force. The sum of all forces are + stored in \e xvel (X-velocity) and \e yvel (Y-velocity). + + \snippet examples/graphicsview/elasticnodes/node.cpp 4 + + The edges between the nodes represent the forces that pull the nodes + together. By visiting each edge that is connected to this node, we can use + a similar approach as above to find the direction and strength of all + forces. These forces are subtracted from \e xvel and \e yvel. + + \snippet examples/graphicsview/elasticnodes/node.cpp 5 + + In theory, the sum of pushing and pulling forces should stabilize to + precisely 0. In practise, however, they never do. To circumvent errors in + numerical precision, we simply force the sum of forces to be 0 when they + are less than 0.1. + + \snippet examples/graphicsview/elasticnodes/node.cpp 6 + + The final step of \e calculateForces() determines the node's new position. + We add the force to the node's current position. We also make sure the new + position stays inside of our defined boundaries. We don't actually move the + item in this function; that's done in a separate step, from \e advance(). + + \snippet examples/graphicsview/elasticnodes/node.cpp 7 + + The \e advance() function updates the item's current position. It is called + from \e GraphWidget::timerEvent(). If the node's position changed, the + function returns true; otherwise false is returned. + + \snippet examples/graphicsview/elasticnodes/node.cpp 8 + + The \e Node's bounding rectangle is a 20x20 sized rectangle centered around + its origin (0, 0), adjusted by 2 units in all directions to compensate for + the node's outline stroke, and by 3 units down and to the right to make + room for a simple drop shadow. + + \snippet examples/graphicsview/elasticnodes/node.cpp 9 + + The shape is a simple ellipse. This ensures that you must click inside the + node's elliptic shape in order to drag it around. You can test this effect + by running the example, and zooming far enough in so that the nodes become + very large. Without reimplementing \l{QGraphicsItem::shape()}{shape()}, the + item's hit area would be identical to its bounding rectangle (i.e., + rectangular). + + \snippet examples/graphicsview/elasticnodes/node.cpp 10 + + This function implements the node's painting. We start by drawing a simple + dark gray elliptic drop shadow at (-7, -7), that is, (3, 3) units down and + to the right. + + We then draw an ellipse with a radial gradient fill. This fill is either + Qt::yellow to Qt::darkYellow when raised, or the opposite when sunken. In + sunken state we also shift the center and focal point by (3, 3) to + emphasize the impression that something has been pushed down. + + Drawing filled ellipses with gradients can be quite slow, especially when + using complex gradients such as QRadialGradient. This is why this example + uses \l{QGraphicsItem::DeviceCoordinateCache}{DeviceCoordinateCache}, a + simple yet effective measure that prevents unnecessary redrawing. + + \snippet examples/graphicsview/elasticnodes/node.cpp 11 + + We reimplement \l{QGraphicsItem::itemChange()}{itemChange()} to adjust the + position of all connected edges, and to notify the scene that an item has + moved (i.e., "something has happened"). This will trigger new force + calculations. + + This notification is the only reason why the nodes need to keep a pointer + back to the \e GraphWidget. Another approach could be to provide such + notification using a signal; in such case, \e Node would need to inherit + from QGraphicsObject. + + \snippet examples/graphicsview/elasticnodes/node.cpp 12 + + Because we have set the \l{QGraphicsItem::ItemIsMovable}{ItemIsMovable} + flag, we don't need to implement the logic that moves the node according to + mouse input; this is already provided for us. We still need to reimplement + the mouse press and release handlers though, to update the nodes' visual + appearance (i.e., sunken or raised). + + \section1 Edge Class Definition + + The \e Edge class represents the arrow-lines between the nodes in this + example. The class is very simple: it maintains a source- and destination + node pointer, and provides an \e adjust() function that makes sure the line + starts at the position of the source, and ends at the position of the + destination. The edges are the only items that change continuously as + forces pull and push on the nodes. + + Let's take a look at the class declaration: + + \snippet examples/graphicsview/elasticnodes/edge.h 0 + + \e Edge inherits from QGraphicsItem, as it's a simple class that has no use + for signals, slots, and properties (compare to QGraphicsObject). + + The constructor takes two node pointers as input. Both pointers are + mandatory in this example. We also provide get-functions for each node. + + The \e adjust() function repositions the edge, and the item also implements + \l{QGraphicsItem::boundingRect()}{boundingRect()} and + \{QGraphicsItem::paint()}{paint()}. + + We will now review its implementation. + + \snippet examples/graphicsview/elasticnodes/edge.cpp 0 + + The \e Edge constructor initializes its arrowSize data member to 10 units; + this determines the size of the arrow which is drawn in + \l{QGraphicsItem::paint()}{paint()}. + + In the constructor body, we call + \l{QGraphicsItem::setAcceptedMouseButtons()}{setAcceptedMouseButtons(0)}. + This ensures that the edge items are not considered for mouse input at all + (i.e., you cannot click the edges). Then, the source and destination + pointers are updated, this edge is registered with each node, and we call + \e adjust() to update this edge's start end end position. + + \snippet examples/graphicsview/elasticnodes/edge.cpp 1 + + The source and destination get-functions simply return the respective + pointers. + + \snippet examples/graphicsview/elasticnodes/edge.cpp 2 + + In \e adjust(), we define two points: \e sourcePoint, and \e destPoint, + pointing at the source and destination nodes' origins respectively. Each + point is calculated using \l{The Graphics View Coordinate System}{local + coordinates}. + + We want the tip of the edge's arrows to point to the exact outline of the + nodes, as opposed to the center of the nodes. To find this point, we first + decompose the vector pointing from the center of the source to the center + of the destination node into X and Y, and then normalize the components by + dividing by the length of the vector. This gives us an X and Y unit delta + that, when multiplied by the radius of the node (which is 10), gives us the + offset that must be added to one point of the edge, and subtracted from the + other. + + If the length of the vector is less than 20 (i.e., if two nodes overlap), + then we fix the source and destination pointer at the center of the source + node. In practise this case is very hard to reproduce manually, as the + forces between the two nodes is then at its maximum. + + It's important to notice that we call + \l{QGraphicsItem::prepareGeometryChange()}{prepareGeometryChange()} in this + function. The reason is that the variables \e sourcePoint and \e destPoint + are used directly when painting, and they are returned from the + \l{QGraphicsItem::boundingRect()}{boundingRect()} reimplementation. We must + always call + \l{QGraphicsItem::prepareGeometryChange()}{prepareGeometryChange()} before + changing what \l{QGraphicsItem::boundingRect()}{boundingRect()} returns, + and before these variables can be used by + \l{QGraphicsItem::paint()}{paint()}, to keep Graphics View's internal + bookkeeping clean. It's safest to call this function once, immediately + before any such variable is modified. + + \snippet examples/graphicsview/elasticnodes/edge.cpp 3 + + The edge's bounding rectangle is defined as the smallest rectangle that + includes both the start and the end point of the edge. Because we draw an + arrow on each edge, we also need to compensate by adjusting with half the + arrow size and half the pen width in all directions. The pen is used to + draw the outline of the arrow, and we can assume that half of the outline + can be drawn outside of the arrow's area, and half will be drawn inside. + + \snippet examples/graphicsview/elasticnodes/edge.cpp 4 + + We start the reimplementation of \l{QGraphicsItem::paint()}{paint()} by + checking a few preconditions. Firstly, if either the source or destination + node is not set, then we return immediately; there is nothing to draw. + + At the same time, we check if the length of the edge is approximately 0, + and if it is, then we also return. + + \snippet examples/graphicsview/elasticnodes/edge.cpp 5 + + We draw the line using a pen that has round joins and caps. If you run the + example, zoom in and study the edge in detail, you will see that there are + no sharp/square edges. + + \snippet examples/graphicsview/elasticnodes/edge.cpp 6 + + We proceed to drawing one arrow at each end of the edge. Each arrow is + drawn as a polygon with a black fill. The coordinates for the arrow are + determined using simple trigonometry. + + \section1 GraphWidget Class Definition + + \e GraphWidget is a subclass of QGraphicsView, which provides the main + window with scrollbars. + + \snippet examples/graphicsview/elasticnodes/graphwidget.h 0 + + It provides a basic constructor that initializes the scene, an \e + itemMoved() function to notify changes in the scene's node graph, a few + event handlers, a reimplementation of + \l{QGraphicsView::drawBackground()}{drawBackground()}, and a helper + function for scaling the view by mouse or keyboard. + + \snippet examples/graphicsview/elasticnodes/graphwidget.cpp 0 + + \e GraphicsWidget's constructor creates the scene, and because most items + move around most of the time, it sets QGraphicsScene::NoIndex. Then the + scene gets a fixed \l{QGraphicsScene::sceneRect}{scene rectangle}. + The scene is then assigned to the \e GraphWidget view. + + The view enables QGraphicsView::CacheBackground to cache rendering of its + static and somewhat complex background. Because the graph renders a close + collection of small items that all move around, it's unnecessary for + Graphics View to waste time finding accurate update regions, so we set the + QGraphicsView::BoundingRectViewportUpdate viewport update mode. The default + would work fine, but this mode is noticably faster for this example. + + To improve rendering quality, we set QPainter::Antialiasing. + + The transformation anchor decides how the view should scroll when you + transform the view, or in our case, when we zoom in or out. We have chosen + QGraphicsView::AnchorUnderMouse, which centers the view on the point under + the mouse cursor. This makes it easy to zoom towards a point in the scene + by moving the mouse over it, and then rolling the mouse wheel. + + Finally we give the window a minimum size that matches the scene's default + size, and set a suitable window title. + + \snippet examples/graphicsview/elasticnodes/graphwidget.cpp 1 + + The last part of the constructor creates the grid of nodes and edges, and + gives each node an initial position. + + \snippet examples/graphicsview/elasticnodes/graphwidget.cpp 2 + + \e GraphWidget is notified of node movement through this \e itemMoved() + function. Its job is simply to restart the main timer in case it's not + running already. The timer is designed to stop when the graph stabilizes, + and start once it's unstable again. + + \snippet examples/graphicsview/elasticnodes/graphwidget.cpp 3 + + This is \e GraphWidget's key event handler. The arrow keys move the center + node around, the '+' and '-' keys zoom in and out by calling \e + scaleView(), and the enter and space keys randomize the positions of the + nodes. All other key events (e.g., page up and page down) are handled by + QGraphicsView's default implementation. + + \snippet examples/graphicsview/elasticnodes/graphwidget.cpp 4 + + The timer event handler's job is to run the whole force calculation + machinery as a smooth animation. Each time the timer is triggered, the + handler will find all nodes in the scene, and call \e + Node::calculateForces() on each node, one at a time. Then, in a final step + it will call \e Node::advance() to move all nodes to their new positions. + By checking the return value of \e advance(), we can decide if the grid + stabilized (i.e., no nodes moved). If so, we can stop the timer. + + \snippet examples/graphicsview/elasticnodes/graphwidget.cpp 5 + + In the wheel event handler, we convert the mouse wheel delta to a scale + factor, and pass this factor to \e scaleView(). This approach takes into + account the speed that the wheel is rolled. The faster you roll the mouse + wheel, the faster the view will zoom. + + \snippet examples/graphicsview/elasticnodes/graphwidget.cpp 6 + + The view's background is rendered in a reimplementation of + QGraphicsView::drawBackground(). We draw a large rectangle filled with a + linear gradient, with a drop shadow, and then render text in top. The text + is rendered twice to give a similar simple drop-shadow effect. + + This background rendering is quite expensive; this is why the view enables + QGraphicsView::CacheBackground. + + \snippet examples/graphicsview/elasticnodes/graphwidget.cpp 7 + + The \e scaleView() helper function checks that the scale factor stays + within certain limits (i.e., you cannot zoom too far in nor too far out), + and then applies this scale. + + \section1 The main() Function + + In contrast to the complexity of the rest of this example, the \e main() + function is very simple: We create a QApplication instance, seed the + randomizer using qsrand(), and then create and show an instance of \e + GraphWidget. Because all nodes in the grid are moved initially, the \e + GraphWidget timer will start immediately after control has returned to the + event loop. */ diff --git a/doc/src/getting-started/examples.qdoc b/doc/src/getting-started/examples.qdoc index 071a107..542f672 100644 --- a/doc/src/getting-started/examples.qdoc +++ b/doc/src/getting-started/examples.qdoc @@ -649,8 +649,8 @@ \list \o \l{graphicsview/collidingmice}{Colliding Mice}\raisedaster \o \l{graphicsview/diagramscene}{Diagram Scene}\raisedaster - \o \l{graphicsview/dragdroprobot}{Drag and Drop Robot} - \o \l{graphicsview/elasticnodes}{Elastic Nodes} + \o \l{graphicsview/dragdroprobot}{Drag and Drop Robot}\raisedaster + \o \l{graphicsview/elasticnodes}{Elastic Nodes}\raisedaster \o \l{graphicsview/portedasteroids}{Ported Asteroids} \o \l{graphicsview/portedcanvas}{Ported Canvas} \endlist diff --git a/examples/graphicsview/dragdroprobot/coloritem.cpp b/examples/graphicsview/dragdroprobot/coloritem.cpp index 95878b1..08edd38 100644 --- a/examples/graphicsview/dragdroprobot/coloritem.cpp +++ b/examples/graphicsview/dragdroprobot/coloritem.cpp @@ -43,6 +43,7 @@ #include "coloritem.h" +//! [0] ColorItem::ColorItem() : color(qrand() % 256, qrand() % 256, qrand() % 256) { @@ -50,13 +51,18 @@ ColorItem::ColorItem() .arg(color.red()).arg(color.green()).arg(color.blue()) .arg("Click and drag this color onto the robot!")); setCursor(Qt::OpenHandCursor); + setAcceptedMouseButtons(Qt::LeftButton); } +//! [0] +//! [1] QRectF ColorItem::boundingRect() const { return QRectF(-15.5, -15.5, 34, 34); } +//! [1] +//! [2] void ColorItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { Q_UNUSED(option); @@ -68,17 +74,16 @@ void ColorItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, painter->setBrush(QBrush(color)); painter->drawEllipse(-15, -15, 30, 30); } +//! [2] +//! [3] void ColorItem::mousePressEvent(QGraphicsSceneMouseEvent *event) { - if (event->button() != Qt::LeftButton) { - event->ignore(); - return; - } - setCursor(Qt::ClosedHandCursor); } +//! [3] +//! [5] void ColorItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { if (QLineF(event->screenPos(), event->buttonDownScreenPos(Qt::LeftButton)) @@ -89,7 +94,9 @@ void ColorItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) QDrag *drag = new QDrag(event->widget()); QMimeData *mime = new QMimeData; drag->setMimeData(mime); +//! [5] +//! [6] static int n = 0; if (n++ > 2 && (qrand() % 3) == 0) { QImage image(":/images/head.png"); @@ -97,6 +104,8 @@ void ColorItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) drag->setPixmap(QPixmap::fromImage(image).scaled(30, 40)); drag->setHotSpot(QPoint(15, 30)); +//! [6] +//! [7] } else { mime->setColorData(color); mime->setText(QString("#%1%2%3") @@ -118,12 +127,17 @@ void ColorItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) drag->setPixmap(pixmap); drag->setHotSpot(QPoint(15, 20)); } +//! [7] +//! [8] drag->exec(); setCursor(Qt::OpenHandCursor); } +//! [8] +//! [4] void ColorItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *) { setCursor(Qt::OpenHandCursor); } +//! [4] diff --git a/examples/graphicsview/dragdroprobot/coloritem.h b/examples/graphicsview/dragdroprobot/coloritem.h index 788d19e..eb19db6 100644 --- a/examples/graphicsview/dragdroprobot/coloritem.h +++ b/examples/graphicsview/dragdroprobot/coloritem.h @@ -44,6 +44,7 @@ #include <QGraphicsItem> +//! [0] class ColorItem : public QGraphicsItem { public: @@ -60,5 +61,6 @@ protected: private: QColor color; }; +//! [0] #endif diff --git a/examples/graphicsview/dragdroprobot/main.cpp b/examples/graphicsview/dragdroprobot/main.cpp index 02585e1..2669c41 100644 --- a/examples/graphicsview/dragdroprobot/main.cpp +++ b/examples/graphicsview/dragdroprobot/main.cpp @@ -46,12 +46,14 @@ #include <math.h> +//! [0] int main(int argc, char **argv) { QApplication app(argc, argv); qsrand(QTime(0,0,0).secsTo(QTime::currentTime())); - +//! [0] +//! [1] QGraphicsScene scene(-200, -200, 400, 400); for (int i = 0; i < 10; ++i) { @@ -66,7 +68,8 @@ int main(int argc, char **argv) robot->scale(1.2, 1.2); robot->setPos(0, -20); scene.addItem(robot); - +//! [1] +//! [2] QGraphicsView view(&scene); view.setRenderHint(QPainter::Antialiasing); view.setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate); @@ -76,3 +79,4 @@ int main(int argc, char **argv) return app.exec(); } +//! [2] diff --git a/examples/graphicsview/dragdroprobot/robot.cpp b/examples/graphicsview/dragdroprobot/robot.cpp index 9ac6d26..705bd9d 100644 --- a/examples/graphicsview/dragdroprobot/robot.cpp +++ b/examples/graphicsview/dragdroprobot/robot.cpp @@ -43,16 +43,18 @@ #include "robot.h" +//! [0] RobotPart::RobotPart(QGraphicsItem *parent) - : QGraphicsItem(parent), color(Qt::lightGray), dragOver(false) + : QGraphicsObject(parent), color(Qt::lightGray), dragOver(false) { setAcceptDrops(true); } +//! [0] +//! [1] void RobotPart::dragEnterEvent(QGraphicsSceneDragDropEvent *event) { - if (event->mimeData()->hasColor() - || (qgraphicsitem_cast<RobotHead *>(this) && event->mimeData()->hasImage())) { + if (event->mimeData()->hasColor()) { event->setAccepted(true); dragOver = true; update(); @@ -60,34 +62,42 @@ void RobotPart::dragEnterEvent(QGraphicsSceneDragDropEvent *event) event->setAccepted(false); } } +//! [1] +//! [2] void RobotPart::dragLeaveEvent(QGraphicsSceneDragDropEvent *event) { Q_UNUSED(event); dragOver = false; update(); } +//! [2] +//! [3] void RobotPart::dropEvent(QGraphicsSceneDragDropEvent *event) { dragOver = false; if (event->mimeData()->hasColor()) color = qVariantValue<QColor>(event->mimeData()->colorData()); - else if (event->mimeData()->hasImage()) - pixmap = qVariantValue<QPixmap>(event->mimeData()->imageData()); update(); } +//! [3] +//! [4] RobotHead::RobotHead(QGraphicsItem *parent) : RobotPart(parent) { } +//! [4] +//! [5] QRectF RobotHead::boundingRect() const { return QRectF(-15, -50, 30, 50); } +//! [5] +//! [6] void RobotHead::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { @@ -110,11 +120,33 @@ void RobotHead::paint(QPainter *painter, painter->drawPixmap(QPointF(-15 * 4.4, -50 * 3.54), pixmap); } } +//! [6] -int RobotHead::type() const +//! [7] +void RobotHead::dragEnterEvent(QGraphicsSceneDragDropEvent *event) { - return Type; + if (event->mimeData()->hasImage()) { + event->setAccepted(true); + dragOver = true; + update(); + } else { + RobotPart::dragEnterEvent(event); + } } +//! [7] + +//! [8] +void RobotHead::dropEvent(QGraphicsSceneDragDropEvent *event) +{ + if (event->mimeData()->hasImage()) { + dragOver = false; + pixmap = qVariantValue<QPixmap>(event->mimeData()->imageData()); + update(); + } else { + RobotPart::dropEvent(event); + } +} +//! [8] RobotTorso::RobotTorso(QGraphicsItem *parent) : RobotPart(parent) @@ -161,19 +193,25 @@ void RobotLimb::paint(QPainter *painter, painter->drawEllipse(-5, -5, 10, 10); } -Robot::Robot() +//! [10] +Robot::Robot(QGraphicsItem *parent) + : RobotPart(parent) { - QGraphicsItem *torsoItem = new RobotTorso(this); - QGraphicsItem *headItem = new RobotHead(torsoItem); - QGraphicsItem *upperLeftArmItem = new RobotLimb(torsoItem); - QGraphicsItem *lowerLeftArmItem = new RobotLimb(upperLeftArmItem); - QGraphicsItem *upperRightArmItem = new RobotLimb(torsoItem); - QGraphicsItem *lowerRightArmItem = new RobotLimb(upperRightArmItem); - QGraphicsItem *upperRightLegItem = new RobotLimb(torsoItem); - QGraphicsItem *lowerRightLegItem = new RobotLimb(upperRightLegItem); - QGraphicsItem *upperLeftLegItem = new RobotLimb(torsoItem); - QGraphicsItem *lowerLeftLegItem = new RobotLimb(upperLeftLegItem); - + setFlag(ItemHasNoContents); + + QGraphicsObject *torsoItem = new RobotTorso(this); + QGraphicsObject *headItem = new RobotHead(torsoItem); + QGraphicsObject *upperLeftArmItem = new RobotLimb(torsoItem); + QGraphicsObject *lowerLeftArmItem = new RobotLimb(upperLeftArmItem); + QGraphicsObject *upperRightArmItem = new RobotLimb(torsoItem); + QGraphicsObject *lowerRightArmItem = new RobotLimb(upperRightArmItem); + QGraphicsObject *upperRightLegItem = new RobotLimb(torsoItem); + QGraphicsObject *lowerRightLegItem = new RobotLimb(upperRightLegItem); + QGraphicsObject *upperLeftLegItem = new RobotLimb(torsoItem); + QGraphicsObject *lowerLeftLegItem = new RobotLimb(upperLeftLegItem); +//! [10] + +//! [11] headItem->setPos(0, -18); upperLeftArmItem->setPos(-15, -10); lowerLeftArmItem->setPos(30, 0); @@ -183,82 +221,78 @@ Robot::Robot() lowerRightLegItem->setPos(30, 0); upperLeftLegItem->setPos(-10, 32); lowerLeftLegItem->setPos(30, 0); +//! [11] - timeLine = new QTimeLine; - - QGraphicsItemAnimation *headAnimation = new QGraphicsItemAnimation; - headAnimation->setItem(headItem); - headAnimation->setTimeLine(timeLine); - headAnimation->setRotationAt(0, 20); - headAnimation->setRotationAt(1, -20); - headAnimation->setScaleAt(1, 1.1, 1.1); - - QGraphicsItemAnimation *upperLeftArmAnimation = new QGraphicsItemAnimation; - upperLeftArmAnimation->setItem(upperLeftArmItem); - upperLeftArmAnimation->setTimeLine(timeLine); - upperLeftArmAnimation->setRotationAt(0, 190); - upperLeftArmAnimation->setRotationAt(1, 180); - - QGraphicsItemAnimation *lowerLeftArmAnimation = new QGraphicsItemAnimation; - lowerLeftArmAnimation->setItem(lowerLeftArmItem); - lowerLeftArmAnimation->setTimeLine(timeLine); - lowerLeftArmAnimation->setRotationAt(0, 50); - lowerLeftArmAnimation->setRotationAt(1, 10); - - QGraphicsItemAnimation *upperRightArmAnimation = new QGraphicsItemAnimation; - upperRightArmAnimation->setItem(upperRightArmItem); - upperRightArmAnimation->setTimeLine(timeLine); - upperRightArmAnimation->setRotationAt(0, 300); - upperRightArmAnimation->setRotationAt(1, 310); - - QGraphicsItemAnimation *lowerRightArmAnimation = new QGraphicsItemAnimation; - lowerRightArmAnimation->setItem(lowerRightArmItem); - lowerRightArmAnimation->setTimeLine(timeLine); - lowerRightArmAnimation->setRotationAt(0, 0); - lowerRightArmAnimation->setRotationAt(1, -70); - - QGraphicsItemAnimation *upperLeftLegAnimation = new QGraphicsItemAnimation; - upperLeftLegAnimation->setItem(upperLeftLegItem); - upperLeftLegAnimation->setTimeLine(timeLine); - upperLeftLegAnimation->setRotationAt(0, 150); - upperLeftLegAnimation->setRotationAt(1, 80); - - QGraphicsItemAnimation *lowerLeftLegAnimation = new QGraphicsItemAnimation; - lowerLeftLegAnimation->setItem(lowerLeftLegItem); - lowerLeftLegAnimation->setTimeLine(timeLine); - lowerLeftLegAnimation->setRotationAt(0, 70); - lowerLeftLegAnimation->setRotationAt(1, 10); - - QGraphicsItemAnimation *upperRightLegAnimation = new QGraphicsItemAnimation; - upperRightLegAnimation->setItem(upperRightLegItem); - upperRightLegAnimation->setTimeLine(timeLine); - upperRightLegAnimation->setRotationAt(0, 40); - upperRightLegAnimation->setRotationAt(1, 120); - - QGraphicsItemAnimation *lowerRightLegAnimation = new QGraphicsItemAnimation; - lowerRightLegAnimation->setItem(lowerRightLegItem); - lowerRightLegAnimation->setTimeLine(timeLine); - lowerRightLegAnimation->setRotationAt(0, 10); - lowerRightLegAnimation->setRotationAt(1, 50); - - QGraphicsItemAnimation *torsoAnimation = new QGraphicsItemAnimation; - torsoAnimation->setItem(torsoItem); - torsoAnimation->setTimeLine(timeLine); - torsoAnimation->setRotationAt(0, 5); - torsoAnimation->setRotationAt(1, -20); - - timeLine->setUpdateInterval(1000 / 25); - timeLine->setCurveShape(QTimeLine::SineCurve); - timeLine->setLoopCount(0); - timeLine->setDuration(2000); - timeLine->start(); -} +//! [12] + QParallelAnimationGroup *animation = new QParallelAnimationGroup(this); -Robot::~Robot() -{ - delete timeLine; + QPropertyAnimation *headAnimation = new QPropertyAnimation(headItem, "rotation"); + headAnimation->setStartValue(20); + headAnimation->setEndValue(-20); + QPropertyAnimation *headScaleAnimation = new QPropertyAnimation(headItem, "scale"); + headScaleAnimation->setEndValue(1.1); + animation->addAnimation(headAnimation); + animation->addAnimation(headScaleAnimation); +//! [12] + + QPropertyAnimation *upperLeftArmAnimation = new QPropertyAnimation(upperLeftArmItem, "rotation"); + upperLeftArmAnimation->setStartValue(190); + upperLeftArmAnimation->setEndValue(180); + animation->addAnimation(upperLeftArmAnimation); + + QPropertyAnimation *lowerLeftArmAnimation = new QPropertyAnimation(lowerLeftArmItem, "rotation"); + lowerLeftArmAnimation->setStartValue(50); + lowerLeftArmAnimation->setEndValue(10); + animation->addAnimation(lowerLeftArmAnimation); + + QPropertyAnimation *upperRightArmAnimation = new QPropertyAnimation(upperRightArmItem, "rotation"); + upperRightArmAnimation->setStartValue(300); + upperRightArmAnimation->setEndValue(310); + animation->addAnimation(upperRightArmAnimation); + + QPropertyAnimation *lowerRightArmAnimation = new QPropertyAnimation(lowerRightArmItem, "rotation"); + lowerRightArmAnimation->setStartValue(0); + lowerRightArmAnimation->setEndValue(-70); + animation->addAnimation(lowerRightArmAnimation); + + QPropertyAnimation *upperLeftLegAnimation = new QPropertyAnimation(upperLeftLegItem, "rotation"); + upperLeftLegAnimation->setStartValue(150); + upperLeftLegAnimation->setEndValue(80); + animation->addAnimation(upperLeftLegAnimation); + + QPropertyAnimation *lowerLeftLegAnimation = new QPropertyAnimation(lowerLeftLegItem, "rotation"); + lowerLeftLegAnimation->setStartValue(70); + lowerLeftLegAnimation->setEndValue(10); + animation->addAnimation(lowerLeftLegAnimation); + + QPropertyAnimation *upperRightLegAnimation = new QPropertyAnimation(upperRightLegItem, "rotation"); + upperRightLegAnimation->setStartValue(40); + upperRightLegAnimation->setEndValue(120); + animation->addAnimation(upperRightLegAnimation); + + QPropertyAnimation *lowerRightLegAnimation = new QPropertyAnimation(lowerRightLegItem, "rotation"); + lowerRightLegAnimation->setStartValue(10); + lowerRightLegAnimation->setEndValue(50); + animation->addAnimation(lowerRightLegAnimation); + + QPropertyAnimation *torsoAnimation = new QPropertyAnimation(torsoItem, "rotation"); + torsoAnimation->setStartValue(5); + torsoAnimation->setEndValue(-20); + animation->addAnimation(torsoAnimation); + +//! [13] + for (int i = 0; i < animation->animationCount(); ++i) { + QPropertyAnimation *anim = qobject_cast<QPropertyAnimation *>(animation->animationAt(i)); + anim->setEasingCurve(QEasingCurve::SineCurve); + anim->setDuration(2000); + } + + animation->setLoopCount(-1); + animation->start(); +//! [13] } +//! [9] QRectF Robot::boundingRect() const { return QRectF(); @@ -271,3 +305,4 @@ void Robot::paint(QPainter *painter, Q_UNUSED(option); Q_UNUSED(widget); } +//! [9] diff --git a/examples/graphicsview/dragdroprobot/robot.h b/examples/graphicsview/dragdroprobot/robot.h index 88c4364..f5ff32c 100644 --- a/examples/graphicsview/dragdroprobot/robot.h +++ b/examples/graphicsview/dragdroprobot/robot.h @@ -46,10 +46,11 @@ QT_BEGIN_NAMESPACE class QGraphicsSceneMouseEvent; -class QTimeLine; +class QParallelAnimationGroup; QT_END_NAMESPACE -class RobotPart : public QGraphicsItem +//! [0] +class RobotPart : public QGraphicsObject { public: RobotPart(QGraphicsItem *parent = 0); @@ -59,11 +60,12 @@ protected: void dragLeaveEvent(QGraphicsSceneDragDropEvent *event); void dropEvent(QGraphicsSceneDragDropEvent *event); - QPixmap pixmap; QColor color; bool dragOver; }; +//! [0] +//! [1] class RobotHead : public RobotPart { public: @@ -72,10 +74,16 @@ public: QRectF boundingRect() const; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); - enum { Type = UserType + 1 }; - int type() const; +protected: + void dragEnterEvent(QGraphicsSceneDragDropEvent *event); + void dropEvent(QGraphicsSceneDragDropEvent *event); + +private: + QPixmap pixmap; }; +//! [1] +//! [2] class RobotTorso : public RobotPart { public: @@ -84,7 +92,9 @@ public: QRectF boundingRect() const; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); }; +//! [2] +//! [3] class RobotLimb : public RobotPart { public: @@ -93,18 +103,17 @@ public: QRectF boundingRect() const; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); }; +//! [3] +//! [4] class Robot : public RobotPart { public: - Robot(); - ~Robot(); + Robot(QGraphicsItem *parent = 0); QRectF boundingRect() const; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); - -private: - QTimeLine *timeLine; }; +//! [4] #endif diff --git a/examples/graphicsview/elasticnodes/edge.cpp b/examples/graphicsview/elasticnodes/edge.cpp index 25c769b..634fbee 100644 --- a/examples/graphicsview/elasticnodes/edge.cpp +++ b/examples/graphicsview/elasticnodes/edge.cpp @@ -49,6 +49,7 @@ static const double Pi = 3.14159265358979323846264338327950288419717; static double TwoPi = 2.0 * Pi; +//! [0] Edge::Edge(Node *sourceNode, Node *destNode) : arrowSize(10) { @@ -59,33 +60,21 @@ Edge::Edge(Node *sourceNode, Node *destNode) dest->addEdge(this); adjust(); } +//! [0] -Edge::~Edge() -{ -} - +//! [1] Node *Edge::sourceNode() const { return source; } -void Edge::setSourceNode(Node *node) -{ - source = node; - adjust(); -} - Node *Edge::destNode() const { return dest; } +//! [1] -void Edge::setDestNode(Node *node) -{ - dest = node; - adjust(); -} - +//! [2] void Edge::adjust() { if (!source || !dest) @@ -104,7 +93,9 @@ void Edge::adjust() sourcePoint = destPoint = line.p1(); } } +//! [2] +//! [3] QRectF Edge::boundingRect() const { if (!source || !dest) @@ -118,7 +109,9 @@ QRectF Edge::boundingRect() const .normalized() .adjusted(-extra, -extra, extra, extra); } +//! [3] +//! [4] void Edge::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) { if (!source || !dest) @@ -127,11 +120,15 @@ void Edge::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) QLineF line(sourcePoint, destPoint); if (qFuzzyCompare(line.length(), qreal(0.))) return; +//! [4] +//! [5] // Draw the line itself painter->setPen(QPen(Qt::black, 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); painter->drawLine(line); +//! [5] +//! [6] // Draw the arrows double angle = ::acos(line.dx() / line.length()); if (line.dy() >= 0) @@ -150,3 +147,4 @@ void Edge::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) painter->drawPolygon(QPolygonF() << line.p1() << sourceArrowP1 << sourceArrowP2); painter->drawPolygon(QPolygonF() << line.p2() << destArrowP1 << destArrowP2); } +//! [6] diff --git a/examples/graphicsview/elasticnodes/edge.h b/examples/graphicsview/elasticnodes/edge.h index b6b951f..58cc89c 100644 --- a/examples/graphicsview/elasticnodes/edge.h +++ b/examples/graphicsview/elasticnodes/edge.h @@ -46,17 +46,14 @@ class Node; +//! [0] class Edge : public QGraphicsItem { public: Edge(Node *sourceNode, Node *destNode); - ~Edge(); Node *sourceNode() const; - void setSourceNode(Node *node); - Node *destNode() const; - void setDestNode(Node *node); void adjust(); @@ -74,5 +71,6 @@ private: QPointF destPoint; qreal arrowSize; }; +//! [0] #endif diff --git a/examples/graphicsview/elasticnodes/graphwidget.cpp b/examples/graphicsview/elasticnodes/graphwidget.cpp index 7c244be..8b419b8 100644 --- a/examples/graphicsview/elasticnodes/graphwidget.cpp +++ b/examples/graphicsview/elasticnodes/graphwidget.cpp @@ -43,14 +43,13 @@ #include "edge.h" #include "node.h" -#include <QDebug> -#include <QGraphicsScene> -#include <QWheelEvent> +#include <QtGui> #include <math.h> -GraphWidget::GraphWidget() - : timerId(0) +//! [0] +GraphWidget::GraphWidget(QWidget *parent) + : QGraphicsView(parent), timerId(0) { QGraphicsScene *scene = new QGraphicsScene(this); scene->setItemIndexMethod(QGraphicsScene::NoIndex); @@ -60,8 +59,12 @@ GraphWidget::GraphWidget() setViewportUpdateMode(BoundingRectViewportUpdate); setRenderHint(QPainter::Antialiasing); setTransformationAnchor(AnchorUnderMouse); - setResizeAnchor(AnchorViewCenter); + scale(qreal(0.8), qreal(0.8)); + setMinimumSize(400, 400); + setWindowTitle(tr("Elastic Nodes")); +//! [0] +//! [1] Node *node1 = new Node(this); Node *node2 = new Node(this); Node *node3 = new Node(this); @@ -102,18 +105,18 @@ GraphWidget::GraphWidget() node7->setPos(-50, 50); node8->setPos(0, 50); node9->setPos(50, 50); - - scale(qreal(0.8), qreal(0.8)); - setMinimumSize(400, 400); - setWindowTitle(tr("Elastic Nodes")); } +//! [1] +//! [2] void GraphWidget::itemMoved() { if (!timerId) timerId = startTimer(1000 / 25); } +//! [2] +//! [3] void GraphWidget::keyPressEvent(QKeyEvent *event) { switch (event->key()) { @@ -146,7 +149,9 @@ void GraphWidget::keyPressEvent(QKeyEvent *event) QGraphicsView::keyPressEvent(event); } } +//! [3] +//! [4] void GraphWidget::timerEvent(QTimerEvent *event) { Q_UNUSED(event); @@ -171,12 +176,16 @@ void GraphWidget::timerEvent(QTimerEvent *event) timerId = 0; } } +//! [4] +//! [5] void GraphWidget::wheelEvent(QWheelEvent *event) { scaleView(pow((double)2, -event->delta() / 240.0)); } +//! [5] +//! [6] void GraphWidget::drawBackground(QPainter *painter, const QRectF &rect) { Q_UNUSED(rect); @@ -213,12 +222,15 @@ void GraphWidget::drawBackground(QPainter *painter, const QRectF &rect) painter->setPen(Qt::black); painter->drawText(textRect, message); } +//! [6] +//! [7] void GraphWidget::scaleView(qreal scaleFactor) { - qreal factor = matrix().scale(scaleFactor, scaleFactor).mapRect(QRectF(0, 0, 1, 1)).width(); + qreal factor = transform().scale(scaleFactor, scaleFactor).mapRect(QRectF(0, 0, 1, 1)).width(); if (factor < 0.07 || factor > 100) return; scale(scaleFactor, scaleFactor); } +//! [7] diff --git a/examples/graphicsview/elasticnodes/graphwidget.h b/examples/graphicsview/elasticnodes/graphwidget.h index 6f67b4e..3f78a5f 100644 --- a/examples/graphicsview/elasticnodes/graphwidget.h +++ b/examples/graphicsview/elasticnodes/graphwidget.h @@ -46,12 +46,13 @@ class Node; +//! [0] class GraphWidget : public QGraphicsView { Q_OBJECT public: - GraphWidget(); + GraphWidget(QWidget *parent = 0); void itemMoved(); @@ -67,5 +68,6 @@ private: int timerId; Node *centerNode; }; +//! [0] #endif diff --git a/examples/graphicsview/elasticnodes/node.cpp b/examples/graphicsview/elasticnodes/node.cpp index 774046c..495aa89 100644 --- a/examples/graphicsview/elasticnodes/node.cpp +++ b/examples/graphicsview/elasticnodes/node.cpp @@ -48,6 +48,7 @@ #include "node.h" #include "graphwidget.h" +//! [0] Node::Node(GraphWidget *graphWidget) : graph(graphWidget) { @@ -56,7 +57,9 @@ Node::Node(GraphWidget *graphWidget) setCacheMode(DeviceCoordinateCache); setZValue(-1); } +//! [0] +//! [1] void Node::addEdge(Edge *edge) { edgeList << edge; @@ -67,14 +70,18 @@ QList<Edge *> Node::edges() const { return edgeList; } +//! [1] +//! [2] void Node::calculateForces() { if (!scene() || scene()->mouseGrabberItem() == this) { newPos = pos(); return; } - +//! [2] + +//! [3] // Sum up all forces pushing this item away qreal xvel = 0; qreal yvel = 0; @@ -83,37 +90,45 @@ void Node::calculateForces() if (!node) continue; - QLineF line(mapFromItem(node, 0, 0), QPointF(0, 0)); - qreal dx = line.dx(); - qreal dy = line.dy(); + QPointF vec = mapToItem(node, 0, 0); + qreal dx = vec.x(); + qreal dy = vec.y(); double l = 2.0 * (dx * dx + dy * dy); if (l > 0) { xvel += (dx * 150.0) / l; yvel += (dy * 150.0) / l; } } +//! [3] +//! [4] // Now subtract all forces pulling items together double weight = (edgeList.size() + 1) * 10; foreach (Edge *edge, edgeList) { - QPointF pos; + QPointF vec; if (edge->sourceNode() == this) - pos = mapFromItem(edge->destNode(), 0, 0); + vec = mapToItem(edge->destNode(), 0, 0); else - pos = mapFromItem(edge->sourceNode(), 0, 0); - xvel += pos.x() / weight; - yvel += pos.y() / weight; + vec = mapToItem(edge->sourceNode(), 0, 0); + xvel -= vec.x() / weight; + yvel -= vec.y() / weight; } - +//! [4] + +//! [5] if (qAbs(xvel) < 0.1 && qAbs(yvel) < 0.1) xvel = yvel = 0; +//! [5] +//! [6] QRectF sceneRect = scene()->sceneRect(); newPos = pos() + QPointF(xvel, yvel); newPos.setX(qMin(qMax(newPos.x(), sceneRect.left() + 10), sceneRect.right() - 10)); newPos.setY(qMin(qMax(newPos.y(), sceneRect.top() + 10), sceneRect.bottom() - 10)); } +//! [6] +//! [7] bool Node::advance() { if (newPos == pos()) @@ -122,21 +137,27 @@ bool Node::advance() setPos(newPos); return true; } +//! [7] +//! [8] QRectF Node::boundingRect() const { qreal adjust = 2; return QRectF(-10 - adjust, -10 - adjust, 23 + adjust, 23 + adjust); } +//! [8] +//! [9] QPainterPath Node::shape() const { QPainterPath path; path.addEllipse(-10, -10, 20, 20); return path; } +//! [9] +//! [10] void Node::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *) { painter->setPen(Qt::NoPen); @@ -157,7 +178,9 @@ void Node::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWid painter->setPen(QPen(Qt::black, 0)); painter->drawEllipse(-10, -10, 20, 20); } +//! [10] +//! [11] QVariant Node::itemChange(GraphicsItemChange change, const QVariant &value) { switch (change) { @@ -172,7 +195,9 @@ QVariant Node::itemChange(GraphicsItemChange change, const QVariant &value) return QGraphicsItem::itemChange(change, value); } +//! [11] +//! [12] void Node::mousePressEvent(QGraphicsSceneMouseEvent *event) { update(); @@ -184,3 +209,4 @@ void Node::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) update(); QGraphicsItem::mouseReleaseEvent(event); } +//! [12] diff --git a/examples/graphicsview/elasticnodes/node.h b/examples/graphicsview/elasticnodes/node.h index 0df579d..990346e 100644 --- a/examples/graphicsview/elasticnodes/node.h +++ b/examples/graphicsview/elasticnodes/node.h @@ -51,6 +51,7 @@ QT_BEGIN_NAMESPACE class QGraphicsSceneMouseEvent; QT_END_NAMESPACE +//! [0] class Node : public QGraphicsItem { public: @@ -80,5 +81,6 @@ private: QPointF newPos; GraphWidget *graph; }; +//! [0] #endif diff --git a/qmake/generators/win32/msbuild_objectmodel.cpp b/qmake/generators/win32/msbuild_objectmodel.cpp index d011c5c..522d517 100644 --- a/qmake/generators/win32/msbuild_objectmodel.cpp +++ b/qmake/generators/win32/msbuild_objectmodel.cpp @@ -2837,6 +2837,18 @@ XmlOutput &operator<<(XmlOutput &xml, const VCXProjectSingleConfig &tool) // ResourceCompiler xml << tool.Configuration.resource; + // Post build event + if ( tool.Configuration.postBuild.UseInBuild != unset ) + xml << tool.Configuration.postBuild; + + // Pre build event + if ( tool.Configuration.preBuild.UseInBuild != unset ) + xml << tool.Configuration.preBuild; + + // Pre link event + if ( tool.Configuration.preLink.UseInBuild != unset ) + xml << tool.Configuration.preLink; + xml << closetag(); QFile filterFile; @@ -3266,6 +3278,18 @@ XmlOutput &operator<<(XmlOutput &xml, VCXProject &tool) // ResourceCompiler xml << tool.SingleProjects.at(i).Configuration.resource; + // Post build event + if ( tool.SingleProjects.at(i).Configuration.postBuild.UseInBuild != unset ) + xml << tool.SingleProjects.at(i).Configuration.postBuild; + + // Pre build event + if ( tool.SingleProjects.at(i).Configuration.preBuild.UseInBuild != unset ) + xml << tool.SingleProjects.at(i).Configuration.preBuild; + + // Pre link event + if ( tool.SingleProjects.at(i).Configuration.preLink.UseInBuild != unset ) + xml << tool.SingleProjects.at(i).Configuration.preLink; + xml << closetag(); } diff --git a/qmake/generators/win32/msvc_vcproj.cpp b/qmake/generators/win32/msvc_vcproj.cpp index 8c9bba8..35e4896 100644 --- a/qmake/generators/win32/msvc_vcproj.cpp +++ b/qmake/generators/win32/msvc_vcproj.cpp @@ -917,14 +917,12 @@ void VcprojGenerator::initCompilerTool() conf.compiler.parseOptions(project->values("QMAKE_CXXFLAGS")); if(project->isActiveConfig("debug")){ // Debug version - conf.compiler.parseOptions(project->values("QMAKE_CXXFLAGS_DEBUG")); if((projectTarget == Application) || (projectTarget == StaticLib)) conf.compiler.parseOptions(project->values("QMAKE_CXXFLAGS_MT_DBG")); else conf.compiler.parseOptions(project->values("QMAKE_CXXFLAGS_MT_DLLDBG")); } else { // Release version - conf.compiler.parseOptions(project->values("QMAKE_CXXFLAGS_RELEASE")); conf.compiler.PreprocessorDefinitions += "QT_NO_DEBUG"; conf.compiler.PreprocessorDefinitions += "NDEBUG"; if((projectTarget == Application) || (projectTarget == StaticLib)) @@ -934,10 +932,6 @@ void VcprojGenerator::initCompilerTool() } // Common for both release and debug - if(project->isActiveConfig("warn_off")) - conf.compiler.parseOptions(project->values("QMAKE_CXXFLAGS_WARN_OFF")); - else if(project->isActiveConfig("warn_on")) - conf.compiler.parseOptions(project->values("QMAKE_CXXFLAGS_WARN_ON")); if(project->isActiveConfig("windows")) conf.compiler.PreprocessorDefinitions += project->values("MSVCPROJ_WINCONDEF"); @@ -1000,22 +994,9 @@ void VcprojGenerator::initLinkerTool() conf.linker.OutputFile += project->first("MSVCPROJ_TARGET"); - if(project->isActiveConfig("debug")){ - conf.linker.parseOptions(project->values("QMAKE_LFLAGS_DEBUG")); - } else { - conf.linker.parseOptions(project->values("QMAKE_LFLAGS_RELEASE")); - } - if(project->isActiveConfig("dll")){ conf.linker.parseOptions(project->values("QMAKE_LFLAGS_QT_DLL")); } - - if(project->isActiveConfig("console")){ - conf.linker.parseOptions(project->values("QMAKE_LFLAGS_CONSOLE")); - } else { - conf.linker.parseOptions(project->values("QMAKE_LFLAGS_WINDOWS")); - } - } void VcprojGenerator::initResourceTool() diff --git a/qmake/generators/win32/msvc_vcxproj.cpp b/qmake/generators/win32/msvc_vcxproj.cpp index 6a91c6b..da93fe3 100644 --- a/qmake/generators/win32/msvc_vcxproj.cpp +++ b/qmake/generators/win32/msvc_vcxproj.cpp @@ -294,14 +294,12 @@ void VcxprojGenerator::initCompilerTool() conf.compiler.parseOptions(project->values("QMAKE_CXXFLAGS")); if(project->isActiveConfig("debug")){ // Debug version - conf.compiler.parseOptions(project->values("QMAKE_CXXFLAGS_DEBUG")); if((projectTarget == Application) || (projectTarget == StaticLib)) conf.compiler.parseOptions(project->values("QMAKE_CXXFLAGS_MT_DBG")); else conf.compiler.parseOptions(project->values("QMAKE_CXXFLAGS_MT_DLLDBG")); } else { // Release version - conf.compiler.parseOptions(project->values("QMAKE_CXXFLAGS_RELEASE")); conf.compiler.PreprocessorDefinitions += "QT_NO_DEBUG"; conf.compiler.PreprocessorDefinitions += "NDEBUG"; if((projectTarget == Application) || (projectTarget == StaticLib)) @@ -311,10 +309,6 @@ void VcxprojGenerator::initCompilerTool() } // Common for both release and debug - if(project->isActiveConfig("warn_off")) - conf.compiler.parseOptions(project->values("QMAKE_CXXFLAGS_WARN_OFF")); - else if(project->isActiveConfig("warn_on")) - conf.compiler.parseOptions(project->values("QMAKE_CXXFLAGS_WARN_ON")); if(project->isActiveConfig("windows")) conf.compiler.PreprocessorDefinitions += project->values("MSVCPROJ_WINCONDEF"); @@ -363,22 +357,9 @@ void VcxprojGenerator::initLinkerTool() conf.linker.OutputFile += project->first("MSVCPROJ_TARGET"); - if(project->isActiveConfig("debug")){ - conf.linker.parseOptions(project->values("QMAKE_LFLAGS_DEBUG")); - } else { - conf.linker.parseOptions(project->values("QMAKE_LFLAGS_RELEASE")); - } - if(project->isActiveConfig("dll")){ conf.linker.parseOptions(project->values("QMAKE_LFLAGS_QT_DLL")); } - - if(project->isActiveConfig("console")){ - conf.linker.parseOptions(project->values("QMAKE_LFLAGS_CONSOLE")); - } else { - conf.linker.parseOptions(project->values("QMAKE_LFLAGS_WINDOWS")); - } - } void VcxprojGenerator::initResourceTool() @@ -403,20 +384,24 @@ void VcxprojGenerator::initPostBuildEventTools() QString cmdline = var("QMAKE_POST_LINK"); conf.postBuild.CommandLine = cmdline; conf.postBuild.Description = cmdline; + conf.postBuild.UseInBuild = _True; } QString signature = !project->isEmpty("SIGNATURE_FILE") ? var("SIGNATURE_FILE") : var("DEFAULT_SIGNATURE"); bool useSignature = !signature.isEmpty() && !project->isActiveConfig("staticlib") && !project->isEmpty("CE_SDK") && !project->isEmpty("CE_ARCH"); - if(useSignature) - conf.postBuild.CommandLine.prepend(QLatin1String("signtool sign /F ") + signature + " \"$(TargetPath)\"\n" + - (!conf.postBuild.CommandLine.isEmpty() ? " && " : "")); + if(useSignature) { + conf.postBuild.CommandLine.prepend(QLatin1String("signtool sign /F ") + signature + " \"$(TargetPath)\"\n" + + (!conf.postBuild.CommandLine.isEmpty() ? " && " : "")); + conf.postBuild.UseInBuild = _True; + } if(!project->values("MSVCPROJ_COPY_DLL").isEmpty()) { if(!conf.postBuild.CommandLine.isEmpty()) conf.postBuild.CommandLine += " && "; conf.postBuild.Description += var("MSVCPROJ_COPY_DLL_DESC"); conf.postBuild.CommandLine += var("MSVCPROJ_COPY_DLL"); + conf.postBuild.UseInBuild = _True; } } @@ -549,6 +534,7 @@ void VcxprojGenerator::initPreLinkEventTools() QString cmdline = var("QMAKE_PRE_LINK"); conf.preLink.Description = cmdline; conf.preLink.CommandLine = cmdline; + conf.preLink.UseInBuild = _True; } } diff --git a/src/corelib/codecs/qtextcodec.cpp b/src/corelib/codecs/qtextcodec.cpp index 59a601e..c9fbec8 100644 --- a/src/corelib/codecs/qtextcodec.cpp +++ b/src/corelib/codecs/qtextcodec.cpp @@ -105,7 +105,7 @@ QT_BEGIN_NAMESPACE -#ifndef QT_NO_TEXTCODECPLUGIN +#if !defined(QT_NO_LIBRARY) && !defined(QT_NO_TEXTCODECPLUGIN) Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader, (QTextCodecFactoryInterface_iid, QLatin1String("/codecs"))) #endif @@ -149,7 +149,7 @@ static bool nameMatch(const QByteArray &name, const QByteArray &test) static QTextCodec *createForName(const QByteArray &name) { -#ifndef QT_NO_TEXTCODECPLUGIN +#if !defined(QT_NO_LIBRARY) && !defined(QT_NO_TEXTCODECPLUGIN) QFactoryLoader *l = loader(); QStringList keys = l->keys(); for (int i = 0; i < keys.size(); ++i) { @@ -1141,7 +1141,7 @@ QList<QByteArray> QTextCodec::availableCodecs() locker.unlock(); #endif -#ifndef QT_NO_TEXTCODECPLUGIN +#if !defined(QT_NO_LIBRARY) && !defined(QT_NO_TEXTCODECPLUGIN) QFactoryLoader *l = loader(); QStringList keys = l->keys(); for (int i = 0; i < keys.size(); ++i) { @@ -1181,7 +1181,7 @@ QList<int> QTextCodec::availableMibs() locker.unlock(); #endif -#ifndef QT_NO_TEXTCODECPLUGIN +#if !defined(QT_NO_LIBRARY) && !defined(QT_NO_TEXTCODECPLUGIN) QFactoryLoader *l = loader(); QStringList keys = l->keys(); for (int i = 0; i < keys.size(); ++i) { diff --git a/src/corelib/io/qurl.cpp b/src/corelib/io/qurl.cpp index a60f206..4e580dd 100644 --- a/src/corelib/io/qurl.cpp +++ b/src/corelib/io/qurl.cpp @@ -2997,7 +2997,9 @@ bool qt_check_std3rules(const QChar *uc, int len) // only LDH is present if (c == '-' || (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') - || (c >= 'a' && c <= 'z')) + || (c >= 'a' && c <= 'z') + //underscore is not supposed to be allowed, but other browser accept it (QTBUG-7434) + || c == '_') continue; return false; diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp index bf2e2e4..609e6b3 100644 --- a/src/corelib/kernel/qcoreapplication.cpp +++ b/src/corelib/kernel/qcoreapplication.cpp @@ -514,7 +514,7 @@ QCoreApplication::QCoreApplication(int &argc, char **argv) { init(); QCoreApplicationPrivate::eventDispatcher->startingUp(); -#if defined(Q_OS_SYMBIAN) && !defined(QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) +#if defined(Q_OS_SYMBIAN) && !defined(QT_NO_LIBRARY) // Refresh factoryloader, as text codecs are requested during lib path // resolving process and won't be therefore properly loaded. // Unknown if this is symbian specific issue. @@ -2189,7 +2189,7 @@ QString QCoreApplication::applicationVersion() return coreappdata()->applicationVersion; } -#if !defined(QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) +#ifndef QT_NO_LIBRARY Q_GLOBAL_STATIC_WITH_ARGS(QMutex, libraryPathMutex, (QMutex::Recursive)) @@ -2291,13 +2291,11 @@ QStringList QCoreApplication::libraryPaths() */ void QCoreApplication::setLibraryPaths(const QStringList &paths) { -#if !defined(QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) QMutexLocker locker(libraryPathMutex()); if (!coreappdata()->app_libpaths) coreappdata()->app_libpaths = new QStringList; *(coreappdata()->app_libpaths) = paths; QFactoryLoader::refreshAll(); -#endif } /*! @@ -2318,7 +2316,6 @@ void QCoreApplication::setLibraryPaths(const QStringList &paths) */ void QCoreApplication::addLibraryPath(const QString &path) { -#if !defined(QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) if (path.isEmpty()) return; @@ -2333,7 +2330,6 @@ void QCoreApplication::addLibraryPath(const QString &path) coreappdata()->app_libpaths->prepend(canonicalPath); QFactoryLoader::refreshAll(); } -#endif } /*! @@ -2344,7 +2340,6 @@ void QCoreApplication::addLibraryPath(const QString &path) */ void QCoreApplication::removeLibraryPath(const QString &path) { -#if !defined(QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) if (path.isEmpty()) return; @@ -2356,7 +2351,6 @@ void QCoreApplication::removeLibraryPath(const QString &path) QString canonicalPath = QDir(path).canonicalPath(); coreappdata()->app_libpaths->removeAll(canonicalPath); QFactoryLoader::refreshAll(); -#endif } #endif //QT_NO_LIBRARY diff --git a/src/corelib/plugin/qfactoryloader.cpp b/src/corelib/plugin/qfactoryloader.cpp index 87decc6..62d565a 100644 --- a/src/corelib/plugin/qfactoryloader.cpp +++ b/src/corelib/plugin/qfactoryloader.cpp @@ -41,7 +41,7 @@ #include "qfactoryloader_p.h" -#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) +#ifndef QT_NO_LIBRARY #include "qfactoryinterface.h" #include "qmap.h" #include <qdir.h> diff --git a/src/corelib/plugin/qfactoryloader_p.h b/src/corelib/plugin/qfactoryloader_p.h index 51426ba..10e6e2a 100644 --- a/src/corelib/plugin/qfactoryloader_p.h +++ b/src/corelib/plugin/qfactoryloader_p.h @@ -57,7 +57,7 @@ #include "QtCore/qstringlist.h" #include "private/qlibrary_p.h" -#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) +#ifndef QT_NO_LIBRARY QT_BEGIN_NAMESPACE diff --git a/src/gui/accessible/qaccessible.cpp b/src/gui/accessible/qaccessible.cpp index a55a061..0921bdb 100644 --- a/src/gui/accessible/qaccessible.cpp +++ b/src/gui/accessible/qaccessible.cpp @@ -389,7 +389,7 @@ QT_BEGIN_NAMESPACE \internal */ -#if !defined(QT_NO_LIBRARY) && (!defined(QT_NO_SETTINGS) || !defined(Q_OS_WIN)) +#ifndef QT_NO_LIBRARY Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader, (QAccessibleFactoryInterface_iid, QLatin1String("/accessible"))) #endif @@ -532,7 +532,7 @@ QAccessibleInterface *QAccessible::queryAccessibleInterface(QObject *object) if (iface) return iface; } -#if !defined(QT_NO_LIBRARY) && (!defined(QT_NO_SETTINGS) || !defined(Q_OS_WIN)) +#ifndef QT_NO_LIBRARY QAccessibleFactoryInterface *factory = qobject_cast<QAccessibleFactoryInterface*>(loader()->instance(cn)); if (factory) { iface = factory->create(cn, object); diff --git a/src/gui/image/qicon.cpp b/src/gui/image/qicon.cpp index bc52e99..891b1db 100644 --- a/src/gui/image/qicon.cpp +++ b/src/gui/image/qicon.cpp @@ -441,7 +441,7 @@ void QPixmapIconEngine::virtual_hook(int id, void *data) } } -#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) +#ifndef QT_NO_LIBRARY Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader, (QIconEngineFactoryInterface_iid, QLatin1String("/iconengines"), Qt::CaseInsensitive)) Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loaderV2, diff --git a/src/gui/image/qimagereader.cpp b/src/gui/image/qimagereader.cpp index 27f9627..93d5cd3 100644 --- a/src/gui/image/qimagereader.cpp +++ b/src/gui/image/qimagereader.cpp @@ -144,7 +144,7 @@ QT_BEGIN_NAMESPACE -#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) +#ifndef QT_NO_LIBRARY Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader, (QImageIOHandlerFactoryInterface_iid, QLatin1String("/imageformats"))) #endif @@ -205,7 +205,7 @@ static QImageIOHandler *createReadHandlerHelper(QIODevice *device, QByteArray form = format.toLower(); QImageIOHandler *handler = 0; -#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) +#ifndef QT_NO_LIBRARY // check if we have plugins that support the image format QFactoryLoader *l = loader(); QStringList keys = l->keys(); @@ -217,7 +217,7 @@ static QImageIOHandler *createReadHandlerHelper(QIODevice *device, << keys.size() << "plugins available: " << keys; #endif -#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) +#ifndef QT_NO_LIBRARY int suffixPluginIndex = -1; if (device && format.isEmpty() && autoDetectImageFormat && !ignoresFormatAndExtension) { // if there's no format, see if \a device is a file, and if so, find @@ -246,7 +246,7 @@ static QImageIOHandler *createReadHandlerHelper(QIODevice *device, if (ignoresFormatAndExtension) testFormat = QByteArray(); -#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) +#ifndef QT_NO_LIBRARY if (suffixPluginIndex != -1) { // check if the plugin that claims support for this format can load // from this device with this format. @@ -331,7 +331,7 @@ static QImageIOHandler *createReadHandlerHelper(QIODevice *device, #endif } -#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) +#ifndef QT_NO_LIBRARY if (!handler && (autoDetectImageFormat || ignoresFormatAndExtension)) { // check if any of our plugins recognize the file from its contents. const qint64 pos = device ? device->pos() : 0; @@ -350,7 +350,7 @@ static QImageIOHandler *createReadHandlerHelper(QIODevice *device, if (device && !device->isSequential()) device->seek(pos); } -#endif +#endif // QT_NO_LIBRARY if (!handler && (autoDetectImageFormat || ignoresFormatAndExtension)) { // check if any of our built-in handlers recognize the file from its @@ -1414,7 +1414,7 @@ QList<QByteArray> QImageReader::supportedImageFormats() for (int i = 0; i < _qt_NumFormats; ++i) formats << _qt_BuiltInFormats[i].extension; -#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) +#ifndef QT_NO_LIBRARY QFactoryLoader *l = loader(); QStringList keys = l->keys(); diff --git a/src/gui/image/qimagewriter.cpp b/src/gui/image/qimagewriter.cpp index 503a1b2..552729f 100644 --- a/src/gui/image/qimagewriter.cpp +++ b/src/gui/image/qimagewriter.cpp @@ -117,7 +117,7 @@ QT_BEGIN_NAMESPACE -#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) +#ifndef QT_NO_LIBRARY Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader, (QImageIOHandlerFactoryInterface_iid, QLatin1String("/imageformats"))) #endif @@ -129,7 +129,7 @@ static QImageIOHandler *createWriteHandlerHelper(QIODevice *device, QByteArray suffix; QImageIOHandler *handler = 0; -#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) +#ifndef QT_NO_LIBRARY // check if any plugins can write the image QFactoryLoader *l = loader(); QStringList keys = l->keys(); @@ -142,7 +142,7 @@ static QImageIOHandler *createWriteHandlerHelper(QIODevice *device, // this allows plugins to override our built-in handlers. if (QFile *file = qobject_cast<QFile *>(device)) { if (!(suffix = QFileInfo(file->fileName()).suffix().toLower().toLatin1()).isEmpty()) { -#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) +#ifndef QT_NO_LIBRARY int index = keys.indexOf(QString::fromLatin1(suffix)); if (index != -1) suffixPluginIndex = index; @@ -153,7 +153,7 @@ static QImageIOHandler *createWriteHandlerHelper(QIODevice *device, QByteArray testFormat = !form.isEmpty() ? form : suffix; -#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) +#ifndef QT_NO_LIBRARY if (suffixPluginIndex != -1) { // when format is missing, check if we can find a plugin for the // suffix. @@ -161,7 +161,7 @@ static QImageIOHandler *createWriteHandlerHelper(QIODevice *device, if (plugin && (plugin->capabilities(device, suffix) & QImageIOPlugin::CanWrite)) handler = plugin->create(device, suffix); } -#endif // Q_NO_LIBRARY +#endif // QT_NO_LIBRARY // check if any built-in handlers can write the image if (!handler && !testFormat.isEmpty()) { @@ -192,7 +192,7 @@ static QImageIOHandler *createWriteHandlerHelper(QIODevice *device, } } -#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) +#ifndef QT_NO_LIBRARY if (!testFormat.isEmpty()) { for (int i = 0; i < keys.size(); ++i) { QImageIOPlugin *plugin = qobject_cast<QImageIOPlugin *>(l->instance(keys.at(i))); @@ -203,7 +203,7 @@ static QImageIOHandler *createWriteHandlerHelper(QIODevice *device, } } } -#endif +#endif // QT_NO_LIBRARY if (!handler) return 0; @@ -670,7 +670,7 @@ QList<QByteArray> QImageWriter::supportedImageFormats() formats << "png"; #endif -#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) +#ifndef QT_NO_LIBRARY QFactoryLoader *l = loader(); QStringList keys = l->keys(); for (int i = 0; i < keys.count(); ++i) { diff --git a/src/gui/inputmethod/qinputcontextfactory.cpp b/src/gui/inputmethod/qinputcontextfactory.cpp index d47e343..ec8d8e2 100644 --- a/src/gui/inputmethod/qinputcontextfactory.cpp +++ b/src/gui/inputmethod/qinputcontextfactory.cpp @@ -81,7 +81,7 @@ QT_BEGIN_NAMESPACE -#if !defined(QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) +#ifndef QT_NO_LIBRARY Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader, (QInputContextFactoryInterface_iid, QLatin1String("/inputmethods"))) #endif @@ -153,7 +153,7 @@ QInputContext *QInputContextFactory::create( const QString& key, QObject *parent result = new QCoeFepInputContext; } #endif -#if defined(QT_NO_LIBRARY) || defined(QT_NO_SETTINGS) +#ifdef QT_NO_LIBRARY Q_UNUSED(key); #else if (QInputContextFactoryInterface *factory = @@ -193,7 +193,7 @@ QStringList QInputContextFactory::keys() #if defined(Q_WS_S60) result << QLatin1String("coefep"); #endif -#if !defined(QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) +#ifndef QT_NO_LIBRARY result += loader()->keys(); #endif // QT_NO_LIBRARY return result; diff --git a/src/gui/itemviews/qtableview.cpp b/src/gui/itemviews/qtableview.cpp index 80334a6..4492e53 100644 --- a/src/gui/itemviews/qtableview.cpp +++ b/src/gui/itemviews/qtableview.cpp @@ -2145,8 +2145,8 @@ int QTableView::sizeHintForRow(int row) const ensurePolished(); - int left = qMax(0, columnAt(0)); - int right = columnAt(d->viewport->width()); + int left = qMax(0, d->horizontalHeader->visualIndexAt(0)); + int right = d->horizontalHeader->visualIndexAt(d->viewport->width()); if (right == -1) // the table don't have enough columns to fill the viewport right = d->model->columnCount(d->root) - 1; @@ -2204,8 +2204,8 @@ int QTableView::sizeHintForColumn(int column) const ensurePolished(); - int top = qMax(0, rowAt(0)); - int bottom = rowAt(d->viewport->height()); + int top = qMax(0, d->verticalHeader->visualIndexAt(0)); + int bottom = d->verticalHeader->visualIndexAt(d->viewport->height()); if (!isVisible() || bottom == -1) // the table don't have enough rows to fill the viewport bottom = d->model->rowCount(d->root) - 1; diff --git a/src/gui/kernel/qguiplatformplugin.cpp b/src/gui/kernel/qguiplatformplugin.cpp index c4119af..2dd251b 100644 --- a/src/gui/kernel/qguiplatformplugin.cpp +++ b/src/gui/kernel/qguiplatformplugin.cpp @@ -81,7 +81,7 @@ QGuiPlatformPlugin *qt_guiPlatformPlugin() static QGuiPlatformPlugin *plugin; if (!plugin) { -#if !defined(QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) +#ifndef QT_NO_LIBRARY QString key = QString::fromLocal8Bit(qgetenv("QT_PLATFORM_PLUGIN")); #ifdef Q_WS_X11 diff --git a/src/gui/kernel/qlayoutitem.cpp b/src/gui/kernel/qlayoutitem.cpp index 6a91d95..e615b2d 100644 --- a/src/gui/kernel/qlayoutitem.cpp +++ b/src/gui/kernel/qlayoutitem.cpp @@ -516,9 +516,7 @@ bool QWidgetItem::hasHeightForWidth() const { if (isEmpty()) return false; - if (wid->layout()) - return wid->layout()->hasHeightForWidth(); - return wid->sizePolicy().hasHeightForWidth(); + return wid->hasHeightForWidth(); } /*! diff --git a/src/gui/kernel/qstackedlayout.cpp b/src/gui/kernel/qstackedlayout.cpp index 7559066..4b49638 100644 --- a/src/gui/kernel/qstackedlayout.cpp +++ b/src/gui/kernel/qstackedlayout.cpp @@ -475,6 +475,32 @@ void QStackedLayout::setGeometry(const QRect &rect) } } +bool QStackedLayout::hasHeightForWidth() const +{ + const int n = count(); + + for (int i = 0; i < n; ++i) { + if (QLayoutItem *item = itemAt(i)) { + if (item->hasHeightForWidth()) + return true; + } + } + return false; +} + +int QStackedLayout::heightForWidth(int width) const +{ + const int n = count(); + + int hfw = 0; + for (int i = 0; i < n; ++i) { + if (QLayoutItem *item = itemAt(i)) { + hfw = qMax(hfw, item->heightForWidth(width)); + } + } + return hfw; +} + /*! \enum QStackedLayout::StackingMode \since 4.4 diff --git a/src/gui/kernel/qstackedlayout.h b/src/gui/kernel/qstackedlayout.h index c069149..842b62b 100644 --- a/src/gui/kernel/qstackedlayout.h +++ b/src/gui/kernel/qstackedlayout.h @@ -95,6 +95,8 @@ public: QLayoutItem *itemAt(int) const; QLayoutItem *takeAt(int); void setGeometry(const QRect &rect); + bool hasHeightForWidth() const; + int heightForWidth(int width) const; Q_SIGNALS: void widgetRemoved(int index); diff --git a/src/gui/kernel/qwidget.cpp b/src/gui/kernel/qwidget.cpp index 20d1d30..399a27b 100644 --- a/src/gui/kernel/qwidget.cpp +++ b/src/gui/kernel/qwidget.cpp @@ -3825,6 +3825,11 @@ void QWidget::setMaximumSize(int maxw, int maxh) d->updateGeometry_helper(d->extra->minw == d->extra->maxw && d->extra->minh == d->extra->maxh); } +bool QWidgetPrivate::hasHeightForWidth() const +{ + return layout ? layout->hasHeightForWidth() : size_policy.hasHeightForWidth(); +} + /*! \overload @@ -7970,6 +7975,18 @@ QSize QWidget::minimumSizeHint() const return QSize(-1, -1); } +/*! + \internal + This is a bit hackish, but ideally this would have been a virtual + function so that subclasses could reimplement their own function. + Instead we add a virtual function to QWidgetPrivate. +*/ +bool QWidget::hasHeightForWidth() const +{ + Q_D(const QWidget); + return d->hasHeightForWidth(); +} + /*! \fn QWidget *QWidget::parentWidget() const diff --git a/src/gui/kernel/qwidget.h b/src/gui/kernel/qwidget.h index e12148b..6e5de7d 100644 --- a/src/gui/kernel/qwidget.h +++ b/src/gui/kernel/qwidget.h @@ -524,6 +524,7 @@ public: virtual QSize sizeHint() const; virtual QSize minimumSizeHint() const; + bool hasHeightForWidth() const; QSizePolicy sizePolicy() const; void setSizePolicy(QSizePolicy); diff --git a/src/gui/kernel/qwidget_p.h b/src/gui/kernel/qwidget_p.h index cad60b5..9926b2c 100644 --- a/src/gui/kernel/qwidget_p.h +++ b/src/gui/kernel/qwidget_p.h @@ -493,6 +493,7 @@ public: bool setMinimumSize_helper(int &minw, int &minh); bool setMaximumSize_helper(int &maxw, int &maxh); + virtual bool hasHeightForWidth() const; void setConstraints_sys(); QWidget *childAt_helper(const QPoint &, bool) const; void updateGeometry_helper(bool forceUpdate); diff --git a/src/gui/painting/qgraphicssystemfactory.cpp b/src/gui/painting/qgraphicssystemfactory.cpp index 29f24a3..3c09894 100644 --- a/src/gui/painting/qgraphicssystemfactory.cpp +++ b/src/gui/painting/qgraphicssystemfactory.cpp @@ -50,7 +50,7 @@ QT_BEGIN_NAMESPACE -#if !defined(QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) +#ifndef QT_NO_LIBRARY Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader, (QGraphicsSystemFactoryInterface_iid, QLatin1String("/graphicssystems"), Qt::CaseInsensitive)) #endif @@ -79,7 +79,7 @@ QGraphicsSystem *QGraphicsSystemFactory::create(const QString& key) else if (system.isEmpty() || system == QLatin1String("native")) return 0; -#if !defined(QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) +#ifndef QT_NO_LIBRARY if (!ret) { if (QGraphicsSystemFactoryInterface *factory = qobject_cast<QGraphicsSystemFactoryInterface*>(loader()->instance(system))) ret = factory->create(system); @@ -100,7 +100,7 @@ QGraphicsSystem *QGraphicsSystemFactory::create(const QString& key) */ QStringList QGraphicsSystemFactory::keys() { -#if !defined(QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) +#ifndef QT_NO_LIBRARY QStringList list = loader()->keys(); #else QStringList list; diff --git a/src/gui/painting/qpaintengine_mac.cpp b/src/gui/painting/qpaintengine_mac.cpp index ac2fcf4..14ba94e 100644 --- a/src/gui/painting/qpaintengine_mac.cpp +++ b/src/gui/painting/qpaintengine_mac.cpp @@ -118,9 +118,10 @@ QMacCGContext::QMacCGContext(QPainter *p) QRegion clip = p->paintEngine()->systemClip(); QTransform native = p->deviceTransform(); QTransform logical = p->combinedTransform(); + if (p->hasClipping()) { QRegion r = p->clipRegion(); - r.translate(native.dx() - logical.dx(), native.dy() - logical.dy()); + r.translate(native.dx(), native.dy()); if (clip.isEmpty()) clip = r; else @@ -128,10 +129,7 @@ QMacCGContext::QMacCGContext(QPainter *p) } qt_mac_clip_cg(context, clip, 0); - QPainterState *state = static_cast<QPainterState *>(pe->state); - Q_ASSERT(state); - if (!state->redirectionMatrix.isIdentity()) - CGContextTranslateCTM(context, state->redirectionMatrix.dx(), state->redirectionMatrix.dy()); + CGContextTranslateCTM(context, native.dx(), native.dy()); } } CGContextRetain(context); diff --git a/src/gui/styles/qstylefactory.cpp b/src/gui/styles/qstylefactory.cpp index 0dbb21f..9009878 100644 --- a/src/gui/styles/qstylefactory.cpp +++ b/src/gui/styles/qstylefactory.cpp @@ -81,7 +81,7 @@ QT_BEGIN_INCLUDE_NAMESPACE QT_END_INCLUDE_NAMESPACE #endif -#if !defined(QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) +#ifndef QT_NO_LIBRARY Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader, (QStyleFactoryInterface_iid, QLatin1String("/styles"), Qt::CaseInsensitive)) #endif diff --git a/src/gui/text/qfontengine_mac.mm b/src/gui/text/qfontengine_mac.mm index 0bfdbc0..a6510cb 100644 --- a/src/gui/text/qfontengine_mac.mm +++ b/src/gui/text/qfontengine_mac.mm @@ -226,8 +226,19 @@ bool QCoreTextFontEngineMulti::stringToCMap(const QChar *str, int len, QGlyphLay QFixed *outAdvances_y = glyphs->advances_y; glyph_t *initialGlyph = outGlyphs; - if (arraySize == 0) - return false; + if (arraySize == 0) { + // CoreText failed to shape the text we gave it, so we assume one glyph + // per character and build a list of invalid glyphs with zero advance + *nglyphs = len; + for (int i = 0; i < len; ++i) { + outGlyphs[i] = 0; + logClusters[i] = i; + outAdvances_x[i] = QFixed(); + outAdvances_y[i] = QFixed(); + outAttributes[i].clusterStart = true; + } + return true; + } const bool rtl = (CTRunGetStatus(static_cast<CTRunRef>(CFArrayGetValueAtIndex(array, 0))) & kCTRunStatusRightToLeft); diff --git a/src/gui/text/qtextcontrol.cpp b/src/gui/text/qtextcontrol.cpp index 3c596e5..a2ee659 100644 --- a/src/gui/text/qtextcontrol.cpp +++ b/src/gui/text/qtextcontrol.cpp @@ -885,8 +885,10 @@ void QTextControl::processEvent(QEvent *e, const QPointF &coordinateOffset, QWid void QTextControl::processEvent(QEvent *e, const QMatrix &matrix, QWidget *contextWidget) { Q_D(QTextControl); - if (d->interactionFlags & Qt::NoTextInteraction) + if (d->interactionFlags == Qt::NoTextInteraction) { + e->ignore(); return; + } d->contextWidget = contextWidget; diff --git a/src/gui/widgets/qsizegrip.cpp b/src/gui/widgets/qsizegrip.cpp index c9d613a..40f3129 100644 --- a/src/gui/widgets/qsizegrip.cpp +++ b/src/gui/widgets/qsizegrip.cpp @@ -78,15 +78,6 @@ static QWidget *qt_sizegrip_topLevelWidget(QWidget* w) return w; } -static inline bool hasHeightForWidth(QWidget *widget) -{ - if (!widget) - return false; - if (QLayout *layout = widget->layout()) - return layout->hasHeightForWidth(); - return widget->sizePolicy().hasHeightForWidth(); -} - class QSizeGripPrivate : public QWidgetPrivate { Q_DECLARE_PUBLIC(QSizeGrip) @@ -318,7 +309,7 @@ void QSizeGrip::mousePressEvent(QMouseEvent * e) #ifdef Q_WS_X11 // Use a native X11 sizegrip for "real" top-level windows if supported. if (tlw->isWindow() && X11->isSupportedByWM(ATOM(_NET_WM_MOVERESIZE)) - && !tlw->testAttribute(Qt::WA_DontShowOnScreen) && !hasHeightForWidth(tlw)) { + && !tlw->testAttribute(Qt::WA_DontShowOnScreen) && !tlw->hasHeightForWidth()) { XEvent xev; xev.xclient.type = ClientMessage; xev.xclient.message_type = ATOM(_NET_WM_MOVERESIZE); @@ -340,7 +331,7 @@ void QSizeGrip::mousePressEvent(QMouseEvent * e) } #endif // Q_WS_X11 #ifdef Q_WS_WIN - if (tlw->isWindow() && !tlw->testAttribute(Qt::WA_DontShowOnScreen) && !hasHeightForWidth(tlw)) { + if (tlw->isWindow() && !tlw->testAttribute(Qt::WA_DontShowOnScreen) && !tlw->hasHeightForWidth()) { uint orientation = 0; if (d->atBottom()) orientation = d->atLeft() ? SZ_SIZEBOTTOMLEFT : SZ_SIZEBOTTOMRIGHT; @@ -429,12 +420,12 @@ void QSizeGrip::mouseMoveEvent(QMouseEvent * e) #ifdef Q_WS_X11 if (tlw->isWindow() && X11->isSupportedByWM(ATOM(_NET_WM_MOVERESIZE)) - && tlw->isTopLevel() && !tlw->testAttribute(Qt::WA_DontShowOnScreen) && !hasHeightForWidth(tlw)) + && tlw->isTopLevel() && !tlw->testAttribute(Qt::WA_DontShowOnScreen) && !tlw->hasHeightForWidth()) return; #endif #ifdef Q_WS_WIN if (tlw->isWindow() && GetSystemMenu(tlw->winId(), FALSE) != 0 && internalWinId() - && !tlw->testAttribute(Qt::WA_DontShowOnScreen) && !hasHeightForWidth(tlw)) { + && !tlw->testAttribute(Qt::WA_DontShowOnScreen) && !tlw->hasHeightForWidth()) { MSG msg; while(PeekMessage(&msg, winId(), WM_MOUSEMOVE, WM_MOUSEMOVE, PM_REMOVE)); return; diff --git a/src/gui/widgets/qtabwidget.cpp b/src/gui/widgets/qtabwidget.cpp index 4a61935..3463241 100644 --- a/src/gui/widgets/qtabwidget.cpp +++ b/src/gui/widgets/qtabwidget.cpp @@ -195,6 +195,7 @@ public: void _q_removeTab(int); void _q_tabMoved(int from, int to); void init(); + bool hasHeightForWidth() const; QTabBar *tabs; QStackedWidget *stack; @@ -873,6 +874,46 @@ QSize QTabWidget::minimumSizeHint() const .expandedTo(QApplication::globalStrut()); } +int QTabWidget::heightForWidth(int width) const +{ + Q_D(const QTabWidget); + QStyleOption opt(0); + opt.init(this); + opt.state = QStyle::State_None; + + QSize zero(0,0); + const QSize padding = style()->sizeFromContents(QStyle::CT_TabWidget, &opt, zero, this) + .expandedTo(QApplication::globalStrut()); + + QSize lc(0, 0), rc(0, 0); + if (d->leftCornerWidget) + lc = d->leftCornerWidget->sizeHint(); + if(d->rightCornerWidget) + rc = d->rightCornerWidget->sizeHint(); + if (!d->dirty) { + QTabWidget *that = (QTabWidget*)this; + that->setUpLayout(true); + } + QSize t(d->tabs->sizeHint()); + + if(usesScrollButtons()) + t = t.boundedTo(QSize(200,200)); + else + t = t.boundedTo(QApplication::desktop()->size()); + + const bool tabIsHorizontal = (d->pos == North || d->pos == South); + const int contentsWidth = width - padding.width(); + int stackWidth = contentsWidth; + if (!tabIsHorizontal) + stackWidth -= qMax(t.width(), qMax(lc.width(), rc.width())); + + int stackHeight = d->stack->heightForWidth(stackWidth); + QSize s(stackWidth, stackHeight); + + QSize contentSize = basicSize(tabIsHorizontal, lc, rc, s, t); + return (contentSize + padding).expandedTo(QApplication::globalStrut()).height(); +} + /*! \reimp */ @@ -905,6 +946,14 @@ void QTabWidgetPrivate::updateTabBarPosition() q->setUpLayout(); } +bool QTabWidgetPrivate::hasHeightForWidth() const +{ + bool has = size_policy.hasHeightForWidth(); + if (!has && stack) + has = stack->hasHeightForWidth(); + return has; +} + /*! \property QTabWidget::tabPosition \brief the position of the tabs in this tab widget diff --git a/src/gui/widgets/qtabwidget.h b/src/gui/widgets/qtabwidget.h index 68200c8..ee50655 100644 --- a/src/gui/widgets/qtabwidget.h +++ b/src/gui/widgets/qtabwidget.h @@ -129,6 +129,7 @@ public: QSize sizeHint() const; QSize minimumSizeHint() const; + int heightForWidth(int width) const; void setCornerWidget(QWidget * w, Qt::Corner corner = Qt::TopRightCorner); QWidget * cornerWidget(Qt::Corner corner = Qt::TopRightCorner) const; diff --git a/src/multimedia/multimedia/audio/qaudiodevicefactory.cpp b/src/multimedia/multimedia/audio/qaudiodevicefactory.cpp index 74add64..96545b4 100644 --- a/src/multimedia/multimedia/audio/qaudiodevicefactory.cpp +++ b/src/multimedia/multimedia/audio/qaudiodevicefactory.cpp @@ -67,7 +67,7 @@ QT_BEGIN_NAMESPACE -#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) +#ifndef QT_NO_LIBRARY Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader, (QAudioEngineFactoryInterface_iid, QLatin1String("/audio"), Qt::CaseInsensitive)) #endif @@ -139,7 +139,7 @@ QList<QAudioDeviceInfo> QAudioDeviceFactory::availableDevices(QAudio::Mode mode) #endif #endif -#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) +#ifndef QT_NO_LIBRARY QFactoryLoader* l = loader(); foreach (QString const& key, l->keys()) { @@ -158,7 +158,7 @@ QList<QAudioDeviceInfo> QAudioDeviceFactory::availableDevices(QAudio::Mode mode) QAudioDeviceInfo QAudioDeviceFactory::defaultInputDevice() { -#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) +#ifndef QT_NO_LIBRARY QAudioEngineFactoryInterface* plugin = qobject_cast<QAudioEngineFactoryInterface*>(loader()->instance(QLatin1String("default"))); if (plugin) { @@ -178,7 +178,7 @@ QAudioDeviceInfo QAudioDeviceFactory::defaultInputDevice() QAudioDeviceInfo QAudioDeviceFactory::defaultOutputDevice() { -#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) +#ifndef QT_NO_LIBRARY QAudioEngineFactoryInterface* plugin = qobject_cast<QAudioEngineFactoryInterface*>(loader()->instance(QLatin1String("default"))); if (plugin) { @@ -207,7 +207,7 @@ QAbstractAudioDeviceInfo* QAudioDeviceFactory::audioDeviceInfo(const QString &re #endif #endif -#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) +#ifndef QT_NO_LIBRARY QAudioEngineFactoryInterface* plugin = qobject_cast<QAudioEngineFactoryInterface*>(loader()->instance(realm)); @@ -238,7 +238,7 @@ QAbstractAudioInput* QAudioDeviceFactory::createInputDevice(QAudioDeviceInfo con return new QAudioInputPrivate(deviceInfo.handle(), format); #endif #endif -#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) +#ifndef QT_NO_LIBRARY QAudioEngineFactoryInterface* plugin = qobject_cast<QAudioEngineFactoryInterface*>(loader()->instance(deviceInfo.realm())); @@ -260,7 +260,7 @@ QAbstractAudioOutput* QAudioDeviceFactory::createOutputDevice(QAudioDeviceInfo c #endif #endif -#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) +#ifndef QT_NO_LIBRARY QAudioEngineFactoryInterface* plugin = qobject_cast<QAudioEngineFactoryInterface*>(loader()->instance(deviceInfo.realm())); diff --git a/src/network/bearer/qnetworkconfigmanager_p.cpp b/src/network/bearer/qnetworkconfigmanager_p.cpp index a7bd2d5..471927a 100644 --- a/src/network/bearer/qnetworkconfigmanager_p.cpp +++ b/src/network/bearer/qnetworkconfigmanager_p.cpp @@ -54,8 +54,10 @@ QT_BEGIN_NAMESPACE +#ifndef QT_NO_LIBRARY Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader, (QBearerEngineFactoryInterface_iid, QLatin1String("/bearer"))) +#endif QNetworkConfigurationManagerPrivate::QNetworkConfigurationManagerPrivate() : pollTimer(0), mutex(QMutex::Recursive), forcedPolling(0), firstUpdate(true) @@ -354,6 +356,7 @@ void QNetworkConfigurationManagerPrivate::updateConfigurations() updating = false; +#ifndef QT_NO_LIBRARY QFactoryLoader *l = loader(); QBearerEngine *generic = 0; @@ -387,6 +390,7 @@ void QNetworkConfigurationManagerPrivate::updateConfigurations() if (generic) sessionEngines.append(generic); +#endif // QT_NO_LIBRARY } QBearerEngine *engine = qobject_cast<QBearerEngine *>(sender()); diff --git a/src/opengl/gl2paintengineex/qglengineshadersource_p.h b/src/opengl/gl2paintengineex/qglengineshadersource_p.h index 3379296..8dba951 100644 --- a/src/opengl/gl2paintengineex/qglengineshadersource_p.h +++ b/src/opengl/gl2paintengineex/qglengineshadersource_p.h @@ -282,7 +282,7 @@ static const char* const qglslPositionWithTextureBrushVertexShader = "\n\ uniform mediump vec2 halfViewportSize; \n\ uniform highp vec2 invertedTextureSize; \n\ uniform highp mat3 brushTransform; \n\ - varying highp vec2 textureCoords; \n\ + varying highp vec2 brushTextureCoords; \n\ void setPosition(void) \n\ { \n\ highp mat3 pmvMatrix = mat3(pmvMatrix1, pmvMatrix2, pmvMatrix3); \n\ @@ -292,7 +292,7 @@ static const char* const qglslPositionWithTextureBrushVertexShader = "\n\ mediump vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1); \n\ mediump float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \n\ gl_Position = vec4(gl_Position.xy * invertedHTexCoordsZ, 0.0, invertedHTexCoordsZ); \n\ - textureCoords.xy = (hTexCoords.xy * invertedTextureSize) * gl_Position.w; \n\ + brushTextureCoords.xy = (hTexCoords.xy * invertedTextureSize) * gl_Position.w; \n\ }\n"; static const char* const qglslAffinePositionWithTextureBrushVertexShader @@ -303,28 +303,28 @@ static const char* const qglslAffinePositionWithTextureBrushVertexShader // we emulate GL_REPEAT by only taking the fractional part of the texture coords. // TODO: Special case POT textures which don't need this emulation static const char* const qglslTextureBrushSrcFragmentShader = "\n\ - varying highp vec2 textureCoords; \n\ + varying highp vec2 brushTextureCoords; \n\ uniform lowp sampler2D brushTexture; \n\ lowp vec4 srcPixel() { \n\ - return texture2D(brushTexture, fract(textureCoords)); \n\ + return texture2D(brushTexture, fract(brushTextureCoords)); \n\ }\n"; #else static const char* const qglslTextureBrushSrcFragmentShader = "\n\ - varying highp vec2 textureCoords; \n\ + varying highp vec2 brushTextureCoords; \n\ uniform lowp sampler2D brushTexture; \n\ lowp vec4 srcPixel() \n\ { \n\ - return texture2D(brushTexture, textureCoords); \n\ + return texture2D(brushTexture, brushTextureCoords); \n\ }\n"; #endif static const char* const qglslTextureBrushSrcWithPatternFragmentShader = "\n\ - varying highp vec2 textureCoords; \n\ + varying highp vec2 brushTextureCoords; \n\ uniform lowp vec4 patternColor; \n\ uniform lowp sampler2D brushTexture; \n\ lowp vec4 srcPixel() \n\ { \n\ - return patternColor * (1.0 - texture2D(brushTexture, textureCoords).r); \n\ + return patternColor * (1.0 - texture2D(brushTexture, brushTextureCoords).r); \n\ }\n"; // Solid Fill Brush diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index 8460430..4461358 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -1337,9 +1337,12 @@ void QGL2PaintEngineEx::drawStaticTextItem(QStaticTextItem *textItem) d->drawCachedGlyphs(glyphType, textItem, true); } -void QGL2PaintEngineEx::drawTexture(const QRectF &dest, GLuint textureId, const QSize &size, const QRectF &src) +bool QGL2PaintEngineEx::drawTexture(const QRectF &dest, GLuint textureId, const QSize &size, const QRectF &src) { Q_D(QGL2PaintEngineEx); + if (!d->shaderManager) + return false; + ensureActive(); d->transferMode(ImageDrawingMode); @@ -1354,6 +1357,7 @@ void QGL2PaintEngineEx::drawTexture(const QRectF &dest, GLuint textureId, const d->updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE, state()->renderHints & QPainter::SmoothPixmapTransform, textureId); d->drawTexture(dest, srcRect, size, false); + return true; } void QGL2PaintEngineEx::drawTextItem(const QPointF &p, const QTextItem &textItem) diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h index 30f6634..6ba0c42 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h @@ -123,7 +123,6 @@ public: virtual void renderHintsChanged(); virtual void transformChanged(); - virtual void drawTexture(const QRectF &r, GLuint textureId, const QSize &size, const QRectF &sr); virtual void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr); virtual void drawPixmapFragments(const QPainter::PixmapFragment *fragments, int fragmentCount, const QPixmap &pixmap, QPainter::PixmapFragmentHints hints); @@ -136,6 +135,8 @@ public: virtual void drawStaticTextItem(QStaticTextItem *textItem); + bool drawTexture(const QRectF &r, GLuint textureId, const QSize &size, const QRectF &sr); + Type type() const { return OpenGL2; } virtual void setState(QPainterState *s); diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp index bf77eda..7abf4bc 100644 --- a/src/opengl/qgl.cpp +++ b/src/opengl/qgl.cpp @@ -2782,8 +2782,8 @@ void QGLContext::drawTexture(const QRectF &target, GLuint textureId, GLenum text if (!eng->isNativePaintingActive()) { QRectF src(0, 0, target.width(), target.height()); QSize size(target.width(), target.height()); - eng->drawTexture(target, textureId, size, src); - return; + if (eng->drawTexture(target, textureId, size, src)) + return; } } @@ -2858,8 +2858,8 @@ void QGLContext::drawTexture(const QPointF &point, GLuint textureId, GLenum text QRectF dest(point, QSizeF(textureWidth, textureHeight)); QRectF src(0, 0, textureWidth, textureHeight); QSize size(textureWidth, textureHeight); - eng->drawTexture(dest, textureId, size, src); - return; + if (eng->drawTexture(dest, textureId, size, src)) + return; } } @@ -5169,11 +5169,17 @@ Q_OPENGL_EXPORT void qt_set_gl_library_name(const QString& name) Q_OPENGL_EXPORT const QString qt_gl_library_name() { if (qt_gl_lib_name()->isNull()) { -#if defined(Q_WS_X11) || defined(Q_WS_QWS) - return QLatin1String("GL"); -#else // Q_WS_MAC +#ifdef Q_WS_MAC return QLatin1String("/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib"); -#endif +#else +# if defined(QT_OPENGL_ES_1) + return QLatin1String("GLES_CM"); +# elif defined(QT_OPENGL_ES_2) + return QLatin1String("GLESv2"); +# else + return QLatin1String("GL"); +# endif +#endif // defined Q_WS_MAC } return *qt_gl_lib_name(); } diff --git a/src/opengl/qwindowsurface_gl.cpp b/src/opengl/qwindowsurface_gl.cpp index 92a347b..7efa9bc 100644 --- a/src/opengl/qwindowsurface_gl.cpp +++ b/src/opengl/qwindowsurface_gl.cpp @@ -97,7 +97,6 @@ extern Q_GUI_EXPORT bool qt_win_owndc_required; QGLGraphicsSystem::QGLGraphicsSystem(bool useX11GL) : QGraphicsSystem(), m_useX11GL(useX11GL) { - QGLWindowSurface::surfaceFormat.setSampleBuffers(true); #if defined(Q_WS_X11) && !defined(QT_OPENGL_ES) // only override the system defaults if the user hasn't already // picked a visual diff --git a/src/sql/kernel/qsqldatabase.cpp b/src/sql/kernel/qsqldatabase.cpp index 1416ee3..76bc2b0 100644 --- a/src/sql/kernel/qsqldatabase.cpp +++ b/src/sql/kernel/qsqldatabase.cpp @@ -98,7 +98,7 @@ QT_BEGIN_NAMESPACE -#if !defined(QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) +#ifndef QT_NO_LIBRARY Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader, (QSqlDriverFactoryInterface_iid, QLatin1String("/sqldrivers"))) @@ -576,7 +576,7 @@ QStringList QSqlDatabase::drivers() list << QLatin1String("QIBASE"); #endif -#if !defined(QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) +#ifndef QT_NO_LIBRARY if (QFactoryLoader *fl = loader()) { QStringList keys = fl->keys(); for (QStringList::const_iterator i = keys.constBegin(); i != keys.constEnd(); ++i) { @@ -774,7 +774,7 @@ void QSqlDatabasePrivate::init(const QString &type) } } -#if !defined(QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) +#ifndef QT_NO_LIBRARY if (!driver && loader()) { if (QSqlDriverFactoryInterface *factory = qobject_cast<QSqlDriverFactoryInterface*>(loader()->instance(type))) driver = factory->create(type); diff --git a/src/svg/qsvghandler.cpp b/src/svg/qsvghandler.cpp index b6e771f..d545440 100644 --- a/src/svg/qsvghandler.cpp +++ b/src/svg/qsvghandler.cpp @@ -3751,7 +3751,7 @@ bool QSvgHandler::characters(const QStringRef &str) QCss::Parser(css).parse(&sheet); m_selector->styleSheets.append(sheet); return true; - } else if (m_skipNodes.isEmpty() || m_skipNodes.top() == Unknown) + } else if (m_skipNodes.isEmpty() || m_skipNodes.top() == Unknown || m_nodes.isEmpty()) return true; if (m_nodes.top()->type() == QSvgNode::TEXT || m_nodes.top()->type() == QSvgNode::TEXTAREA) { diff --git a/tests/auto/qtableview/tst_qtableview.cpp b/tests/auto/qtableview/tst_qtableview.cpp index 2062e8e..3e5d077 100644 --- a/tests/auto/qtableview/tst_qtableview.cpp +++ b/tests/auto/qtableview/tst_qtableview.cpp @@ -202,6 +202,7 @@ private slots: void taskQTBUG_8585_crashForNoGoodReason(); void taskQTBUG_7774_RtoLVisualRegionForSelection(); void taskQTBUG_8777_scrollToSpans(); + void taskQTBUG_10169_sizeHintForRow(); void mouseWheel_data(); void mouseWheel(); @@ -478,6 +479,11 @@ public: return QTableView::selectedIndexes(); } + int sizeHintForRow(int row) const + { + return QTableView::sizeHintForRow(row); + } + bool checkSignalOrder; public slots: void currentChanged(QModelIndex , QModelIndex ) { @@ -4042,5 +4048,20 @@ void tst_QTableView::taskQTBUG_8777_scrollToSpans() QVERIFY(table.verticalScrollBar()->value() > 10); } +void tst_QTableView::taskQTBUG_10169_sizeHintForRow() +{ + QtTestTableView tableView; + QStandardItemModel model(1, 3); + model.setData(model.index(0, 0), "Word wrapping text goes here."); + tableView.setModel(&model); + tableView.verticalHeader()->setResizeMode(QHeaderView::ResizeToContents); + const int orderedHeight = tableView.sizeHintForRow(0); + tableView.horizontalHeader()->moveSection(2, 0); + const int reorderedHeight = tableView.sizeHintForRow(0); + + //the order of the columns shouldn't matter. + QCOMPARE(orderedHeight, reorderedHeight); +} + QTEST_MAIN(tst_QTableView) #include "tst_qtableview.moc" diff --git a/tests/auto/qtabwidget/tst_qtabwidget.cpp b/tests/auto/qtabwidget/tst_qtabwidget.cpp index 504579f..54e7259 100644 --- a/tests/auto/qtabwidget/tst_qtabwidget.cpp +++ b/tests/auto/qtabwidget/tst_qtabwidget.cpp @@ -45,6 +45,7 @@ #include <qdebug.h> #include <qapplication.h> #include <qlabel.h> +#include <qboxlayout.h> //TESTED_CLASS= //TESTED_FILES= @@ -120,6 +121,8 @@ class tst_QTabWidget:public QObject { void clear(); void keyboardNavigation(); void paintEventCount(); + void heightForWidth(); + void heightForWidth_data(); private: int addPage(); @@ -624,6 +627,50 @@ void tst_QTabWidget::paintEventCount() QCOMPARE(tab2->count, 1); } +void tst_QTabWidget::heightForWidth_data() +{ + QTest::addColumn<int>("tabPosition"); + QTest::newRow("West") << int(QTabWidget::West); + QTest::newRow("North") << int(QTabWidget::North); + QTest::newRow("East") << int(QTabWidget::East); + QTest::newRow("South") << int(QTabWidget::South); +} + +void tst_QTabWidget::heightForWidth() +{ + QFETCH(int, tabPosition); + + QWidget *window = new QWidget; + QVBoxLayout *lay = new QVBoxLayout(window); + lay->setMargin(0); + lay->setSpacing(0); + QTabWidget *tabWid = new QTabWidget(window); + QWidget *w = new QWidget; + tabWid->addTab(w, QLatin1String("HFW page")); + tabWid->setTabPosition(QTabWidget::TabPosition(tabPosition)); + QVBoxLayout *lay2 = new QVBoxLayout(w); + QLabel *label = new QLabel("Label with wordwrap turned on makes it trade height for width." + " Make it a really long text so that it spans on several lines" + " when the label is on its narrowest." + " I don't like to repeat myself." + " I don't like to repeat myself." + " I don't like to repeat myself." + " I don't like to repeat myself." + ); + label->setWordWrap(true); + lay2->addWidget(label); + lay2->setMargin(0); + + lay->addWidget(tabWid); + int h = window->heightForWidth(160); + window->resize(160, h); + window->show(); + + QTest::qWaitForWindowShown(window); + QVERIFY(label->height() >= label->heightForWidth(label->width())); + + delete window; +} QTEST_MAIN(tst_QTabWidget) #include "tst_qtabwidget.moc" diff --git a/tests/auto/qurl/tst_qurl.cpp b/tests/auto/qurl/tst_qurl.cpp index b7cbdb8..fa42adc 100644 --- a/tests/auto/qurl/tst_qurl.cpp +++ b/tests/auto/qurl/tst_qurl.cpp @@ -1632,6 +1632,10 @@ void tst_QUrl::toString_data() QTest::newRow("nopath_task31320") << QString::fromLatin1("host://protocol") << uint(QUrl::None) << QString::fromLatin1("host://protocol"); + + QTest::newRow("underscore_QTBUG-7434") << QString::fromLatin1("http://foo_bar.host.com/rss.php") + << uint(QUrl::None) + << QString::fromLatin1("http://foo_bar.host.com/rss.php"); } void tst_QUrl::toString() @@ -3244,7 +3248,6 @@ void tst_QUrl::std3violations_data() QTest::newRow("question") << "foo?bar" << true; QTest::newRow("at") << "foo@bar" << true; QTest::newRow("backslash") << "foo\\bar" << false; - QTest::newRow("underline") << "foo_bar" << false; // these characters are transformed by NFKC to non-LDH characters QTest::newRow("dot-like") << QString::fromUtf8("foo\342\200\244bar") << false; // U+2024 ONE DOT LEADER @@ -3289,6 +3292,7 @@ void tst_QUrl::std3deviations_data() QTest::newRow("ending-dot") << "example.com."; QTest::newRow("ending-dot3002") << QString("example.com") + QChar(0x3002); + QTest::newRow("underline") << "foo_bar"; //QTBUG-7434 } void tst_QUrl::std3deviations() diff --git a/tests/auto/qvector/tst_qvector.cpp b/tests/auto/qvector/tst_qvector.cpp index ebc19ed..2bc8d15 100644 --- a/tests/auto/qvector/tst_qvector.cpp +++ b/tests/auto/qvector/tst_qvector.cpp @@ -55,10 +55,610 @@ public: virtual ~tst_QVector() {} private slots: + void constructors() const; + void append() const; + void at() const; + void capacity() const; + void clear() const; + void constData() const; + void contains() const; + void count() const; + void data() const; + void empty() const; + void endsWith() const; + void fill() const; + void first() const; + void fromList() const; + void fromStdVector() const; + void indexOf() const; + void insert() const; + void isEmpty() const; + void last() const; + void lastIndexOf() const; + void mid() const; + void prepend() const; + void remove() const; + void size() const; + void startsWith() const; + void toList() const; + void toStdVector() const; + void value() const; + + void testOperators() const; + void outOfMemory(); void QTBUG6416_reserve(); }; +void tst_QVector::constructors() const +{ + // pre-reserve capacity + { + QVector<int> myvec(5); + + QVERIFY(myvec.capacity() == 5); + } + + // default-initialise items + { + QVector<int> myvec(5, 42); + + QVERIFY(myvec.capacity() == 5); + + // make sure all items are initialised ok + foreach (int meaningoflife, myvec) { + QCOMPARE(meaningoflife, 42); + } + } +} + +void tst_QVector::append() const +{ + QVector<int> myvec; + myvec.append(42); + myvec.append(43); + myvec.append(44); + + QVERIFY(myvec.size() == 3); + QCOMPARE(myvec, QVector<int>() << 42 << 43 << 44); +} + +void tst_QVector::at() const +{ + QVector<QString> myvec; + myvec << "foo" << "bar" << "baz"; + + QVERIFY(myvec.size() == 3); + QCOMPARE(myvec.at(0), QLatin1String("foo")); + QCOMPARE(myvec.at(1), QLatin1String("bar")); + QCOMPARE(myvec.at(2), QLatin1String("baz")); + + // append an item + myvec << "hello"; + QVERIFY(myvec.size() == 4); + QCOMPARE(myvec.at(0), QLatin1String("foo")); + QCOMPARE(myvec.at(1), QLatin1String("bar")); + QCOMPARE(myvec.at(2), QLatin1String("baz")); + QCOMPARE(myvec.at(3), QLatin1String("hello")); + + // remove an item + myvec.remove(1); + QVERIFY(myvec.size() == 3); + QCOMPARE(myvec.at(0), QLatin1String("foo")); + QCOMPARE(myvec.at(1), QLatin1String("baz")); + QCOMPARE(myvec.at(2), QLatin1String("hello")); +} + +void tst_QVector::capacity() const +{ + QVector<QString> myvec; + + // TODO: is this guarenteed? seems a safe assumption, but I suppose preallocation of a + // few items isn't an entirely unforseeable possibility. + QVERIFY(myvec.capacity() == 0); + + // test it gets a size + myvec << "aaa" << "bbb" << "ccc"; + QVERIFY(myvec.capacity() >= 3); + + // make sure it grows ok + myvec << "aaa" << "bbb" << "ccc"; + QVERIFY(myvec.capacity() >= 6); + + // let's try squeeze a bit + myvec.remove(3); + myvec.remove(3); + myvec.remove(3); + // TODO: is this a safe assumption? presumably it won't release memory until shrink(), but can we asser that is true? + QVERIFY(myvec.capacity() >= 6); + myvec.squeeze(); + QVERIFY(myvec.capacity() >= 3); + + myvec.remove(0); + myvec.remove(0); + myvec.remove(0); + // TODO: as above note + QVERIFY(myvec.capacity() >= 3); + myvec.squeeze(); + QVERIFY(myvec.capacity() == 0); +} + +void tst_QVector::clear() const +{ + QVector<QString> myvec; + myvec << "aaa" << "bbb" << "ccc"; + + QVERIFY(myvec.size() == 3); + myvec.clear(); + QVERIFY(myvec.size() == 0); + QVERIFY(myvec.capacity() == 0); +} + +void tst_QVector::constData() const +{ + int arr[] = { 42, 43, 44 }; + QVector<int> myvec; + myvec << 42 << 43 << 44; + + QVERIFY(memcmp(myvec.constData(), reinterpret_cast<const int *>(&arr), sizeof(int) * 3) == 0); +} + +void tst_QVector::contains() const +{ + QVector<QString> myvec; + myvec << "aaa" << "bbb" << "ccc"; + + QVERIFY(myvec.contains(QLatin1String("aaa"))); + QVERIFY(myvec.contains(QLatin1String("bbb"))); + QVERIFY(myvec.contains(QLatin1String("ccc"))); + QVERIFY(!myvec.contains(QLatin1String("I don't exist"))); + + // add it and make sure it does :) + myvec.append(QLatin1String("I don't exist")); + QVERIFY(myvec.contains(QLatin1String("I don't exist"))); +} + +void tst_QVector::count() const +{ + // total size + { + // zero size + QVector<int> myvec; + QVERIFY(myvec.count() == 0); + + // grow + myvec.append(42); + QVERIFY(myvec.count() == 1); + myvec.append(42); + QVERIFY(myvec.count() == 2); + + // shrink + myvec.remove(0); + QVERIFY(myvec.count() == 1); + myvec.remove(0); + QVERIFY(myvec.count() == 0); + } + + // count of items + { + QVector<QString> myvec; + myvec << "aaa" << "bbb" << "ccc"; + + // initial tests + QVERIFY(myvec.count(QLatin1String("aaa")) == 1); + QVERIFY(myvec.count(QLatin1String("pirates")) == 0); + + // grow + myvec.append(QLatin1String("aaa")); + QVERIFY(myvec.count(QLatin1String("aaa")) == 2); + + // shrink + myvec.remove(0); + QVERIFY(myvec.count(QLatin1String("aaa")) == 1); + } +} + +void tst_QVector::data() const +{ + QVector<int> myvec; + myvec << 42 << 43 << 44; + + // make sure it starts off ok + QCOMPARE(*(myvec.data() + 1), 43); + + // alter it + *(myvec.data() + 1) = 69; + + // check it altered + QCOMPARE(*(myvec.data() + 1), 69); + + int arr[] = { 42, 69, 44 }; + QVERIFY(memcmp(myvec.data(), reinterpret_cast<int *>(&arr), sizeof(int) * 3) == 0); +} + +void tst_QVector::empty() const +{ + QVector<int> myvec; + + // starts empty + QVERIFY(myvec.empty()); + + // not empty + myvec.append(1); + QVERIFY(!myvec.empty()); + + // empty again + myvec.remove(0); + QVERIFY(myvec.empty()); +} + +void tst_QVector::endsWith() const +{ + QVector<int> myvec; + + // empty vector + QVERIFY(!myvec.endsWith(1)); + + // add the one, should work + myvec.append(1); + QVERIFY(myvec.endsWith(1)); + + // add something else, fails now + myvec.append(3); + QVERIFY(!myvec.endsWith(1)); + + // remove it again :) + myvec.remove(1); + QVERIFY(myvec.endsWith(1)); +} + +void tst_QVector::fill() const +{ + QVector<int> myvec; + + // resize + myvec.resize(5); + myvec.fill(69); + QCOMPARE(myvec, QVector<int>() << 69 << 69 << 69 << 69 << 69); + + // make sure it can resize itself too + myvec.fill(42, 10); + QCOMPARE(myvec, QVector<int>() << 42 << 42 << 42 << 42 << 42 << 42 << 42 << 42 << 42 << 42); +} + +void tst_QVector::first() const +{ + QVector<int> myvec; + myvec << 69 << 42 << 3; + + // test it starts ok + QCOMPARE(myvec.first(), 69); + + // test removal changes + myvec.remove(0); + QCOMPARE(myvec.first(), 42); + + // test prepend changes + myvec.prepend(23); + QCOMPARE(myvec.first(), 23); +} + +void tst_QVector::fromList() const +{ + QList<QString> list; + list << "aaa" << "bbb" << "ninjas" << "pirates"; + + QVector<QString> myvec; + myvec = QVector<QString>::fromList(list); + + // test it worked ok + QCOMPARE(myvec, QVector<QString>() << "aaa" << "bbb" << "ninjas" << "pirates"); + QCOMPARE(list, QList<QString>() << "aaa" << "bbb" << "ninjas" << "pirates"); +} + +void tst_QVector::fromStdVector() const +{ + // stl = :( + std::vector<QString> svec; + svec.push_back(QLatin1String("aaa")); + svec.push_back(QLatin1String("bbb")); + svec.push_back(QLatin1String("ninjas")); + svec.push_back(QLatin1String("pirates")); + QVector<QString> myvec = QVector<QString>::fromStdVector(svec); + + // test it converts ok + QCOMPARE(myvec, QVector<QString>() << "aaa" << "bbb" << "ninjas" << "pirates"); +} + +void tst_QVector::indexOf() const +{ + QVector<QString> myvec; + myvec << "A" << "B" << "C" << "B" << "A"; + + QVERIFY(myvec.indexOf("B") == 1); + QVERIFY(myvec.indexOf("B", 1) == 1); + QVERIFY(myvec.indexOf("B", 2) == 3); + QVERIFY(myvec.indexOf("X") == -1); + QVERIFY(myvec.indexOf("X", 2) == -1); + + // add an X + myvec << "X"; + QVERIFY(myvec.indexOf("X") == 5); + QVERIFY(myvec.indexOf("X", 5) == 5); + QVERIFY(myvec.indexOf("X", 6) == -1); + + // remove first A + myvec.remove(0); + QVERIFY(myvec.indexOf("A") == 3); + QVERIFY(myvec.indexOf("A", 3) == 3); + QVERIFY(myvec.indexOf("A", 4) == -1); +} + +void tst_QVector::insert() const +{ + QVector<QString> myvec; + myvec << "A" << "B" << "C"; + + // first position + QCOMPARE(myvec.at(0), QLatin1String("A")); + myvec.insert(0, QLatin1String("X")); + QCOMPARE(myvec.at(0), QLatin1String("X")); + QCOMPARE(myvec.at(1), QLatin1String("A")); + + // middle + myvec.insert(1, QLatin1String("Z")); + QCOMPARE(myvec.at(0), QLatin1String("X")); + QCOMPARE(myvec.at(1), QLatin1String("Z")); + QCOMPARE(myvec.at(2), QLatin1String("A")); + + // end + myvec.insert(5, QLatin1String("T")); + QCOMPARE(myvec.at(5), QLatin1String("T")); + QCOMPARE(myvec.at(4), QLatin1String("C")); + + // insert a lot of garbage in the middle + myvec.insert(2, 2, QLatin1String("infinity")); + QCOMPARE(myvec, QVector<QString>() << "X" << "Z" << "infinity" << "infinity" + << "A" << "B" << "C" << "T"); +} + +void tst_QVector::isEmpty() const +{ + QVector<QString> myvec; + + // starts ok + QVERIFY(myvec.isEmpty()); + + // not empty now + myvec.append(QLatin1String("hello there")); + QVERIFY(!myvec.isEmpty()); + + // empty again + myvec.remove(0); + QVERIFY(myvec.isEmpty()); +} + +void tst_QVector::last() const +{ + QVector<QString> myvec; + myvec << "A" << "B" << "C"; + + // test starts ok + QCOMPARE(myvec.last(), QLatin1String("C")); + + // test it changes ok + myvec.append(QLatin1String("X")); + QCOMPARE(myvec.last(), QLatin1String("X")); + + // and remove again + myvec.remove(3); + QCOMPARE(myvec.last(), QLatin1String("C")); +} + +void tst_QVector::lastIndexOf() const +{ + QVector<QString> myvec; + myvec << "A" << "B" << "C" << "B" << "A"; + + QVERIFY(myvec.lastIndexOf("B") == 3); + QVERIFY(myvec.lastIndexOf("B", 2) == 1); + QVERIFY(myvec.lastIndexOf("X") == -1); + QVERIFY(myvec.lastIndexOf("X", 2) == -1); + + // add an X + myvec << "X"; + QVERIFY(myvec.lastIndexOf("X") == 5); + QVERIFY(myvec.lastIndexOf("X", 5) == 5); + QVERIFY(myvec.lastIndexOf("X", 3) == -1); + + // remove first A + myvec.remove(0); + QVERIFY(myvec.lastIndexOf("A") == 3); + QVERIFY(myvec.lastIndexOf("A", 3) == 3); + QVERIFY(myvec.lastIndexOf("A", 2) == -1); +} + +void tst_QVector::mid() const +{ + QVector<QString> list; + list << "foo" << "bar" << "baz" << "bak" << "buck" << "hello" << "kitty"; + + QCOMPARE(list.mid(3, 3), QVector<QString>() << "bak" << "buck" << "hello"); + QCOMPARE(list.mid(4), QVector<QString>() << "buck" << "hello" << "kitty"); +} + +void tst_QVector::prepend() const +{ + QVector<QString> myvec; + myvec << "A" << "B" << "C"; + + // starts ok + QVERIFY(myvec.size() == 3); + QCOMPARE(myvec.at(0), QLatin1String("A")); + + // add something + myvec.prepend(QLatin1String("X")); + QCOMPARE(myvec.at(0), QLatin1String("X")); + QCOMPARE(myvec.at(1), QLatin1String("A")); + QVERIFY(myvec.size() == 4); + + // something else + myvec.prepend(QLatin1String("Z")); + QCOMPARE(myvec.at(0), QLatin1String("Z")); + QCOMPARE(myvec.at(1), QLatin1String("X")); + QCOMPARE(myvec.at(2), QLatin1String("A")); + QVERIFY(myvec.size() == 5); + + // clear and append to an empty vector + myvec.clear(); + QVERIFY(myvec.size() == 0); + myvec.prepend(QLatin1String("ninjas")); + QVERIFY(myvec.size() == 1); + QCOMPARE(myvec.at(0), QLatin1String("ninjas")); +} + +void tst_QVector::remove() const +{ + QVector<QString> myvec; + myvec << "A" << "B" << "C"; + + // remove middle + myvec.remove(1); + QCOMPARE(myvec, QVector<QString>() << "A" << "C"); + + // remove rest + myvec.remove(0, 2); + QCOMPARE(myvec, QVector<QString>()); +} + +// ::reserve() is really hard to think of tests for, so not doing it. +// ::resize() is tested in ::capacity(). + +void tst_QVector::size() const +{ + // total size + { + // zero size + QVector<int> myvec; + QVERIFY(myvec.size() == 0); + + // grow + myvec.append(42); + QVERIFY(myvec.size() == 1); + myvec.append(42); + QVERIFY(myvec.size() == 2); + + // shrink + myvec.remove(0); + QVERIFY(myvec.size() == 1); + myvec.remove(0); + QVERIFY(myvec.size() == 0); + } +} + +// ::squeeze() is tested in ::capacity(). + +void tst_QVector::startsWith() const +{ + QVector<int> myvec; + + // empty vector + QVERIFY(!myvec.startsWith(1)); + + // add the one, should work + myvec.prepend(1); + QVERIFY(myvec.startsWith(1)); + + // add something else, fails now + myvec.prepend(3); + QVERIFY(!myvec.startsWith(1)); + + // remove it again :) + myvec.remove(0); + QVERIFY(myvec.startsWith(1)); +} + +void tst_QVector::toList() const +{ + QVector<QString> myvec; + myvec << "A" << "B" << "C"; + + // make sure it converts and doesn't modify the original vector + QCOMPARE(myvec.toList(), QList<QString>() << "A" << "B" << "C"); + QCOMPARE(myvec, QVector<QString>() << "A" << "B" << "C"); +} + +void tst_QVector::toStdVector() const +{ + QVector<QString> myvec; + myvec << "A" << "B" << "C"; + + std::vector<QString> svec = myvec.toStdVector(); + QCOMPARE(svec.at(0), QLatin1String("A")); + QCOMPARE(svec.at(1), QLatin1String("B")); + QCOMPARE(svec.at(2), QLatin1String("C")); + + QCOMPARE(myvec, QVector<QString>() << "A" << "B" << "C"); +} + +void tst_QVector::value() const +{ + QVector<QString> myvec; + myvec << "A" << "B" << "C"; + + // valid calls + QCOMPARE(myvec.value(0), QLatin1String("A")); + QCOMPARE(myvec.value(1), QLatin1String("B")); + QCOMPARE(myvec.value(2), QLatin1String("C")); + + // default calls + QCOMPARE(myvec.value(-1), QString()); + QCOMPARE(myvec.value(3), QString()); + + // test calls with a provided default, valid calls + QCOMPARE(myvec.value(0, QLatin1String("default")), QLatin1String("A")); + QCOMPARE(myvec.value(1, QLatin1String("default")), QLatin1String("B")); + QCOMPARE(myvec.value(2, QLatin1String("default")), QLatin1String("C")); + + // test calls with a provided default that will return the default + QCOMPARE(myvec.value(-1, QLatin1String("default")), QLatin1String("default")); + QCOMPARE(myvec.value(3, QLatin1String("default")), QLatin1String("default")); +} + +void tst_QVector::testOperators() const +{ + QVector<QString> myvec; + myvec << "A" << "B" << "C"; + QVector<QString> myvectwo; + myvectwo << "D" << "E" << "F"; + QVector<QString> combined; + combined << "A" << "B" << "C" << "D" << "E" << "F"; + + // != + QVERIFY(myvec != myvectwo); + + // + + QCOMPARE(myvec + myvectwo, combined); + QCOMPARE(myvec, QVector<QString>() << "A" << "B" << "C"); + QCOMPARE(myvectwo, QVector<QString>() << "D" << "E" << "F"); + + // += + myvec += myvectwo; + QCOMPARE(myvec, combined); + + // == + QVERIFY(myvec == combined); + + // [] + QCOMPARE(myvec[0], QLatin1String("A")); + QCOMPARE(myvec[1], QLatin1String("B")); + QCOMPARE(myvec[2], QLatin1String("C")); + QCOMPARE(myvec[3], QLatin1String("D")); + QCOMPARE(myvec[4], QLatin1String("E")); + QCOMPARE(myvec[5], QLatin1String("F")); +} + + int fooCtor; int fooDtor; |