Bug 466337

Summary: Plasma crashed in Positioner::sourceRowsAboutToBeRemoved() when moving files from Desktop to Pictures folder in Dolphin
Product: [Plasma] plasmashell Reporter: Jaak Ristioja <jaak>
Component: FolderAssignee: Plasma Bugs List <plasma-bugs>
Status: RESOLVED FIXED    
Severity: crash CC: hein, kde, nate, rion4ik
Priority: NOR Keywords: drkonqi
Version: 5.26.5   
Target Milestone: 1.0   
Platform: Compiled Sources   
OS: Linux   
Latest Commit: Version Fixed In: 6.1.1
Sentry Crash Report:

Description Jaak Ristioja 2023-02-24 08:37:17 UTC
Application: plasmashell (5.26.5)
 (Compiled from sources)
Qt Version: 5.15.8
Frameworks Version: 5.103.0
Operating System: Linux 6.2.0-gentoo x86_64
Windowing System: Wayland
Distribution: "Gentoo Linux"
DrKonqi: 5.27.1 [KCrashBackend]

-- Information about the crash:
Using two click-drag selections, I selected a number of picture files on the desktop and click-drag-moved them to the Pictures folder open in a Dolphin window, and selected the move option from the popup menu. After this plasma crashed.

As a somewhat unrelated issue but perhaps still noteworthy is that one of the pictures I moved was also used as the desktop wallpaper. This also caused the wallpaper to reset after restarting plasmashell.

The reporter is unsure if this crash is reproducible.

