Merge pull request #178 from TheOneRing/fix_snore_crash
authorManuel Nickschas <sputnick@quassel-irc.org>
Mon, 8 Feb 2016 20:34:48 +0000 (21:34 +0100)
committerManuel Nickschas <sputnick@quassel-irc.org>
Mon, 8 Feb 2016 20:34:48 +0000 (21:34 +0100)
Fix possible crash, mostly occurring on notification flood.

CMakeLists.txt
src/client/networkmodel.cpp
src/client/selectionmodelsynchronizer.cpp
src/common/aliasmanager.cpp
src/common/peer.cpp
src/uisupport/action.cpp
src/uisupport/bufferview.cpp
src/uisupport/bufferview.h
src/uisupport/bufferviewfilter.cpp
src/uisupport/bufferviewfilter.h

index 2c29af4..046b66d 100644 (file)
@@ -430,7 +430,7 @@ set(CMAKE_REQUIRED_INCLUDES ${QT_INCLUDES} ${Qt5Core_INCLUDE_DIRS})
 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Core_EXECUTABLE_COMPILE_FLAGS}")
 check_cxx_source_compiles("
     #include \"qglobal.h\"
-    #if defined QT_NO_OPENSSL || defined QT_NO_SSL
+    #if defined QT_NO_SSL
     #  error \"No SSL support\"
     #endif
     int main() {}"
index 4d49efb..ddc71dd 100644 (file)
@@ -463,6 +463,12 @@ bool QueryBufferItem::setData(int column, const QVariant &value, int role)
     case Qt::EditRole:
     {
         QString newName = value.toString();
+
+        // Sanity check - buffer names must not contain newlines!
+        int nlpos = newName.indexOf('\n');
+        if (nlpos >= 0)
+            newName = newName.left(nlpos);
+
         if (!newName.isEmpty()) {
             Client::renameBuffer(bufferId(), newName);
             return true;
index 0dcf7f8..14c57c0 100644 (file)
@@ -255,6 +255,13 @@ void SelectionModelSynchronizer::currentChanged(const QModelIndex &current, cons
         ++iter;
     }
     _changeCurrentEnabled = true;
+
+    // Trigger a dataChanged() signal from the base model to update all proxy models (e.g. filters).
+    // Since signals are protected, we have to use invokeMethod for faking signal emission.
+    if (previous.isValid()) {
+        QMetaObject::invokeMethod(model(), "dataChanged", Qt::DirectConnection,
+                                  Q_ARG(QModelIndex, previous), Q_ARG(QModelIndex, previous));
+    }
 }
 
 
index 05ef3c9..cd21f99 100644 (file)
@@ -198,7 +198,7 @@ void AliasManager::expand(const QString &alias, const BufferInfo &bufferInfo, co
 
     while (!expandedCommands.isEmpty()) {
         QString command;
-        if (expandedCommands[0].trimmed().toLower().startsWith("/wait")) {
+        if (expandedCommands[0].trimmed().toLower().startsWith("/wait ")) {
             command = expandedCommands.join("; ");
             expandedCommands.clear();
         }
index 3785326..c076806 100644 (file)
@@ -34,20 +34,23 @@ AuthHandler *Peer::authHandler() const
 }
 
 
-// Note that we need to use a fixed-size integer instead of uintptr_t, in order
-// to avoid issues with different architectures for client and core.
-// In practice, we'll never really have to restore the real value of a PeerPtr from
-// a QVariant.
+// PeerPtr is used in RPC signatures for enabling receivers to send replies
+// to a particular peer rather than broadcast to all connected ones.
+// To enable this, the SignalProxy transparently replaces the bogus value
+// received over the network with the actual address of the local Peer
+// instance. Because the actual value isn't needed on the wire, it is
+// serialized as null.
 QDataStream &operator<<(QDataStream &out, PeerPtr ptr)
 {
-    out << reinterpret_cast<quint64>(ptr);
+    Q_UNUSED(ptr);
+    out << static_cast<quint64>(0);  // 64 bit for historic reasons
     return out;
 }
 
 QDataStream &operator>>(QDataStream &in, PeerPtr &ptr)
 {
+    ptr = nullptr;
     quint64 value;
     in >> value;
-    ptr = reinterpret_cast<PeerPtr>(value);
     return in;
 }
index c222dc1..2758e77 100644 (file)
@@ -98,11 +98,16 @@ void Action::setShortcutConfigurable(bool b)
 QKeySequence Action::shortcut(ShortcutTypes type) const
 {
     Q_ASSERT(type);
-    if (type == DefaultShortcut)
+    if (type == DefaultShortcut) {
+#if QT_VERSION < 0x050000
         return property("defaultShortcut").value<QKeySequence>();
+#else
+        auto sequence = property("defaultShortcuts").value<QList<QKeySequence>>();
+        return sequence.isEmpty() ? QKeySequence() : sequence.first();
+#endif
+    }
 
-    if (shortcuts().count()) return shortcuts().value(0);
-    return QKeySequence();
+    return shortcuts().isEmpty() ? QKeySequence() : shortcuts().first();
 }
 
 
@@ -116,9 +121,13 @@ void Action::setShortcut(const QKeySequence &key, ShortcutTypes type)
 {
     Q_ASSERT(type);
 
-    if (type & DefaultShortcut)
+    if (type & DefaultShortcut) {
+#if QT_VERSION < 0x050000
         setProperty("defaultShortcut", key);
-
+#else
+        setProperty("defaultShortcuts", QVariant::fromValue(QList<QKeySequence>() << key));
+#endif
+    }
     if (type & ActiveShortcut)
         QAction::setShortcut(key);
 }
index d092146..c27e3a3 100644 (file)
@@ -158,21 +158,6 @@ void BufferView::setFilteredModel(QAbstractItemModel *model_, BufferViewConfig *
 }
 
 
-void BufferView::setSelectionModel(QItemSelectionModel *selectionModel)
-{
-    if (QTreeView::selectionModel())
-        disconnect(selectionModel, SIGNAL(currentChanged(QModelIndex, QModelIndex)),
-            model(), SIGNAL(checkPreviousCurrentForRemoval(QModelIndex, QModelIndex)));
-
-    QTreeView::setSelectionModel(selectionModel);
-    BufferViewFilter *filter = qobject_cast<BufferViewFilter *>(model());
-    if (filter) {
-        connect(selectionModel, SIGNAL(currentChanged(QModelIndex, QModelIndex)),
-            filter, SLOT(checkPreviousCurrentForRemoval(QModelIndex, QModelIndex)));
-    }
-}
-
-
 void BufferView::setConfig(BufferViewConfig *config)
 {
     if (_config == config)
index a49ce15..2962e5e 100644 (file)
@@ -52,7 +52,6 @@ public:
 
     void setModel(QAbstractItemModel *model);
     void setFilteredModel(QAbstractItemModel *model, BufferViewConfig *config);
-    virtual void setSelectionModel(QItemSelectionModel *selectionModel);
 
     void setConfig(BufferViewConfig *config);
     inline BufferViewConfig *config() { return _config; }
index c829267..4c5d4a9 100644 (file)
 #include "networkmodel.h"
 #include "uistyle.h"
 
-class CheckRemovalEvent : public QEvent
-{
-public:
-    CheckRemovalEvent(const QModelIndex &source_index) : QEvent(QEvent::User), index(source_index) {};
-    QPersistentModelIndex index;
-};
-
 
 /*****************************************
 * The Filter for the Tree View
@@ -57,9 +50,6 @@ BufferViewFilter::BufferViewFilter(QAbstractItemModel *model, BufferViewConfig *
 
     setDynamicSortFilter(true);
 
-    connect(this, SIGNAL(_dataChanged(const QModelIndex &, const QModelIndex &)),
-        this, SLOT(_q_sourceDataChanged(QModelIndex, QModelIndex)));
-
     _enableEditMode.setCheckable(true);
     _enableEditMode.setChecked(_editMode);
     connect(&_enableEditMode, SIGNAL(toggled(bool)), this, SLOT(enableEditMode(bool)));
@@ -542,34 +532,6 @@ bool BufferViewFilter::setCheckedState(const QModelIndex &index, Qt::CheckState
 }
 
 
-void BufferViewFilter::checkPreviousCurrentForRemoval(const QModelIndex &current, const QModelIndex &previous)
-{
-    Q_UNUSED(current);
-    if (previous.isValid())
-        QCoreApplication::postEvent(this, new CheckRemovalEvent(previous));
-}
-
-
-void BufferViewFilter::customEvent(QEvent *event)
-{
-    if (event->type() != QEvent::User)
-        return;
-
-    CheckRemovalEvent *removalEvent = static_cast<CheckRemovalEvent *>(event);
-    checkItemForRemoval(removalEvent->index);
-
-    event->accept();
-}
-
-
-void BufferViewFilter::checkItemsForRemoval(const QModelIndex &topLeft, const QModelIndex &bottomRight)
-{
-    QModelIndex source_topLeft = mapToSource(topLeft);
-    QModelIndex source_bottomRight = mapToSource(bottomRight);
-    emit _dataChanged(source_topLeft, source_bottomRight);
-}
-
-
 bool BufferViewFilter::bufferIdLessThan(const BufferId &left, const BufferId &right)
 {
     Q_CHECK_PTR(Client::networkModel());
index 1a4d781..5cf0cce 100644 (file)
@@ -69,20 +69,13 @@ public:
 
     QList<QAction *> actions(const QModelIndex &index);
 
-public slots:
-    void checkPreviousCurrentForRemoval(const QModelIndex &current, const QModelIndex &previous);
-    void checkItemForRemoval(const QModelIndex &index) { checkItemsForRemoval(index, index); }
-    void checkItemsForRemoval(const QModelIndex &topLeft, const QModelIndex &bottomRight);
-
 protected:
     bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const;
     bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const;
     bool bufferLessThan(const QModelIndex &source_left, const QModelIndex &source_right) const;
     bool networkLessThan(const QModelIndex &source_left, const QModelIndex &source_right) const;
-    virtual void customEvent(QEvent *event);
 
 signals:
-    void _dataChanged(const QModelIndex &source_topLeft, const QModelIndex &source_bottomRight);
     void configChanged();
 
 private slots: