summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTobias Markmann <tm@ayena.de>2017-05-15 14:27:12 (GMT)
committerTobias Markmann <tm@ayena.de>2017-05-15 14:34:02 (GMT)
commit33f9a7682a9b40d141900aa7ce302a8e47d4d762 (patch)
tree288ddffe71fb0117bf8d0998c99df54c0d91deb3
parentd93be16eb1bb43ba602fcd7398fc0e46084dbd7f (diff)
downloadswift-33f9a7682a9b40d141900aa7ce302a8e47d4d762.zip
swift-33f9a7682a9b40d141900aa7ce302a8e47d4d762.tar.bz2
Use QPointer to prevent access to potentially freed QtTreeWidget
As the QtTreeWidget and the QtFilterWidget are siblings in their parent widget, it might happen that the QtTreeWidget is deleted before the QtFilterWidget. Using Pointer, we are able to detect this case and can prevent accessing the already deleted QtTreeWidget. QtFilterWidget cannot be made the child of the QtTreeWidget in this case, so this fix uses the QPointers approach as a workaround. SWIFT-247 Test-Information: Tests pass and builds on macOS 10.12.4 with Qt 5.4.2. Change-Id: I3a60006519b580010718c4d2aa94638555c0afdf
-rw-r--r--Swift/QtUI/Roster/QtFilterWidget.cpp12
-rw-r--r--Swift/QtUI/Roster/QtFilterWidget.h5
2 files changed, 15 insertions, 2 deletions
diff --git a/Swift/QtUI/Roster/QtFilterWidget.cpp b/Swift/QtUI/Roster/QtFilterWidget.cpp
index 4df4a39..a52dfff 100644
--- a/Swift/QtUI/Roster/QtFilterWidget.cpp
+++ b/Swift/QtUI/Roster/QtFilterWidget.cpp
@@ -26,60 +26,64 @@
namespace Swift {
QtFilterWidget::QtFilterWidget(QWidget* parent, QtTreeWidget* treeView, UIEventStream* eventStream, QBoxLayout* layout) : QWidget(parent), treeView_(treeView), eventStream_(eventStream), fuzzyRosterFilter_(nullptr), isModifierSinglePressed_(false) {
int targetIndex = layout->indexOf(treeView);
QVBoxLayout* vboxLayout = new QVBoxLayout(this);
vboxLayout->setSpacing(0);
vboxLayout->setContentsMargins(0,0,0,0);
filterLineEdit_ = new QtClosableLineEdit(this);
filterLineEdit_->hide();
vboxLayout->addWidget(filterLineEdit_);
vboxLayout->addWidget(treeView);
setLayout(vboxLayout);
layout->insertWidget(targetIndex, this);
filterLineEdit_->installEventFilter(this);
treeView_->installEventFilter(this);
sourceModel_ = treeView_->model();
}
QtFilterWidget::~QtFilterWidget() {
filterLineEdit_->removeEventFilter(this);
treeView_->removeEventFilter(this);
}
bool QtFilterWidget::eventFilter(QObject*, QEvent* event) {
+ if (!treeView_) {
+ return false;
+ }
+
if (event->type() == QEvent::KeyPress ||
event->type() == QEvent::KeyRelease ||
// InputMethodQuery got introduced in Qt 5.
#if QT_VERSION >= 0x050000
event->type() == QEvent::InputMethodQuery ||
#endif
event->type() == QEvent::InputMethod) {
event->ignore();
QKeyEvent* keyEvent = dynamic_cast<QKeyEvent*>(event);
if (keyEvent) {
if (keyEvent->key() == Qt::Key_Up || keyEvent->key() == Qt::Key_Down) {
return false;
} else if ((keyEvent->key() == Qt::Key_Left || keyEvent->key() == Qt::Key_Right) && filterLineEdit_->text().isEmpty()) {
return false;
} else if (keyEvent->key() == Qt::Key_Alt && event->type() == QEvent::KeyPress) {
isModifierSinglePressed_ = true;
} else if ((keyEvent->key() == Qt::Key_Alt && event->type() == QEvent::KeyRelease && isModifierSinglePressed_)
|| (keyEvent->key() == Qt::Key_Menu)) {
QPoint itemOffset(2,2);
QPoint contextMenuPosition = treeView_->visualRect(treeView_->currentIndex()).topLeft() + itemOffset;;
QApplication::postEvent(treeView_, new QContextMenuEvent(QContextMenuEvent::Keyboard, contextMenuPosition, treeView_->mapToGlobal(contextMenuPosition)));
return true;
} else if (keyEvent->key() == Qt::Key_Return) {
JID target = treeView_->selectedJID();
if (target.isValid()) {
eventStream_->send(std::make_shared<RequestChatUIEvent>(target));
}
filterLineEdit_->setText("");
updateRosterFilters();
} else if (keyEvent->key() == Qt::Key_Escape) {
@@ -92,79 +96,87 @@ bool QtFilterWidget::eventFilter(QObject*, QEvent* event) {
filterLineEdit_->event(event);
if (event->type() == QEvent::KeyRelease) {
updateRosterFilters();
}
return true;
}
return false;
}
void QtFilterWidget::popAllFilters() {
std::vector<RosterFilter*> filters = treeView_->getRoster()->getFilters();
for (auto filter : filters) {
filters_.push_back(filter);
treeView_->getRoster()->removeFilter(filter);
}
treeView_->getRoster()->onFilterAdded.connect(boost::bind(&QtFilterWidget::handleFilterAdded, this, _1));
treeView_->getRoster()->onFilterRemoved.connect(boost::bind(&QtFilterWidget::handleFilterRemoved, this, _1));
}
void QtFilterWidget::pushAllFilters() {
treeView_->getRoster()->onFilterAdded.disconnect(boost::bind(&QtFilterWidget::handleFilterAdded, this, _1));
treeView_->getRoster()->onFilterRemoved.disconnect(boost::bind(&QtFilterWidget::handleFilterRemoved, this, _1));
for (auto filter : filters_) {
treeView_->getRoster()->addFilter(filter);
}
filters_.clear();
}
void QtFilterWidget::updateRosterFilters() {
+ if (!treeView_) {
+ return;
+ }
+
if (fuzzyRosterFilter_) {
if (filterLineEdit_->text().isEmpty()) {
// remove currently installed search filter and put old filters back
treeView_->getRoster()->removeFilter(fuzzyRosterFilter_);
delete fuzzyRosterFilter_;
fuzzyRosterFilter_ = nullptr;
pushAllFilters();
} else {
// remove currently intsalled search filter and put new search filter in place
updateSearchFilter();
}
} else {
if (!filterLineEdit_->text().isEmpty()) {
// remove currently installed filters and put a search filter in place
popAllFilters();
updateSearchFilter();
}
}
filterLineEdit_->setVisible(!filterLineEdit_->text().isEmpty());
}
void QtFilterWidget::updateSearchFilter() {
+ if (!treeView_) {
+ return;
+ }
+
if (fuzzyRosterFilter_) {
treeView_->getRoster()->removeFilter(fuzzyRosterFilter_);
delete fuzzyRosterFilter_;
fuzzyRosterFilter_ = nullptr;
}
fuzzyRosterFilter_ = new FuzzyRosterFilter(Q2PSTRING(filterLineEdit_->text()));
treeView_->getRoster()->addFilter(fuzzyRosterFilter_);
treeView_->setCurrentIndex(sourceModel_->index(0, 0, sourceModel_->index(0,0)));
}
void QtFilterWidget::handleFilterAdded(RosterFilter* filter) {
if (filter != fuzzyRosterFilter_) {
filterLineEdit_->setText("");
updateRosterFilters();
}
}
void QtFilterWidget::handleFilterRemoved(RosterFilter* filter) {
/* make sure we don't end up adding this one back in later */
filters_.erase(std::remove(filters_.begin(), filters_.end(), filter), filters_.end());
if (filter != fuzzyRosterFilter_) {
filterLineEdit_->setText("");
updateRosterFilters();
}
}
}
diff --git a/Swift/QtUI/Roster/QtFilterWidget.h b/Swift/QtUI/Roster/QtFilterWidget.h
index ea3c325..85f607e 100644
--- a/Swift/QtUI/Roster/QtFilterWidget.h
+++ b/Swift/QtUI/Roster/QtFilterWidget.h
@@ -1,57 +1,58 @@
/*
* Copyright (c) 2013 Tobias Markmann
* Licensed under the simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
/*
- * Copyright (c) 2016 Isode Limited.
+ * Copyright (c) 2016-2017 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
#pragma once
#include <vector>
#include <QBoxLayout>
+#include <QPointer>
#include <QWidget>
#include <Swift/Controllers/Roster/FuzzyRosterFilter.h>
#include <Swift/Controllers/Roster/RosterFilter.h>
#include <Swift/QtUI/Roster/QtTreeWidget.h>
namespace Swift {
class UIEventStream;
class QtClosableLineEdit;
class QtFilterWidget : public QWidget {
Q_OBJECT
public:
QtFilterWidget(QWidget* parent, QtTreeWidget* treeView, UIEventStream* eventStream, QBoxLayout* layout = nullptr);
virtual ~QtFilterWidget();
protected:
bool eventFilter(QObject*, QEvent* event);
private:
void popAllFilters();
void pushAllFilters();
void updateRosterFilters();
void updateSearchFilter();
void handleFilterAdded(RosterFilter* filter);
void handleFilterRemoved(RosterFilter* filter);
private:
QtClosableLineEdit* filterLineEdit_;
- QtTreeWidget* treeView_;
+ QPointer<QtTreeWidget> treeView_;
UIEventStream* eventStream_;
std::vector<RosterFilter*> filters_;
QAbstractItemModel* sourceModel_;
FuzzyRosterFilter* fuzzyRosterFilter_;
bool isModifierSinglePressed_;
};
}