-- Backtrace:
Application: Plasma (plasmashell), signal: Aborted
Content of s_kcrashErrorMessage: std::unique_ptr<char []> = {get() = 0x0}
[KCrash Handler]
#6  __pthread_kill_implementation (threadid=<optimized out>, signo=signo@entry=6, no_tid=no_tid@entry=0) at pthread_kill.c:44
#7  0x00007f03f78b1783 in __pthread_kill_internal (signo=6, threadid=<optimized out>) at pthread_kill.c:78
#8  0x00007f03f7864516 in __GI_raise (sig=sig@entry=6) at ../sysdeps/posix/raise.c:26
#9  0x00007f03f784e7fb in __GI_abort () at abort.c:79
#10 0x00007f03f7e929cf in qt_message_fatal (message=<synthetic pointer>..., context=...) at /var/tmp/portage/dev-qt/qtcore-5.15.8-r3/work/qtbase-everywhere-src-5.15.8/src/corelib/global/qlogging.cpp:1914
#11 QMessageLogger::fatal(char const*, ...) const (this=this@entry=0x7ffd19b65468, msg=msg@entry=0x7f03f818b968 "ASSERT: \"%s\" in file %s, line %d") at /var/tmp/portage/dev-qt/qtcore-5.15.8-r3/work/qtbase-everywhere-src-5.15.8/src/corelib/global/qlogging.cpp:893
#12 0x00007f03f7e917d2 in qt_assert(char const*, char const*, int) (assertion=assertion@entry=0x7f03f8270fea "last < rowCount(parent)", file=file@entry=0x7f03f8270a28 "/var/tmp/portage/dev-qt/qtcore-5.15.8-r3/work/qtbase-everywhere-src-5.15.8/src/corelib/itemmodels/qabstractitemmodel.cpp", line=line@entry=2815) at /var/tmp/portage/dev-qt/qtcore-5.15.8-r3/work/qtbase-everywhere-src-5.15.8/src/corelib/global/qglobal.cpp:3391
#13 0x00007f03f7ead64e in QAbstractItemModel::beginRemoveRows(QModelIndex const&, int, int) (this=0x55b2f00f4500, parent=<optimized out>, first=120, last=120) at /var/tmp/portage/dev-qt/qtcore-5.15.8-r3/work/qtbase-everywhere-src-5.15.8/src/corelib/itemmodels/qabstractitemmodel.cpp:2815
#14 0x00007f03bd7d7f8b in Positioner::sourceRowsAboutToBeRemoved(QModelIndex const&, int, int) (parent=<optimized out>, last=14, first=<optimized out>, this=0x55b2f00f4500) at /var/tmp/portage/kde-plasma/plasma-desktop-5.26.5-r2/work/plasma-desktop-5.26.5/containments/desktop/plugins/folder/positioner.cpp:626
#15 Positioner::sourceRowsAboutToBeRemoved(QModelIndex const&, int, int) (this=0x55b2f00f4500, parent=<optimized out>, first=<optimized out>, last=14) at /var/tmp/portage/kde-plasma/plasma-desktop-5.26.5-r2/work/plasma-desktop-5.26.5/containments/desktop/plugins/folder/positioner.cpp:591
#16 0x00007f03f80e73ae in QtPrivate::QSlotObjectBase::call(QObject*, void**) (a=0x7ffd19b656c0, r=0x55b2f00f4500, this=0x55b2f00c0750) at /var/tmp/portage/dev-qt/qtcore-5.15.8-r3/work/qtbase-everywhere-src-5.15.8/include/QtCore/../../src/corelib/kernel/qobjectdefs_impl.h:398
#17 doActivate<false>(QObject*, int, void**) (sender=0x55b2f025a360, signal_index=14, argv=0x7ffd19b656c0) at /var/tmp/portage/dev-qt/qtcore-5.15.8-r3/work/qtbase-everywhere-src-5.15.8/src/corelib/kernel/qobject.cpp:3923
#18 0x00007f03f80e0717 in QMetaObject::activate(QObject*, QMetaObject const*, int, void**) (sender=sender@entry=0x55b2f025a360, m=m@entry=0x7f03f83bfcc0 <QAbstractItemModel::staticMetaObject>, local_signal_index=local_signal_index@entry=11, argv=argv@entry=0x7ffd19b656c0) at /var/tmp/portage/dev-qt/qtcore-5.15.8-r3/work/qtbase-everywhere-src-5.15.8/src/corelib/kernel/qobject.cpp:3983
#19 0x00007f03f805c8a2 in QAbstractItemModel::rowsAboutToBeRemoved(QModelIndex const&, int, int, QAbstractItemModel::QPrivateSignal) (this=this@entry=0x55b2f025a360, _t1=..., _t2=<optimized out>, _t2@entry=5, _t3=<optimized out>, _t3@entry=14, _t4=...) at .moc/moc_qabstractitemmodel.cpp:600
#20 0x00007f03f8064c32 in QAbstractItemModel::beginRemoveRows(QModelIndex const&, int, int) (this=0x55b2f025a360, parent=..., first=5, last=14) at /var/tmp/portage/dev-qt/qtcore-5.15.8-r3/work/qtbase-everywhere-src-5.15.8/src/corelib/itemmodels/qabstractitemmodel.cpp:2818
#21 0x00007f03f8086ded in QSortFilterProxyModelPrivate::remove_proxy_interval(QVector<int>&, QVector<int>&, int, int, QModelIndex const&, Qt::Orientation, bool) (this=0x55b2f0051ec0, source_to_proxy=..., proxy_to_source=..., proxy_start=<optimized out>, proxy_end=14, proxy_parent=<optimized out>, orient=Qt::Vertical, emit_signal=true) at /var/tmp/portage/dev-qt/qtcore-5.15.8-r3/work/qtbase-everywhere-src-5.15.8/src/corelib/itemmodels/qsortfilterproxymodel.cpp:811
#22 0x00007f03f808a9b7 in QSortFilterProxyModelPrivate::remove_source_items(QVector<int>&, QVector<int>&, QVector<int> const&, QModelIndex const&, Qt::Orientation, bool) (this=0x55b2f0051ec0, source_to_proxy=..., proxy_to_source=..., source_items=<optimized out>, source_parent=<optimized out>, orient=Qt::Vertical, emit_signal=true) at /var/tmp/portage/dev-qt/qtcore-5.15.8-r3/work/qtbase-everywhere-src-5.15.8/src/corelib/itemmodels/qsortfilterproxymodel.cpp:792
#23 0x00007f03f808acf8 in QSortFilterProxyModelPrivate::source_items_about_to_be_removed(QModelIndex const&, int, int, Qt::Orientation) (this=0x55b2f0051ec0, source_parent=..., start=5, end=14, orient=Qt::Vertical) at /var/tmp/portage/dev-qt/qtcore-5.15.8-r3/work/qtbase-everywhere-src-5.15.8/src/corelib/itemmodels/qsortfilterproxymodel.cpp:1094
#24 0x00007f03f80e73f4 in doActivate<false>(QObject*, int, void**) (sender=0x55b2f00906b0, signal_index=14, argv=0x7ffd19b659d0) at /var/tmp/portage/dev-qt/qtcore-5.15.8-r3/work/qtbase-everywhere-src-5.15.8/src/corelib/kernel/qobject.cpp:3935
#25 0x00007f03f80e0717 in QMetaObject::activate(QObject*, QMetaObject const*, int, void**) (sender=sender@entry=0x55b2f00906b0, m=m@entry=0x7f03f83bfcc0 <QAbstractItemModel::staticMetaObject>, local_signal_index=local_signal_index@entry=11, argv=argv@entry=0x7ffd19b659d0) at /var/tmp/portage/dev-qt/qtcore-5.15.8-r3/work/qtbase-everywhere-src-5.15.8/src/corelib/kernel/qobject.cpp:3983
#26 0x00007f03f805c8a2 in QAbstractItemModel::rowsAboutToBeRemoved(QModelIndex const&, int, int, QAbstractItemModel::QPrivateSignal) (this=this@entry=0x55b2f00906b0, _t1=..., _t2=<optimized out>, _t2@entry=5, _t3=<optimized out>, _t3@entry=14, _t4=...) at .moc/moc_qabstractitemmodel.cpp:600
#27 0x00007f03f8064c32 in QAbstractItemModel::beginRemoveRows(QModelIndex const&, int, int) (this=0x55b2f00906b0, parent=..., first=5, last=14) at /var/tmp/portage/dev-qt/qtcore-5.15.8-r3/work/qtbase-everywhere-src-5.15.8/src/corelib/itemmodels/qabstractitemmodel.cpp:2818
#28 0x00007f03f724d568 in KDirModelPrivate::_k_slotDeleteItems(KFileItemList const&) (this=0x55b2f01cdab0, items=<optimized out>) at /var/tmp/portage/kde-frameworks/kio-5.103.0/work/kio-5.103.0/src/widgets/kdirmodel.cpp:653
#29 0x00007f03f80e73ae in QtPrivate::QSlotObjectBase::call(QObject*, void**) (a=0x7ffd19b65c30, r=0x55b2f00906b0, this=0x55b2f01265a0) at /var/tmp/portage/dev-qt/qtcore-5.15.8-r3/work/qtbase-everywhere-src-5.15.8/include/QtCore/../../src/corelib/kernel/qobjectdefs_impl.h:398
#30 doActivate<false>(QObject*, int, void**) (sender=0x55b2f008db70, signal_index=18, argv=0x7ffd19b65c30) at /var/tmp/portage/dev-qt/qtcore-5.15.8-r3/work/qtbase-everywhere-src-5.15.8/src/corelib/kernel/qobject.cpp:3923
#31 0x00007f03f80e0717 in QMetaObject::activate(QObject*, QMetaObject const*, int, void**) (sender=<optimized out>, m=m@entry=0x7f03f76d1880 <KCoreDirLister::staticMetaObject>, local_signal_index=local_signal_index@entry=15, argv=argv@entry=0x7ffd19b65c30) at /var/tmp/portage/dev-qt/qtcore-5.15.8-r3/work/qtbase-everywhere-src-5.15.8/src/corelib/kernel/qobject.cpp:3983
#32 0x00007f03f7638c69 in KCoreDirLister::itemsDeleted(KFileItemList const&) (this=<optimized out>, _t1=...) at /var/tmp/portage/kde-frameworks/kio-5.103.0/work/kio-5.103.0_build/src/core/KF5KIOCore_autogen/include/moc_kcoredirlister.cpp:583
#33 0x00007f03f763d398 in KCoreDirListerPrivate::emitItemsDeleted(KFileItemList const&) (this=0x55b2f00f2f60, itemsList=...) at /var/tmp/portage/kde-frameworks/kio-5.103.0/work/kio-5.103.0/src/core/kcoredirlister.cpp:2611
#34 0x00007f03f764c873 in KCoreDirListerCache::itemsDeleted(QList<KCoreDirLister*> const&, KFileItemList const&) (this=this@entry=0x7f03f76d55c0 <(anonymous namespace)::Q_QGS_kDirListerCache::innerFunction()::holder>, listers=..., deletedItems=...) at /var/tmp/portage/kde-frameworks/kio-5.103.0/work/kio-5.103.0/src/core/kcoredirlister.cpp:1924
#35 0x00007f03f764cf9e in KCoreDirListerCache::deleteUnmarkedItems(QList<KCoreDirLister*> const&, QList<KFileItem>&, QHash<QString, KFileItem> const&) (this=this@entry=0x7f03f76d55c0 <(anonymous namespace)::Q_QGS_kDirListerCache::innerFunction()::holder>, listers=..., lstItems=..., itemsToDelete=...) at /var/tmp/portage/kde-frameworks/kio-5.103.0/work/kio-5.103.0/src/core/kcoredirlister.cpp:1918
#36 0x00007f03f76532e8 in KCoreDirListerCache::slotUpdateResult(KJob*) (this=0x7f03f76d55c0 <(anonymous namespace)::Q_QGS_kDirListerCache::innerFunction()::holder>, j=<optimized out>) at /var/tmp/portage/kde-frameworks/kio-5.103.0/work/kio-5.103.0/src/core/kcoredirlister.cpp:1842
#37 0x00007f03f80e73ae in QtPrivate::QSlotObjectBase::call(QObject*, void**) (a=0x7ffd19b65fe0, r=0x7f03f76d55c0 <(anonymous namespace)::Q_QGS_kDirListerCache::innerFunction()::holder>, this=0x55b2efda2ef0) at /var/tmp/portage/dev-qt/qtcore-5.15.8-r3/work/qtbase-everywhere-src-5.15.8/include/QtCore/../../src/corelib/kernel/qobjectdefs_impl.h:398
#38 doActivate<false>(QObject*, int, void**) (sender=0x55b2f1e1d190, signal_index=6, argv=0x7ffd19b65fe0) at /var/tmp/portage/dev-qt/qtcore-5.15.8-r3/work/qtbase-everywhere-src-5.15.8/src/corelib/kernel/qobject.cpp:3923
#39 0x00007f03f80e0717 in QMetaObject::activate(QObject*, QMetaObject const*, int, void**) (sender=sender@entry=0x55b2f1e1d190, m=m@entry=0x7f03f93a8160 <KJob::staticMetaObject>, local_signal_index=local_signal_index@entry=3, argv=argv@entry=0x7ffd19b65fe0) at /var/tmp/portage/dev-qt/qtcore-5.15.8-r3/work/qtbase-everywhere-src-5.15.8/src/corelib/kernel/qobject.cpp:3983
#40 0x00007f03f9349987 in KJob::result(KJob*, KJob::QPrivateSignal) (this=this@entry=0x55b2f1e1d190, _t1=<optimized out>, _t1@entry=0x55b2f1e1d190, _t2=...) at /var/tmp/portage/kde-frameworks/kcoreaddons-5.103.0/work/kcoreaddons-5.103.0_build/src/lib/KF5CoreAddons_autogen/include/moc_kjob.cpp:635
#41 0x00007f03f934afab in KJob::finishJob(bool) (this=0x55b2f1e1d190, emitResult=<optimized out>) at /var/tmp/portage/kde-frameworks/kcoreaddons-5.103.0/work/kcoreaddons-5.103.0/src/lib/jobs/kjob.cpp:98
#42 0x00007f03f80e73ae in QtPrivate::QSlotObjectBase::call(QObject*, void**) (a=0x7ffd19b660b0, r=0x55b2f1e1d190, this=0x55b2f1fb3cc0) at /var/tmp/portage/dev-qt/qtcore-5.15.8-r3/work/qtbase-everywhere-src-5.15.8/include/QtCore/../../src/corelib/kernel/qobjectdefs_impl.h:398
#43 doActivate<false>(QObject*, int, void**) (sender=0x55b2f01f61a0, signal_index=7, argv=0x7ffd19b660b0) at /var/tmp/portage/dev-qt/qtcore-5.15.8-r3/work/qtbase-everywhere-src-5.15.8/src/corelib/kernel/qobject.cpp:3923
#44 0x00007f03f80e0717 in QMetaObject::activate(QObject*, QMetaObject const*, int, void**) (sender=sender@entry=0x55b2f01f61a0, m=m@entry=0x7f03f76cf820 <KIO::SlaveInterface::staticMetaObject>, local_signal_index=local_signal_index@entry=4, argv=argv@entry=0x0) at /var/tmp/portage/dev-qt/qtcore-5.15.8-r3/work/qtbase-everywhere-src-5.15.8/src/corelib/kernel/qobject.cpp:3983
#45 0x00007f03f75dd5e7 in KIO::SlaveInterface::finished() (this=this@entry=0x55b2f01f61a0) at /var/tmp/portage/kde-frameworks/kio-5.103.0/work/kio-5.103.0_build/src/core/KF5KIOCore_autogen/include/moc_slaveinterface.cpp:465
#46 0x00007f03f75df802 in KIO::SlaveInterface::dispatch(int, QByteArray const&) (this=0x55b2f01f61a0, _cmd=<optimized out>, rawdata=...) at /var/tmp/portage/kde-frameworks/kio-5.103.0/work/kio-5.103.0/src/core/slaveinterface.cpp:149
#47 0x00007f03f75dde4a in KIO::SlaveInterface::dispatch() (this=0x55b2f01f61a0) at /var/tmp/portage/kde-frameworks/kio-5.103.0/work/kio-5.103.0/src/core/slaveinterface.cpp:78
#48 0x00007f03f75e2ba1 in KIO::Slave::gotInput() (this=0x55b2f01f61a0) at /var/tmp/portage/kde-frameworks/kio-5.103.0/work/kio-5.103.0/src/core/slave.cpp:354
#49 0x00007f03f80e73ae in QtPrivate::QSlotObjectBase::call(QObject*, void**) (a=0x7ffd19b66310, r=0x55b2f01f61a0, this=0x55b2f022e940) at /var/tmp/portage/dev-qt/qtcore-5.15.8-r3/work/qtbase-everywhere-src-5.15.8/include/QtCore/../../src/corelib/kernel/qobjectdefs_impl.h:398
#50 doActivate<false>(QObject*, int, void**) (sender=0x55b2f03612b0, signal_index=3, argv=0x7ffd19b66310) at /var/tmp/portage/dev-qt/qtcore-5.15.8-r3/work/qtbase-everywhere-src-5.15.8/src/corelib/kernel/qobject.cpp:3923
#51 0x00007f03f80de50c in QObject::event(QEvent*) (this=0x55b2f03612b0, e=0x7f03a824cae0) at /var/tmp/portage/dev-qt/qtcore-5.15.8-r3/work/qtbase-everywhere-src-5.15.8/src/corelib/kernel/qobject.cpp:1347
#52 0x00007f03f8d6c6b3 in QApplicationPrivate::notify_helper(QObject*, QEvent*) (this=<optimized out>, receiver=0x55b2f03612b0, e=0x7f03a824cae0) at /var/tmp/portage/dev-qt/qtwidgets-5.15.8-r2/work/qtbase-everywhere-src-5.15.8/src/widgets/kernel/qapplication.cpp:3640
#53 0x00007f03f80af4a8 in QCoreApplication::notifyInternal2(QObject*, QEvent*) (receiver=0x55b2f03612b0, event=0x7f03a824cae0) at /var/tmp/portage/dev-qt/qtcore-5.15.8-r3/work/qtbase-everywhere-src-5.15.8/src/corelib/kernel/qcoreapplication.cpp:1064
#54 0x00007f03f80b2b2e in QCoreApplicationPrivate::sendPostedEvents(QObject*, int, QThreadData*) (receiver=0x0, event_type=0, data=0x55b2ef9923b0) at /var/tmp/portage/dev-qt/qtcore-5.15.8-r3/work/qtbase-everywhere-src-5.15.8/src/corelib/kernel/qcoreapplication.cpp:1821
#55 0x00007f03f8108737 in postEventSourceDispatch(GSource*, GSourceFunc, gpointer) (s=0x55b2ef9b3dd0) at /var/tmp/portage/dev-qt/qtcore-5.15.8-r3/work/qtbase-everywhere-src-5.15.8/src/corelib/kernel/qeventdispatcher_glib.cpp:277
#56 0x00007f03f651a458 in g_main_dispatch (context=0x55b2ef9b7ee0) at ../glib-2.74.5/glib/gmain.c:3454
#57 g_main_context_dispatch (context=0x55b2ef9b7ee0) at ../glib-2.74.5/glib/gmain.c:4172
#58 0x00007f03f651a6e8 in g_main_context_iterate (context=context@entry=0x55b2ef9b7ee0, block=block@entry=1, dispatch=dispatch@entry=1, self=<optimized out>) at ../glib-2.74.5/glib/gmain.c:4248
#59 0x00007f03f651a780 in g_main_context_iteration (context=0x55b2ef9b7ee0, may_block=1) at ../glib-2.74.5/glib/gmain.c:4313
#60 0x00007f03f8107d9a in QEventDispatcherGlib::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) (this=0x55b2ef9b87e0, flags=...) at /var/tmp/portage/dev-qt/qtcore-5.15.8-r3/work/qtbase-everywhere-src-5.15.8/src/corelib/kernel/qeventdispatcher_glib.cpp:423
#61 0x00007f03f80ad8fb in QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>) (this=this@entry=0x7ffd19b666f0, flags=..., flags@entry=...) at /var/tmp/portage/dev-qt/qtcore-5.15.8-r3/work/qtbase-everywhere-src-5.15.8/include/QtCore/../../src/corelib/global/qflags.h:69
#62 0x00007f03f80b6924 in QCoreApplication::exec() () at /var/tmp/portage/dev-qt/qtcore-5.15.8-r3/work/qtbase-everywhere-src-5.15.8/include/QtCore/../../src/corelib/global/qflags.h:121
#63 0x00007f03f8530c50 in QGuiApplication::exec() () at /var/tmp/portage/dev-qt/qtgui-5.15.8-r3/work/qtbase-everywhere-src-5.15.8/src/gui/kernel/qguiapplication.cpp:1870
#64 0x00007f03f8d6c629 in QApplication::exec() () at /var/tmp/portage/dev-qt/qtwidgets-5.15.8-r2/work/qtbase-everywhere-src-5.15.8/src/widgets/kernel/qapplication.cpp:2832
#65 0x000055b2ef0af29b in main(int, char**) (argc=<optimized out>, argv=<optimized out>) at /var/tmp/portage/kde-plasma/plasma-workspace-5.26.5-r1/work/plasma-workspace-5.26.5/shell/main.cpp:233
[Inferior 1 (process 3525) detached]

