Merge remote-tracking branch 'main_repo/master' into git_is_pepega

This commit is contained in:
Mm2PL
2020-04-18 13:39:01 +02:00
155 changed files with 3182 additions and 2037 deletions
+13 -8
View File
@@ -38,13 +38,7 @@ bool CompletionModel::TaggedString::operator<(const TaggedString &that) const
return this->isEmote();
}
// try comparing insensitively, if they are the same then senstively
// (fixes order of LuL and LUL)
int k = QString::compare(this->string, that.string, Qt::CaseInsensitive);
if (k == 0)
return this->string > that.string;
return k < 0;
return CompletionModel::compareStrings(this->string, that.string);
}
//
@@ -133,7 +127,7 @@ void CompletionModel::refresh(const QString &prefix, bool isFirstWord)
TaggedString::Type::Username);
}
}
else
else if (!getSettings()->userCompletionOnlyWithAt)
{
for (const auto &name :
usernames->subrange(Prefix(usernamePrefix)))
@@ -191,4 +185,15 @@ void CompletionModel::refresh(const QString &prefix, bool isFirstWord)
}
}
bool CompletionModel::compareStrings(const QString &a, const QString &b)
{
// try comparing insensitively, if they are the same then senstively
// (fixes order of LuL and LUL)
int k = QString::compare(a, b, Qt::CaseInsensitive);
if (k == 0)
return a > b;
return k < 0;
}
} // namespace chatterino
+2
View File
@@ -49,6 +49,8 @@ public:
void refresh(const QString &prefix, bool isFirstWord = false);
static bool compareStrings(const QString &a, const QString &b);
private:
TaggedString createUser(const QString &str);
+118 -191
View File
@@ -4,244 +4,171 @@
#include <QTimer>
#include <boost/noncopyable.hpp>
#include <pajlada/signals/signal.hpp>
#include <shared_mutex>
#include <vector>
#include "debug/AssertInGuiThread.hpp"
namespace chatterino {
template <typename TVectorItem>
struct SignalVectorItemArgs {
const TVectorItem &item;
template <typename T>
struct SignalVectorItemEvent {
const T &item;
int index;
void *caller;
};
template <typename TVectorItem>
class ReadOnlySignalVector : boost::noncopyable
template <typename T>
class SignalVector : boost::noncopyable
{
using VecIt = typename std::vector<TVectorItem>::iterator;
public:
struct Iterator
: public std::iterator<std::input_iterator_tag, TVectorItem> {
Iterator(VecIt &&it, std::shared_mutex &mutex)
: it_(std::move(it))
, lock_(mutex)
, mutex_(mutex)
{
}
pajlada::Signals::Signal<SignalVectorItemEvent<T>> itemInserted;
pajlada::Signals::Signal<SignalVectorItemEvent<T>> itemRemoved;
pajlada::Signals::NoArgSignal delayedItemsChanged;
Iterator(const Iterator &other)
: it_(other.it_)
, lock_(other.mutex_)
, mutex_(other.mutex_)
{
}
Iterator &operator=(const Iterator &other)
{
this->lock_ = std::shared_lock(other.mutex_.get());
this->mutex_ = other.mutex_;
return *this;
}
TVectorItem &operator*()
{
return it_.operator*();
}
Iterator &operator++()
{
++this->it_;
return *this;
}
bool operator==(const Iterator &other)
{
return this->it_ == other.it_;
}
bool operator!=(const Iterator &other)
{
return this->it_ != other.it_;
}
auto operator-(const Iterator &other)
{
return this->it_ - other.it_;
}
private:
VecIt it_;
std::shared_lock<std::shared_mutex> lock_;
std::reference_wrapper<std::shared_mutex> mutex_;
};
ReadOnlySignalVector()
SignalVector()
: readOnly_(new std::vector<T>())
{
QObject::connect(&this->itemsChangedTimer_, &QTimer::timeout,
[this] { this->delayedItemsChanged.invoke(); });
this->itemsChangedTimer_.setInterval(100);
this->itemsChangedTimer_.setSingleShot(true);
}
virtual ~ReadOnlySignalVector() = default;
pajlada::Signals::Signal<SignalVectorItemArgs<TVectorItem>> itemInserted;
pajlada::Signals::Signal<SignalVectorItemArgs<TVectorItem>> itemRemoved;
pajlada::Signals::NoArgSignal delayedItemsChanged;
Iterator begin() const
SignalVector(std::function<bool(const T &, const T &)> &&compare)
: SignalVector()
{
return Iterator(
const_cast<std::vector<TVectorItem> &>(this->vector_).begin(),
this->mutex_);
itemCompare_ = std::move(compare);
}
Iterator end() const
virtual bool isSorted() const
{
return Iterator(
const_cast<std::vector<TVectorItem> &>(this->vector_).end(),
this->mutex_);
return bool(this->itemCompare_);
}
bool empty() const
/// A read-only version of the vector which can be used concurrently.
std::shared_ptr<const std::vector<T>> readOnly()
{
std::shared_lock lock(this->mutex_);
return this->vector_.empty();
return this->readOnly_;
}
const std::vector<TVectorItem> &getVector() const
/// This may only be called from the GUI thread.
///
/// @param item
/// Item to be inserted.
/// @param proposedIndex
/// Index to insert at. `-1` will append at the end.
/// Will be ignored if the vector is sorted.
/// @param caller
/// Caller id which will be passed in the itemInserted and itemRemoved
/// signals.
int insert(const T &item, int index = -1, void *caller = nullptr)
{
assertInGuiThread();
return this->vector_;
if (this->isSorted())
{
auto it = std::lower_bound(this->items_.begin(), this->items_.end(),
item, this->itemCompare_);
index = it - this->items_.begin();
this->items_.insert(it, item);
}
else
{
if (index == -1)
index = this->items_.size();
else
assert(index >= 0 && index <= this->items_.size());
this->items_.insert(this->items_.begin() + index, item);
}
SignalVectorItemEvent<T> args{item, index, caller};
this->itemInserted.invoke(args);
this->itemsChanged_();
return index;
}
std::vector<TVectorItem> cloneVector() const
/// This may only be called from the GUI thread.
///
/// @param item
/// Item to be appended.
/// @param caller
/// Caller id which will be passed in the itemInserted and itemRemoved
/// signals.
int append(const T &item, void *caller = nullptr)
{
std::shared_lock lock(this->mutex_);
return this->vector_;
return this->insert(item, -1, caller);
}
void invokeDelayedItemsChanged()
void removeAt(int index, void *caller = nullptr)
{
assertInGuiThread();
assert(index >= 0 && index < int(this->items_.size()));
T item = this->items_[index];
this->items_.erase(this->items_.begin() + index);
SignalVectorItemEvent<T> args{item, index, caller};
this->itemRemoved.invoke(args);
this->itemsChanged_();
}
const std::vector<T> &raw() const
{
assertInGuiThread();
return this->items_;
}
[[deprecated]] std::vector<T> cloneVector()
{
return *this->readOnly();
}
// mirror vector functions
auto begin() const
{
assertInGuiThread();
return this->items_.begin();
}
auto end() const
{
assertInGuiThread();
return this->items_.end();
}
decltype(auto) operator[](size_t index)
{
assertInGuiThread();
return this->items[index];
}
auto empty()
{
assertInGuiThread();
return this->items_.empty();
}
private:
void itemsChanged_()
{
// emit delayed event
if (!this->itemsChangedTimer_.isActive())
{
this->itemsChangedTimer_.start();
}
// update concurrent version
this->readOnly_ = std::make_shared<const std::vector<T>>(this->items_);
}
virtual bool isSorted() const = 0;
protected:
std::vector<TVectorItem> vector_;
std::vector<T> items_;
std::shared_ptr<const std::vector<T>> readOnly_;
QTimer itemsChangedTimer_;
mutable std::shared_mutex mutex_;
};
template <typename TVectorItem>
class BaseSignalVector : public ReadOnlySignalVector<TVectorItem>
{
public:
// returns the actual index of the inserted item
virtual int insertItem(const TVectorItem &item, int proposedIndex = -1,
void *caller = nullptr) = 0;
void removeItem(int index, void *caller = nullptr)
{
assertInGuiThread();
std::unique_lock lock(this->mutex_);
assert(index >= 0 && index < int(this->vector_.size()));
TVectorItem item = this->vector_[index];
this->vector_.erase(this->vector_.begin() + index);
lock.unlock(); // manual unlock
SignalVectorItemArgs<TVectorItem> args{item, index, caller};
this->itemRemoved.invoke(args);
this->invokeDelayedItemsChanged();
}
int appendItem(const TVectorItem &item, void *caller = nullptr)
{
return this->insertItem(item, -1, caller);
}
};
template <typename TVectorItem>
class UnsortedSignalVector : public BaseSignalVector<TVectorItem>
{
public:
virtual int insertItem(const TVectorItem &item, int index = -1,
void *caller = nullptr) override
{
assertInGuiThread();
{
std::unique_lock lock(this->mutex_);
if (index == -1)
{
index = this->vector_.size();
}
else
{
assert(index >= 0 && index <= this->vector_.size());
}
this->vector_.insert(this->vector_.begin() + index, item);
}
SignalVectorItemArgs<TVectorItem> args{item, index, caller};
this->itemInserted.invoke(args);
this->invokeDelayedItemsChanged();
return index;
}
virtual bool isSorted() const override
{
return false;
}
};
template <typename TVectorItem, typename Compare>
class SortedSignalVector : public BaseSignalVector<TVectorItem>
{
public:
virtual int insertItem(const TVectorItem &item, int = -1,
void *caller = nullptr) override
{
assertInGuiThread();
int index = -1;
{
std::unique_lock lock(this->mutex_);
auto it = std::lower_bound(this->vector_.begin(),
this->vector_.end(), item, Compare{});
index = it - this->vector_.begin();
this->vector_.insert(it, item);
}
SignalVectorItemArgs<TVectorItem> args{item, index, caller};
this->itemInserted.invoke(args);
this->invokeDelayedItemsChanged();
return index;
}
virtual bool isSorted() const override
{
return true;
}
std::function<bool(const T &, const T &)> itemCompare_;
};
} // namespace chatterino
+75 -9
View File
@@ -25,11 +25,11 @@ public:
}
}
void init(BaseSignalVector<TVectorItem> *vec)
void initialize(SignalVector<TVectorItem> *vec)
{
this->vector_ = vec;
auto insert = [this](const SignalVectorItemArgs<TVectorItem> &args) {
auto insert = [this](const SignalVectorItemEvent<TVectorItem> &args) {
if (args.caller == this)
{
return;
@@ -52,9 +52,9 @@ public:
};
int i = 0;
for (const TVectorItem &item : vec->getVector())
for (const TVectorItem &item : vec->raw())
{
SignalVectorItemArgs<TVectorItem> args{item, i++, 0};
SignalVectorItemEvent<TVectorItem> args{item, i++, 0};
insert(args);
}
@@ -89,6 +89,12 @@ public:
this->afterInit();
}
SignalVectorModel<TVectorItem> *initialized(SignalVector<TVectorItem> *vec)
{
this->initialize(vec);
return this;
}
virtual ~SignalVectorModel()
{
for (Row &row : this->rows_)
@@ -147,12 +153,12 @@ public:
else
{
int vecRow = this->getVectorIndexFromModelIndex(row);
this->vector_->removeItem(vecRow, this);
this->vector_->removeAt(vecRow, this);
assert(this->rows_[row].original);
TVectorItem item = this->getItemFromRow(
this->rows_[row].items, this->rows_[row].original.get());
this->vector_->insertItem(item, vecRow, this);
this->vector_->insert(item, vecRow, this);
}
return true;
@@ -219,7 +225,7 @@ public:
void deleteRow(int row)
{
int signalVectorRow = this->getVectorIndexFromModelIndex(row);
this->vector_->removeItem(signalVectorRow);
this->vector_->removeAt(signalVectorRow);
}
bool removeRows(int row, int count, const QModelIndex &parent) override
@@ -234,11 +240,71 @@ public:
assert(row >= 0 && row < this->rows_.size());
int signalVectorRow = this->getVectorIndexFromModelIndex(row);
this->vector_->removeItem(signalVectorRow);
this->vector_->removeAt(signalVectorRow);
return true;
}
QStringList mimeTypes() const override
{
return {"chatterino_row_id"};
}
QMimeData *mimeData(const QModelIndexList &list) const
{
if (list.length() == 1)
{
return nullptr;
}
// Check if all indices are in the same row -> single row selected
for (auto &&x : list)
{
if (x.row() != list.first().row())
return nullptr;
}
auto data = new QMimeData;
data->setData("chatterino_row_id", QByteArray::number(list[0].row()));
return data;
}
bool dropMimeData(const QMimeData *data, Qt::DropAction action, int /*row*/,
int /*column*/, const QModelIndex &parent) override
{
if (data->hasFormat("chatterino_row_id") &&
action & (Qt::DropAction::MoveAction | Qt::DropAction::CopyAction))
{
int from = data->data("chatterino_row_id").toInt();
int to = parent.row();
if (from < 0 || from > this->vector_->raw().size() || to < 0 ||
to > this->vector_->raw().size())
{
return false;
}
if (from != to)
{
auto item = this->vector_->raw()[from];
this->vector_->removeAt(from);
this->vector_->insert(item, to);
}
// We return false since we remove items ourselves.
return false;
}
return false;
}
Qt::DropActions supportedDropActions() const override
{
return this->vector_->isSorted()
? Qt::DropActions()
: Qt::DropAction::CopyAction | Qt::DropAction::MoveAction;
}
protected:
virtual void afterInit()
{
@@ -326,7 +392,7 @@ protected:
private:
std::vector<QMap<int, QVariant>> headerData_;
BaseSignalVector<TVectorItem> *vector_;
SignalVector<TVectorItem> *vector_;
std::vector<Row> rows_;
int columnCount_;