/****************************************************************************
**
** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved.
**
** This file is part of the documentation of the Qt Toolkit.
**
** This file may be used under the terms of the GNU General Public
** License versions 2.0 or 3.0 as published by the Free Software
** Foundation and appearing in the files LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file.  Alternatively you may (at
** your option) use any later version of the GNU General Public
** License if such license has been publicly approved by Trolltech ASA
** (or its successors, if any) and the KDE Free Qt Foundation. In
** addition, as a special exception, Trolltech gives you certain
** additional rights. These rights are described in the Trolltech GPL
** Exception version 1.2, which can be found at
** http://www.trolltech.com/products/qt/gplexception/ and in the file
** GPL_EXCEPTION.txt in this package.
**
** Please review the following information to ensure GNU General
** Public Licensing requirements will be met:
** http://trolltech.com/products/qt/licenses/licensing/opensource/. If
** you are unsure which license is appropriate for your use, please
** review the following information:
** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
** or contact the sales department at sales@trolltech.com.
**
** In addition, as a special exception, Trolltech, as the sole
** copyright holder for Qt Designer, grants users of the Qt/Eclipse
** Integration plug-in the right for the Qt/Eclipse Integration to
** link to functionality provided by Qt Designer and its related
** libraries.
**
** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE. Trolltech reserves all rights not expressly
** granted herein.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/

/*!
    \example draganddrop/fridgemagnets
    \title Fridge Magnets Example

    \title Fridge Magnets Example

    The Fridge Magnets example shows how to supply more than one type
    of MIME-encoded data with a drag and drop operation.

    \image fridgemagnets-example.png

    With this application the user can play around with a collection
    of fridge magnets, using drag and drop to form new sentences from
    the words on the magnets. The example consists of two classes:

    \list
        \o \c DragLabel is a custom widget representing one
           single fridge magnet.
        \o \c DragWidget provides the main application window.
    \endlist

    We will first take a look at the \c DragWidget class, then we will
    take a quick look at the \c DragLabel class.

    \section1 DragWidget Class Definition

    The \c DragWidget class inherits QWidget, providing support for
    drag and drop operations:

    \snippet examples/draganddrop/fridgemagnets/dragwidget.h 0

    To enable drag and drop, we simply reimplement the \l
    {QWidget::}{dragEnterEvent()}, \l {QWidget::}{dragMoveEvent()} and
    \l {QWidget::}{dropEvent()} event handlers inherited from QWidget.

    \section1 DragWidget Class Implementation

    In the constructor, we first open the file containing the words on
    our fridge magnets:

    \snippet examples/draganddrop/fridgemagnets/dragwidget.cpp 0

    QFile is an I/O device for reading and writing text and binary
    files and resources, and may be used by itself or in combination
    with QTextStream or QDataStream. We have chosen to read the
    contents of the file using the QTextStream class that provides a
    convenient interface for reading and writing text.

    \snippet examples/draganddrop/fridgemagnets/dragwidget.cpp 1

    Then we create the fridge magnets: As long as there is data (the
    QTextStream::atEnd() method returns true if there is no more data
    to be read from the stream), we read one line at a time using
    QTextStream's \l {QTextStream::}{readLine()} method. For each
    line, we create a \c DragLabel object using the read line as text,
    we calculate its position and ensure that it is visible by calling
    the QWidget::show() method.

    \snippet examples/draganddrop/fridgemagnets/dragwidget.cpp 2

    We also set the \c FridgeMagnets widget's palette, minimum size
    and window title.

    \snippet examples/draganddrop/fridgemagnets/dragwidget.cpp 3

    Finally, to enable our user to move the fridge magnets around, we
    must also set the \c FridgeMagnets widget's \l
    {QWidget::acceptDrops}{acceptDrops} property. Setting this
    property to true announces to the system that this widget \e may
    be able to accept drop events (events that are sent when drag and
    drop actions are completed).

    When a a drag and drop action enters our widget, we will receive a
    drag enter \e event. QDragEnterEvent inherits most of its
    functionality from QDragMoveEvent, which in turn inherits most of
    its functionality from QDropEvent. Note that we must accept this
    event in order to receive the drag move events that are sent while
    the drag and drop action is in progress. The drag enter event is
    always immediately followed by a drag move event.

    In our \c dragEnterEvent() implementation, we first determine
    whether we support the event's MIME type or not:

    \snippet examples/draganddrop/fridgemagnets/dragwidget.cpp 4
    \snippet examples/draganddrop/fridgemagnets/dragwidget.cpp 5
    \snippet examples/draganddrop/fridgemagnets/dragwidget.cpp 6

    If the type is \c "application/x-fridgemagnet" and the event
    origins from any of this application's fridge magnet widgets, we
    first set the event's drop action using the
    QDropEvent::setDropAction() method. An event's drop action is the
    action to be performed on the data by the target. Qt::MoveAction
    indicates that the data is moved from the source to the target.

    Then we call the event's \l {QDragMoveEvent::}{accept()} method to
    indicate that we have handled the event. In general, unaccepted
    events might be propagated to the parent widget. If the event
    origins from any other widget, we simply accept the proposed
    action.

    \snippet examples/draganddrop/fridgemagnets/dragwidget.cpp 7

    We also accept the proposed action if the event's MIME type is \c
    text/plain, i.e., if QMimeData::hasText() returns true. If the
    event has any other type, on the other hand, we call the event's
    \l {QDragMoveEvent::}{ignore()} method allowing the event to be
    propagated further.

    \snippet examples/draganddrop/fridgemagnets/dragwidget.cpp 8

    Drag move events occur when the cursor enters a widget, when it
    moves within the widget, and when a modifier key is pressed on the
    keyboard while the widget has focus. Our widget will receive drag
    move events repeatedly while a drag is within its boundaries. We
    reimplement the \l {QWidget::}{dragMoveEvent()} method, and
    examine the event in the exact same way as we did with drag enter
    events.

    \target drop
    \snippet examples/draganddrop/fridgemagnets/dragwidget.cpp 9

    Note that the \l {QWidget::}{dropEvent()} event handler behaves
    slightly different: We first get hold of the event's MIME
    data. The QMimeData class provides a container for data that
    records information about its MIME type. QMimeData objects
    associate the data that they hold with the corresponding MIME
    types to ensure that information can be safely transferred between
    applications, and copied around within the same application.

    \snippet examples/draganddrop/fridgemagnets/dragwidget.cpp 10
    \snippet examples/draganddrop/fridgemagnets/dragwidget.cpp 11

    Then we retrieve the data associated with the \c
    "application/x-fridgemagnet" MIME type using a data stream, and
    create a new \c DragLabel object. The QDataStream class provides
    serialization of binary data to a QIODevice (a data stream is a
    binary stream of encoded information which is 100% independent of
    the host computer's operating system, CPU or byte order).

    Finally, we move the magnet to the event's position before we
    check if the event origins from any of this application's fridge
    magnet widgets. If it does, we set the event's drop action to
    Qt::MoveAction and call the event's \l
    {QDragMoveEvent::}{accept()} method. Otherwise, we simply accept
    the proposed action.

    \snippet examples/draganddrop/fridgemagnets/dragwidget.cpp 12

    If the event's MIME type is \c text/plain, i.e., if
    QMimeData::hasText() returns true, we retrieve its text and split
    it into words. For each word we create a new \c DragLabel action,
    and show it at the event's position plus an offset depending on
    the number of words in the text. In the end we accept the proposed
    action.

    If the event has any other type, we call the event's \l
    {QDragMoveEvent::}{ignore()} method allowing the event to be
    propagated further.

    This completes the \c DragWidget implementation. Now, let's take a
    quick look at the \c DragLabel class.

    \section1 DragLabel Class Definition

    Each fridge magnet is represented by an instance of the \c
    DragLabel class:

    \snippet examples/draganddrop/fridgemagnets/draglabel.h 0

    Earlier we set our main application widget's \l
    {QWidget::acceptDrops}{acceptDrops} property and reimplemented
    QWidget's \l {QWidget::)}{dragEnterEvent()}, \l
    {QWidget::}{dragMoveEvent()} and \l {QWidget::}{dropEvent()} event
    handlers to support drag and drop. In addition, we must
    reimplement the \l {QWidget::}{mousePressEvent()} method in our
    fridge magnet widget to make the user able to pick it up in the
    first place.

    \section1 DragLabel Class Implementation

    In the \c DragLabel constructor, we first create a QImage object
    on which we will draw the fridge magnet's text and frame:

    \snippet examples/draganddrop/fridgemagnets/draglabel.cpp 0

    Its size depends on the current font size, and its format is
    QImage::Format_ARGB32_Premultiplied (i.e., the image is stored
    using a premultiplied 32-bit ARGB format (0xAARRGGBB)).

    Then we constructs a font object that uses the application's
    default font, and set its style strategy. The style strategy tells
    the font matching algorithm what type of fonts should be used to
    find an appropriate default family. The QFont::ForceOutline forces
    the use of outline fonts.

    \snippet examples/draganddrop/fridgemagnets/draglabel.cpp 1

    To draw the text and frame onto the image, we use the QPainter
    class. QPainter provides highly optimized methods to do most of
    the drawing GUI programs require. It can draw everything from
    simple lines to complex shapes like pies and chords. It can also
    draw aligned text and pixmaps.

    A painter can be activated by passing a paint device to the
    constructor, or by using the \l {QPainter::}{begin()} method as we
    do in this example. The \l {QPainter::}{end()} method deactivates
    it. Note that the latter function is called automatically upon
    destruction when the painter is actived by its constructor. The
    QPainter::Antialiasing render hint ensures that the paint engine
    will antialias the edges of primitives if possible.

    \snippet examples/draganddrop/fridgemagnets/draglabel.cpp 2

    When the painting is done, we convert our image to a pixmap using
    QPixmap's \l {QPixmap::}{fromImage()} method. This method also
    takes an optional flags argument, and converts the given image to
    a pixmap using the specified flags to control the conversion (the
    flags argument is a bitwise-OR of the Qt::ImageConversionFlags;
    passing 0 for flags sets all the default options).

    Finally, we set the label's \l {QLabel::pixmap}{pixmap property}
    and store the label's text for later use. Note that setting the
    pixmap clears any previous content, and disables the label
    widget's buddy shortcut, if any.

    Now, let's take a look at the \l {QWidget::}{mousePressEvent()}
    event handler:

    \snippet examples/draganddrop/fridgemagnets/draglabel.cpp 3
    \snippet examples/draganddrop/fridgemagnets/draglabel.cpp 4

    Mouse events occur when a mouse button is pressed or released
    inside a widget, or when the mouse cursor is moved. By
    reimplementing the \l {QWidget::}{mousePressEvent()} method we
    ensure that we will receive mouse press events for the fridge
    magnet widget.

    Whenever we receive such an event, we will first create a byte
    array to store our item data, and a QDataStream object to stream
    the data to the byte array.

    \snippet examples/draganddrop/fridgemagnets/draglabel.cpp 5

    Then we create a new QMimeData object. As mentioned above,
    QMimeData objects associate the data that they hold with the
    corresponding MIME types to ensure that information can be safely
    transferred between applications. The \l {QMimeData::}{setData()}
    method sets the data associated with a given MIME type. In our
    case, we associate our item data with the custom \c
    "application/x-fridgemagnet" type.

    Note that we also associate the magnet's text with the \c
    text/plain MIME type using QMimeData's \l {QMimeData::}{setText()}
    method. We have already seen how our main widget detects both
    these MIME types with its event handlers.

    \snippet examples/draganddrop/fridgemagnets/draglabel.cpp 6


    Finally, we create a QDrag object. It is the QDrag class that
    handles most of the details of a drag and drop operation,
    providing support for MIME-based drag and drop data transfer. The
    data to be transferred by the drag and drop operation is contained
    in a QMimeData object. When we call QDrag's \l
    {QDrag::}{setMimeData()} method the ownership of our item data is
    transferred to the QDrag object.

    We also specify the cursor's hot spot, i.e., its position while
    the drag is in progress, to be the top-left corner of our fridge
    magnet. We call the \l {QDrag::}{setPixmap()} method to set
    the pixmap used to represent the data during the drag and drop
    operation. Typically, this pixmap shows an icon that represents
    the MIME type of the data being transferred, but any pixmap can be
    used. In this example, we have chosen to use the fridge magnet
    image itself to make the magnet appear as moving, immediately
    hiding the activated widget.

    \snippet examples/draganddrop/fridgemagnets/draglabel.cpp 7

    Then we start the drag using QDrag's \l {QDrag::}{exec()} method
    requesting that the magnet is moved when the drag is
    completed. The method returns the performed drop action; if this
    action is equal to Qt::MoveAction we will close the activated
    fridge magnet widget because we then create a new one (with the
    same data) at the drop position (see the implementation of our
    main widgets \l {drop}{dropEvent()} method). Otherwise, if
    the drop is outside our main widget, we simply show the widget in
    its original position.
*/