Reported using DrKonqi
Comment 1 Bug Janitor Service 2024-02-26 16:19:22 UTC
A possibly relevant merge request was started @ https://invent.kde.org/plasma/plasma-desktop/-/merge_requests/2069
Comment 2 Nate Graham 2024-02-26 22:15:37 UTC
*** Bug 481850 has been marked as a duplicate of this bug. ***
Comment 3 Marco Martin 2024-02-28 08:49:41 UTC
Git commit f0ede2d83731952012be0d43c77916d18617edb2 by Marco Martin.
Committed on 28/02/2024 at 08:49.
Pushed by mart into branch 'master'.

FolderView Positioner: fix rows insert and remove

The positioner "proxy" model had problems both in rows insertion and
removal.

when an icon is dropped in an empty desktop area as the new "last"
position, the positioner model creates new empty items for the GridView
until it reaches the cell of the drop position.

This broke because of connection slot invocation order: the connection
to QAbstractItemModel::rowsInserted in FolderModel constructor was
executed before the connection in positioner.
In turn that connection emitted move, which invoked move on Positioner,
which at this point thinks its still in the first rows insertion
transaction, because its slot has not been executed yet,
and m_beginInsertRowsCalled is still true, so there won't be a "correct"
new beginInsertRows called.
Make it a Queued connection to push it back.

