You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
384 lines
14 KiB
384 lines
14 KiB
14 years ago
|
/****************************************************************************
|
||
|
**
|
||
|
** Drag and drop documentation
|
||
|
**
|
||
|
** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
|
||
|
**
|
||
|
** This file is part of the Qt GUI 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.
|
||
|
**
|
||
|
** 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.
|
||
|
**
|
||
|
** This file may be used under the terms of the Q Public License as
|
||
|
** defined by Trolltech ASA and appearing in the file LICENSE.QPL
|
||
|
** included in the packaging of this file. Licensees holding valid Qt
|
||
|
** Commercial licenses may use this file in accordance with the Qt
|
||
|
** Commercial License Agreement provided with the Software.
|
||
|
**
|
||
|
** 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 granted
|
||
|
** herein.
|
||
|
**
|
||
|
**********************************************************************/
|
||
|
|
||
|
/*!
|
||
|
\page dnd.html
|
||
|
|
||
|
\title Drag and Drop
|
||
|
|
||
|
Drag and drop provides a simple visual mechanism which users can use
|
||
|
to transfer information between and within applications. (In the
|
||
|
literature this is referred to as a "direct manipulation model".) Drag
|
||
|
and drop is similar in function to the clipboard's cut-and-paste
|
||
|
mechanism.
|
||
|
|
||
|
\tableofcontents
|
||
|
|
||
|
For drag and drop examples see (in increasing order of
|
||
|
sophistication): \c qt/examples/iconview/simple_dd, \c
|
||
|
qt/examples/dragdrop and \c qt/examples/fileiconview. See also the
|
||
|
QTextEdit widget source code.
|
||
|
|
||
|
|
||
|
\section1 Dragging
|
||
|
|
||
|
To start a drag, for example in a \link QWidget::mouseMoveEvent()
|
||
|
mouse motion event\endlink, create an object of the QDragObject
|
||
|
subclass appropriate for your media, such as QTextDrag for text and
|
||
|
QImageDrag for images. Then call the drag() method. This is all you
|
||
|
need for simple dragging of existing types.
|
||
|
|
||
|
For example, to start dragging some text from a widget:
|
||
|
\code
|
||
|
void MyWidget::startDrag()
|
||
|
{
|
||
|
QDragObject *d = new QTextDrag( myHighlightedText(), this );
|
||
|
d->dragCopy();
|
||
|
// do NOT delete d.
|
||
|
}
|
||
|
\endcode
|
||
|
|
||
|
Note that the QDragObject is not deleted after the drag. The
|
||
|
QDragObject needs to persist after the drag is apparently finished
|
||
|
since it may still be communicating with another process. Eventually
|
||
|
Qt will delete the object. If the widget owning the drag object is
|
||
|
deleted before then, any pending drop will be canceled and the drag
|
||
|
object deleted. For this reason, you should be careful what the object
|
||
|
references.
|
||
|
|
||
|
\section1 Dropping
|
||
|
|
||
|
To be able to receive media dropped on a widget, call
|
||
|
\link QWidget::setAcceptDrops() setAcceptDrops(TRUE)\endlink
|
||
|
for the widget (e.g. in its constructor), and override the
|
||
|
event handler methods
|
||
|
\link QWidget::dragEnterEvent() dragEnterEvent()\endlink and
|
||
|
\link QWidget::dropEvent() dropEvent()\endlink.
|
||
|
For more sophisticated applications overriding
|
||
|
\link QWidget::dragMoveEvent() dragMoveEvent()\endlink and
|
||
|
\link QWidget::dragLeaveEvent() dragLeaveEvent()\endlink will also be
|
||
|
necessary.
|
||
|
|
||
|
For example, to accept text and image drops:
|
||
|
\code
|
||
|
MyWidget::MyWidget(...) :
|
||
|
QWidget(...)
|
||
|
{
|
||
|
...
|
||
|
setAcceptDrops(TRUE);
|
||
|
}
|
||
|
|
||
|
void MyWidget::dragEnterEvent(QDragEnterEvent* event)
|
||
|
{
|
||
|
event->accept(
|
||
|
QTextDrag::canDecode(event) ||
|
||
|
QImageDrag::canDecode(event)
|
||
|
);
|
||
|
}
|
||
|
|
||
|
void MyWidget::dropEvent(QDropEvent* event)
|
||
|
{
|
||
|
QImage image;
|
||
|
QString text;
|
||
|
|
||
|
if ( QImageDrag::decode(event, image) ) {
|
||
|
insertImageAt(image, event->pos());
|
||
|
} else if ( QTextDrag::decode(event, text) ) {
|
||
|
insertTextAt(text, event->pos());
|
||
|
}
|
||
|
}
|
||
|
\endcode
|
||
|
|
||
|
\section1 The Clipboard
|
||
|
|
||
|
The QDragObject, QDragEnterEvent, QDragMoveEvent, and QDropEvent
|
||
|
classes are all subclasses of QMimeSource: the class of objects which
|
||
|
provide typed information. If you base your data transfers on
|
||
|
QDragObject, you not only get drag-and-drop, but you also get
|
||
|
traditional cut-and-paste for free. The QClipboard has two functions:
|
||
|
\code
|
||
|
setData(QMimeSource*)
|
||
|
QMimeSource* data()const
|
||
|
\endcode
|
||
|
With these functions you can trivially put your drag-and-drop oriented
|
||
|
information on the clipboard:
|
||
|
\code
|
||
|
void MyWidget::copy()
|
||
|
{
|
||
|
QApplication::clipboard()->setData(
|
||
|
new QTextDrag(myHighlightedText()) );
|
||
|
}
|
||
|
|
||
|
void MyWidget::paste()
|
||
|
{
|
||
|
QString text;
|
||
|
if ( QTextDrag::decode(QApplication::clipboard()->data(), text) )
|
||
|
insertText( text );
|
||
|
}
|
||
|
\endcode
|
||
|
You can even use QDragObject subclasses as part of file IO. For
|
||
|
example, if your application has a subclass of QDragObject that
|
||
|
encodes CAD designs in DXF format, your saving and loading code might
|
||
|
be:
|
||
|
\code
|
||
|
void MyWidget::save()
|
||
|
{
|
||
|
QFile out(current_file_name);
|
||
|
if ( out.open(IO_WriteOnly) ) {
|
||
|
MyCadDrag tmp(current_design);
|
||
|
out.writeBlock( tmp->encodedData( "image/x-dxf" ) );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void MyWidget::load()
|
||
|
{
|
||
|
QFile in(current_file_name);
|
||
|
if ( in.open(IO_ReadOnly) ) {
|
||
|
if ( !MyCadDrag::decode(in.readAll(), current_design) ) {
|
||
|
QMessageBox::warning( this, "Format error",
|
||
|
tr("The file \"%1\" is not in any supported format")
|
||
|
.arg(current_file_name)
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
\endcode
|
||
|
Note how the QDragObject subclass is called "MyCadDrag", not
|
||
|
"MyDxfDrag": because in the future you might extend it to provide
|
||
|
DXF, DWG, SVF, WMF, or even QPicture data to other applications.
|
||
|
|
||
|
\section1 Drag and Drop Actions
|
||
|
|
||
|
In the simpler cases, the target of a drag-and-drop receives a copy of
|
||
|
the data being dragged and the source decides whether to delete the
|
||
|
original. This is the "Copy" action in QDropEvent. The target may also
|
||
|
choose to understand other actions, specifically the Move and Link
|
||
|
actions. If the target understands the Move action, \e{the
|
||
|
target} is responsible for both the copy and delete operations and
|
||
|
the source will not attempt to delete the data itself. If the target
|
||
|
understands the Link, it stores its own reference to the original
|
||
|
information, and again the source does not delete the original. The
|
||
|
most common use of drag-and-drop actions is when performing a Move
|
||
|
within the same widget: see the \link #advanced Advanced
|
||
|
Drag-and-Drop\endlink section below.
|
||
|
|
||
|
The other major use of drag actions is when using a reference type
|
||
|
such as text/uri-list, where the dragged data are actually references
|
||
|
to files or objects.
|
||
|
|
||
|
\section1 Adding New Drag and Drop Types
|
||
|
|
||
|
As suggested in the DXF example above, drag-and-drop is not limited to
|
||
|
text and images. Any information can be dragged and dropped. To drag
|
||
|
information between applications, the applications must be able to
|
||
|
indicate to each other which data formats they can accept and which
|
||
|
they can produce. This is achieved using \link
|
||
|
http://www.rfc-editor.org/rfc/rfc1341.txt MIME types\endlink: the drag
|
||
|
source provides a list of MIME types that it can produce (ordered from
|
||
|
most appropriate to least appropriate), and the drop target chooses
|
||
|
which of those it can accept. For example, QTextDrag provides support
|
||
|
for the "\c{text/plain}" MIME type (ordinary unformatted text), and
|
||
|
the Unicode formats "\c{text/utf16}" and "\c{text/utf8}"; QImageDrag
|
||
|
provides for "\c{image/*}", where \c{*} is any image format that
|
||
|
\l QImageIO supports; and the QUriDrag subclass provides
|
||
|
"\c{text/uri-list}", a standard format for transferring a list of
|
||
|
filenames (or URLs).
|
||
|
|
||
|
To implement drag-and-drop of some type of information for which there
|
||
|
is no available QDragObject subclass, the first and most important
|
||
|
step is to look for existing formats that are appropriate: the
|
||
|
Internet Assigned Numbers Authority (\link http://www.iana.org
|
||
|
IANA\endlink) provides a \link
|
||
|
http://www.isi.edu/in-notes/iana/assignments/media-types/ hierarchical
|
||
|
list of MIME media types\endlink at the Information Sciences Institute
|
||
|
(\link http://www.isi.edu ISI\endlink). Using standard MIME types
|
||
|
maximizes the inter-operability of your application with other
|
||
|
software now and in the future.
|
||
|
|
||
|
To support an additional media type, subclass either QDragObject or
|
||
|
QStoredDrag. Subclass QDragObject when you need to provide support for
|
||
|
multiple media types. Subclass the simpler QStoredDrag when one type
|
||
|
is sufficient.
|
||
|
|
||
|
Subclasses of QDragObject will override the
|
||
|
\link QDragObject::format()
|
||
|
const char* format(int i) const
|
||
|
\endlink and
|
||
|
\link QDragObject::encodedData()
|
||
|
QByteArray encodedData(const char* mimetype) const
|
||
|
\endlink
|
||
|
members, and provide a set-method to encode the media data and static
|
||
|
members canDecode() and decode() to decode incoming data, similar to
|
||
|
\link QImageDrag::canDecode()
|
||
|
bool canDecode(QMimeSource*) const
|
||
|
\endlink and
|
||
|
\link QImageDrag::decode()
|
||
|
QByteArray decode(QMimeSource*) const
|
||
|
\endlink
|
||
|
of QImageDrag.
|
||
|
Of course, you can provide drag-only or drop-only support for a media
|
||
|
type by omitting some of these methods.
|
||
|
|
||
|
Subclasses of QStoredDrag provide a set-method to encode the media
|
||
|
data and the same static members canDecode() and decode() to decode
|
||
|
incoming data.
|
||
|
|
||
|
\target advanced
|
||
|
\section1 Advanced Drag-and-Drop
|
||
|
|
||
|
In the clipboard model, the user can \e cut or \e copy the source
|
||
|
information, then later paste it. Similarly in the drag-and-drop
|
||
|
model, the user can drag a \e copy of the information or they can drag
|
||
|
the information itself to a new place (\e moving it). The
|
||
|
drag-and-drop model however has an additional complication for the
|
||
|
programmer: the program doesn't know whether the user wants to cut or
|
||
|
copy until the drop (paste) is done! For dragging between
|
||
|
applications, it makes no difference, but for dragging within an
|
||
|
application, the application must take a little extra care not to
|
||
|
tread on its own feet. For example, to drag text around in a document,
|
||
|
the drag start point and the drop event might look like this:
|
||
|
|
||
|
\code
|
||
|
void MyEditor::startDrag()
|
||
|
{
|
||
|
QDragObject *d = new QTextDrag(myHighlightedText(), this);
|
||
|
if ( d->drag() && d->target() != this )
|
||
|
cutMyHighlightedText();
|
||
|
}
|
||
|
|
||
|
void MyEditor::dropEvent(QDropEvent* event)
|
||
|
{
|
||
|
QString text;
|
||
|
|
||
|
if ( QTextDrag::decode(event, text) ) {
|
||
|
if ( event->source() == this && event->action() == QDropEvent::Move ) {
|
||
|
// Careful not to tread on my own feet
|
||
|
event->acceptAction();
|
||
|
moveMyHighlightedTextTo(event->pos());
|
||
|
} else {
|
||
|
pasteTextAt(text, event->pos());
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
\endcode
|
||
|
|
||
|
Some widgets are more specific than just a "yes" or "no" response when
|
||
|
data is dragged onto them. For example, a CAD program might only
|
||
|
accept drops of text onto text objects in the view. In these cases,
|
||
|
the \link QWidget::dragMoveEvent() dragMoveEvent()\endlink is used and
|
||
|
an \e area is given for which the drag is accepted or ignored:
|
||
|
\code
|
||
|
void MyWidget::dragMoveEvent(QDragMoveEvent* event)
|
||
|
{
|
||
|
if ( QTextDrag::canDecode(event) ) {
|
||
|
MyCadItem* item = findMyItemAt(event->pos());
|
||
|
if ( item )
|
||
|
event->accept();
|
||
|
}
|
||
|
}
|
||
|
\endcode
|
||
|
If the computations to find objects are particularly slow, you might
|
||
|
achieve improved performance if you tell the system an area for which
|
||
|
you promise the acceptance persists:
|
||
|
\code
|
||
|
void MyWidget::dragMoveEvent(QDragMoveEvent* event)
|
||
|
{
|
||
|
if ( QTextDrag::canDecode(event) ) {
|
||
|
MyCadItem* item = findMyItemAt(event->pos());
|
||
|
if ( item ) {
|
||
|
QRect r = item->areaRelativeToMeClippedByAnythingInTheWay();
|
||
|
if ( item->type() == MyTextType )
|
||
|
event->accept( r );
|
||
|
else
|
||
|
event->ignore( r );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
\endcode
|
||
|
|
||
|
The dragMoveEvent() can also be used if you need to give visual
|
||
|
feedback as the drag progresses, to start timers, to scroll the
|
||
|
window, or whatever is appropriate (don't forget to stop the scrolling
|
||
|
and timers in a dragLeaveEvent() though).
|
||
|
|
||
|
The QApplication object (available as the \c qApp global) also
|
||
|
provides some drag and drop related functions:
|
||
|
\l{QApplication::setStartDragTime()},
|
||
|
\l{QApplication::setStartDragDistance()}, and their corresponding
|
||
|
getters, \l{QApplication::startDragTime()} and
|
||
|
\l{QApplication::startDragDistance()}.
|
||
|
|
||
|
\section1 Inter-operating with Other Applications
|
||
|
|
||
|
On X11, the public <a class="r"
|
||
|
href="http://www.newplanetsoftware.com/xdnd/">XDND protocol</a> is
|
||
|
used, while on Windows Qt uses the OLE standard, and Qt/Mac uses the
|
||
|
Carbon Drag Manager. On X11, XDND uses MIME, so no translation is
|
||
|
necessary. The Qt API is the same regardless of the platform. On
|
||
|
Windows, MIME-aware applications can communicate by using clipboard
|
||
|
format names that are MIME types. Already some Windows applications
|
||
|
use MIME naming conventions for their clipboard formats. Internally,
|
||
|
Qt has facilities for translating proprietary clipboard formats to and
|
||
|
from MIME types. This interface will be made public at some time, but
|
||
|
if you need to do such translations now, contact your Qt Technical
|
||
|
Support service.
|
||
|
|
||
|
On X11, Qt also supports drops via the Motif Drag\&Drop Protocol. The
|
||
|
implementation incorporates some code that was originally written by
|
||
|
Daniel Dardailler, and adapted for Qt by Matt Koss \<koss@napri.sk\>
|
||
|
and Trolltech. Here is the original copyright notice:
|
||
|
|
||
|
\legalese
|
||
|
|
||
|
Copyright 1996 Daniel Dardailler.
|
||
|
|
||
|
Permission to use, copy, modify, distribute, and sell this software
|
||
|
for any purpose is hereby granted without fee, provided that the above
|
||
|
copyright notice appear in all copies and that both that copyright
|
||
|
notice and this permission notice appear in supporting documentation,
|
||
|
and that the name of Daniel Dardailler not be used in advertising or
|
||
|
publicity pertaining to distribution of the software without specific,
|
||
|
written prior permission. Daniel Dardailler makes no representations
|
||
|
about the suitability of this software for any purpose. It is
|
||
|
provided "as is" without express or implied warranty.
|
||
|
|
||
|
Modifications Copyright 1999 Matt Koss, under the same license as
|
||
|
above.
|
||
|
|
||
|
*/ // NOTE: That notice is from qmotifdnd_x11.cpp.
|