Hi all,
I have two table model views. When I drag an item to the other view how can I tell the source view that the drop has been accepted? The idea is to grey out the item which was copied to the other view.
Any hints?
Thanks a lot.
Printable View
Hi all,
I have two table model views. When I drag an item to the other view how can I tell the source view that the drop has been accepted? The idea is to grey out the item which was copied to the other view.
Any hints?
Thanks a lot.
Return true from QAbstractItemModel::dropMimeData(). Unfortunately you can't access that information from within the source. But if you force a MoveAction, the item will get deleted by the source view. If you want a different behaviour, subclass the view and reimplement startDrag().
As you said the only one who knows that mimedata was sucessfully droped is QAbstractItemModel::dropMimeData() so, I implemented a signal in the target model and a slot in the source model to inform the source that data has been transfered. Is that a resonable way to do that?
Thanks.
Not really, but if it works then why not...Quote:
Originally Posted by larry104
If you say
how should I do it? I tried the subclassing approach but non of the theseQuote:
Not really, but if it works then why not...
Code:
void startDrag(Qt::DropActions supportedActions);
tell me that the target has really accepted the drop. Do I miss something?
Thanks.
QDrag::start() tells you that and it is called from QAbstractItemView::startDrag(), that's why I said you could reimplement it.
I see your point but, still if the user drops the data other than the target model view I wouln't know that. Subclassing startDrag would just allow me to act on the actual move out of my source view - right? There is no real feedback mechanism between source and target.
startDrag will notify you in the source view (by the return value from startDrag()). From then you have direct access to the source model (you can connect them through signal and slot then, emiting the signal from the view in this situation is better than from the model), I thought that was what you wanted -- to change the source model after the drop.Quote:
Originally Posted by larry104
So, I subclassed startDrag and indeed QDrag::start() tells me that something was moved/copied but as I thought it will tell me when I droped into the target as well as any other application e.g firefox. So, I don't see a difference that the data has been accepted by the target.
I have to admit I didn't understand your post :)
QDrag::start returns an information if the drag was accepted and with which action. If it was dropped on an invalid target, it will return IgnoreAction, if it was dropped on a valid target but the drop was rejected, it will return IgnoreAction. If it was dropped on a valid target and the target did something with the data (no matter if the target is in the same application as the source or if it's a completely different program), it will return an action telling you what should you do with the data -- copy, move, link or ignore it. If you drop on Firefox and firefox accepts the drop, you'll receive CopyAction. So you'll always know what you should do with the item.
Does that solve your problem? If you have doubts, please look at the puzzle example bundled with Qt and at the definition of the puzzle widget (or whatever it's called). The widget does the thing I think you want to do, just it doesn't use model-view, but the idea remains. If a drag is started, the item gets removed from the widget, if a valid drop occurs, the item gets inserted in a new position. If an invalid drop occurs, the item gets inserted back into the place it was taken from. No matter where you actually drop the item (and by using a custom MIME type it assures that you won't make a valid drop outside the puzzle application).
Yep, that does the trick to ensure that only the target is allowed to accept the drop. Unfortunately, rewriting startDrag is a little bit of work. Thanks again for the help.Code:
... using a custom MIME type it assures ...
Copy and paste it from Qt sources and add the lines you need.Quote:
Originally Posted by larry104
Hmmm, that might be embarrissing for me (after all I'm QT beginner) but I get compile errors when I just copy it.
Code:
{ QModelIndexList indexes = selectedIndexes(); if (indexes.count() > 0) { // setup pixmap QList<QRect> rects; for (int i = 0; i < indexes.count(); ++i) { rects.append(visualRect(indexes.at(i))); rect |= rects.at(i); } rect = rect.intersect(d->viewport->rect()); pixmap.fill(palette().base().color()); for (int j = 0; j < indexes.count(); ++j) { rects.at(j).size()); itemDelegate()->paint(&painter, option, indexes.at(j)); } painter.end(); // create drag object drag->setPixmap(pixmap); drag->setMimeData(model()->mimeData(indexes)); if (drag->start(supportedActions) == Qt::MoveAction) d->removeSelectedRows(); } }
Code:
../../../qt/qt-4.1.4/include/QtGui/qtableview.h: In member function `virtual void MyTableView::startDrag(QFlags<Qt::DropAction>)': ../../../qt/qt-4.1.4/include/QtGui/qtableview.h:134: `QTableViewPrivate* QTableView::d_func()' is private mytableview.cpp:43: within this context mytableview.cpp:43: cannot convert `QTableViewPrivate*' to ` QAbstractItemViewPrivate* const' in initialization mytableview.cpp:53: invalid use of undefined type `struct QAbstractItemViewPrivate' ../../../qt/qt-4.1.4/include/QtGui/qabstractitemview.h:41: forward declaration of `struct QAbstractItemViewPrivate' mytableview.cpp:69: invalid use of undefined type `struct QAbstractItemViewPrivate' ../../../qt/qt-4.1.4/include/QtGui/qabstractitemview.h:41: forward declaration of `struct QAbstractItemViewPrivate' mytableview.cpp:71: invalid use of undefined type `struct QAbstractItemViewPrivate' ../../../qt/qt-4.1.4/include/QtGui/qabstractitemview.h:41: forward declaration of `struct QAbstractItemViewPrivate' make: *** [mytableview.o] Error 1
You can't use private components of Qt classes as they are not accessible, so you have to think a workaround for using Q_D and d->. It shouldn't be too hard as d->viewport should be available as viewport() and you can remove the selected rows without using the d->removeSelectedRows() call if you need that functionality. And when you won't be using "d" anymore, you can remove the Q_D() call.
Works perfect now - thanks again so much for all the help.
what could be the cause if the item was dropped on a valid target, but QDrag::exec (or start) still returns IgnoreAction?
i'm creating a QDrag object in a custom item view in the startDrag(...) function like this:
Code:
p_pDrag->setMimeData(p_pMimeData); p_pDrag->setPixmap(p_Pixmap); // always returns IGNORE?! Qt::DropAction p_DropAction = p_pDrag->exec(Qt::MoveAction | Qt::CopyAction);
the underlying model's (subclassed QStandardItemModel) flag function gives Qt::ItemIsDropEnabled for every index, supportedDropActions gives Qt::MoveAction | Qt::CopyAction.
i overloaded dropEvent(...) for the view and QDropEvent::dropAction() is CopyAction
i also set setDragEnabled and setAcceptDrops to true and setDragDropMode to DragDrop
but still no luck :(
d&d works fine btw, just the return value of exec is wrong...
yes, it definetly returns true :(
Can you show me the dropMimeData() implementation and the contents of supportedDragActions and supportedDropActions?
oh boy, thats it. i didn't set the supported drag actions :o