In the same way, when dragging from a "last" position, the Positioner model
will remove all the trailing empty items. But it modified m_proxyToSource
(from which rowCount() depends) before calling beginRemoveRows, sending
the model into an inconsitent state and causing an assert. Make sure
that m_proxyToSource is touched only after beginRemoveRows.
Related: bug 481254

M  +18   -11   containments/desktop/plugins/folder/foldermodel.cpp
M  +11   -6    containments/desktop/plugins/folder/positioner.cpp

https://invent.kde.org/plasma/plasma-desktop/-/commit/f0ede2d83731952012be0d43c77916d18617edb2
Comment 4 Marco Martin 2024-02-28 08:50:53 UTC
Git commit e306c63ddbeaccea72a03fbb2c3dbd8245addef5 by Marco Martin.
Committed on 28/02/2024 at 08:50.
Pushed by mart into branch 'Plasma/6.0'.

FolderView Positioner: fix rows insert and remove

The positioner "proxy" model had problems both in rows insertion and
removal.

when an icon is dropped in an empty desktop area as the new "last"
position, the positioner model creates new empty items for the GridView
until it reaches the cell of the drop position.

This broke because of connection slot invocation order: the connection
to QAbstractItemModel::rowsInserted in FolderModel constructor was
executed before the connection in positioner.
In turn that connection emitted move, which invoked move on Positioner,
which at this point thinks its still in the first rows insertion
transaction, because its slot has not been executed yet,
and m_beginInsertRowsCalled is still true, so there won't be a "correct"
new beginInsertRows called.
Make it a Queued connection to push it back.

In the same way, when dragging from a "last" position, the Positioner model
will remove all the trailing empty items. But it modified m_proxyToSource
(from which rowCount() depends) before calling beginRemoveRows, sending
the model into an inconsitent state and causing an assert. Make sure
that m_proxyToSource is touched only after beginRemoveRows.
Related: bug 481254

M  +18   -11   containments/desktop/plugins/folder/foldermodel.cpp
M  +11   -6    containments/desktop/plugins/folder/positioner.cpp

https://invent.kde.org/plasma/plasma-desktop/-/commit/e306c63ddbeaccea72a03fbb2c3dbd8245addef5
Comment 5 David Edmundson 2024-06-17 13:37:34 UTC
Git commit 4da2346e42302349422cf7c45e64e838fb4d630f by David Edmundson.
Committed on 17/06/2024 at 12:44.
Pushed by davidedmundson into branch 'master'.

FolderView Positioner: fix dragging files across screens.

f0ede2d83731952012be0d43c77916d18617edb2 fixed a bug in which items
would disappear when dragging between screens. The rationale in the
description was correct. The fix there was to queue the connection of
rowsInserted so that we don't emit move signals before Positioner proxy
model has processed any pending rowsInserted signals.

This was incorrectly simplified in
99a3597285a92531efb09492421fac0a6a2e82dc . The important part isn't to
process it after FolderModel gets a source model set, but to process it
after Positioner gets the source model, which FolderView doesn't know
about and the original bug introduced.

Rather than a straight revert the code is adjusted to emit the move
signal delayed. This is safer than delaying the processing of a signal
with index arguments.
Related: bug 481254

M  +10   -4    containments/desktop/plugins/folder/foldermodel.cpp

https://invent.kde.org/plasma/plasma-desktop/-/commit/4da2346e42302349422cf7c45e64e838fb4d630f
Comment 6 David Edmundson 2024-06-17 13:45:52 UTC
Git commit 97794807a9a974ba32ee160665f0b69795888268 by David Edmundson, on behalf of David Edmundson.
Committed on 17/06/2024 at 13:38.
Pushed by davidedmundson into branch 'Plasma/6.1'.

FolderView Positioner: fix dragging files across screens.

f0ede2d83731952012be0d43c77916d18617edb2 fixed a bug in which items
would disappear when dragging between screens. The rationale in the
description was correct. The fix there was to queue the connection of
rowsInserted so that we don't emit move signals before Positioner proxy
model has processed any pending rowsInserted signals.

This was incorrectly simplified in
99a3597285a92531efb09492421fac0a6a2e82dc . The important part isn't to
process it after FolderModel gets a source model set, but to process it
after Positioner gets the source model, which FolderView doesn't know
about and the original bug introduced.

Rather than a straight revert the code is adjusted to emit the move
signal delayed. This is safer than delaying the processing of a signal
with index arguments.
Related: bug 481254


(cherry picked from commit 4da2346e42302349422cf7c45e64e838fb4d630f)

Co-authored-by: David Edmundson <kde@davidedmundson.co.uk>

M  +10   -4    containments/desktop/plugins/folder/foldermodel.cpp

https://invent.kde.org/plasma/plasma-desktop/-/commit/97794807a9a974ba32ee160665f0b69795888268