From a3d142034fed5ddf6004c5fb2297eb82471314c7 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Wed, 29 Jul 2020 07:51:48 +0200 Subject: [PATCH] debug next status --- resources/icons.qrc | 1 + resources/rssguard.qrc | 1 + resources/text/COPYING_MIT | 19 + src/librssguard/3rd-party/boolinq/boolinq.h | 882 ++++++++++++++++++ src/librssguard/core/messagesmodel.cpp | 10 + src/librssguard/core/messagesmodel.h | 2 + src/librssguard/gui/dialogs/formabout.cpp | 7 + src/librssguard/gui/dialogs/formabout.ui | 68 +- src/librssguard/gui/dialogs/formmain.cpp | 2 +- src/librssguard/gui/feedsview.cpp | 12 +- src/librssguard/gui/messagesview.cpp | 31 +- src/librssguard/gui/messagesview.h | 18 +- .../services/abstract/recyclebin.cpp | 2 +- .../services/abstract/recyclebin.h | 2 +- .../services/abstract/rootitem.cpp | 2 +- src/librssguard/services/abstract/rootitem.h | 2 +- .../services/abstract/serviceroot.cpp | 4 +- .../services/abstract/serviceroot.h | 8 +- .../services/gmail/gmailserviceroot.cpp | 23 +- .../services/gmail/gmailserviceroot.h | 6 + .../services/gmail/gui/formaddeditemail.cpp | 13 +- .../gmail/network/gmailnetworkfactory.cpp | 50 +- .../gmail/network/gmailnetworkfactory.h | 3 +- .../owncloud/gui/formeditowncloudaccount.cpp | 2 +- .../network/owncloudnetworkfactory.cpp | 2 + .../services/standard/standardfeed.cpp | 2 +- .../services/standard/standardfeed.h | 2 +- 27 files changed, 1130 insertions(+), 46 deletions(-) create mode 100755 resources/text/COPYING_MIT create mode 100755 src/librssguard/3rd-party/boolinq/boolinq.h diff --git a/resources/icons.qrc b/resources/icons.qrc index 2c39d2853..3320fda80 100644 --- a/resources/icons.qrc +++ b/resources/icons.qrc @@ -37,6 +37,7 @@ ./graphics/Faenza/actions/64/mail-mark-read.png ./graphics/Faenza/actions/64/mail-mark-unread.png ./graphics/Faenza/actions/64/mail-message-new.png + ./graphics/Faenza/actions/64/mail-reply-sender.png ./graphics/Faenza/actions/64/mail-send.png ./graphics/Faenza/actions/64/mail-sent.png ./graphics/Faenza/actions/64/media-playback-start.png diff --git a/resources/rssguard.qrc b/resources/rssguard.qrc index feb8bc999..6367a2995 100755 --- a/resources/rssguard.qrc +++ b/resources/rssguard.qrc @@ -2,6 +2,7 @@ text/CHANGELOG text/COPYING_BSD + text/COPYING_MIT text/COPYING_GNU_GPL text/COPYING_GNU_GPL_HTML diff --git a/resources/text/COPYING_MIT b/resources/text/COPYING_MIT new file mode 100755 index 000000000..58363dadb --- /dev/null +++ b/resources/text/COPYING_MIT @@ -0,0 +1,19 @@ +Copyright (C) 2019 by Anton Bukov (k06aaa@gmail.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/src/librssguard/3rd-party/boolinq/boolinq.h b/src/librssguard/3rd-party/boolinq/boolinq.h new file mode 100755 index 000000000..0d52c1167 --- /dev/null +++ b/src/librssguard/3rd-party/boolinq/boolinq.h @@ -0,0 +1,882 @@ +#pragma once + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +// + +namespace boolinq { + + struct LinqEndException {}; + + enum BytesDirection { + BytesFirstToLast, + BytesLastToFirst, + }; + + enum BitsDirection { + BitsHighToLow, + BitsLowToHigh, + }; + + template + class Linq { + std::function nextFunc; + S storage; + + public: + typedef T value_type; + + Linq() : nextFunc(), storage() + { + } + + Linq(S storage, std::function nextFunc) : nextFunc(nextFunc), storage(storage) + { + } + + T next() + { + return nextFunc(storage); + } + + void for_each_i(std::function apply) const + { + Linq linq = *this; + try { + for (int i = 0; ; i++) { + apply(linq.next(), i); + } + } + catch (LinqEndException &) {} + } + + void for_each(std::function apply) const + { + return for_each_i([apply](T value, int index) { return apply(value); }); + } + + Linq, int>, T> where_i(std::function filter) const + { + return Linq, int>, T>( + std::make_tuple(*this, 0), + [filter](std::tuple, int> &tuple) { + Linq &linq = std::get<0>(tuple); + int &index = std::get<1>(tuple); + + while (true) { + T ret = linq.next(); + if (filter(ret, index++)) { + return ret; + } + } + } + ); + } + + Linq, int>, T> where(std::function filter) const + { + return where_i([filter](T value, int index) { return filter(value); }); + } + + Linq, int>, T> take(int count) const + { + return where_i([count](T /*value*/, int i) { + if (i == count) { + throw LinqEndException(); + } + return true; + }); + } + + Linq, int>, T> takeWhile_i(std::function predicate) const + { + return where_i([predicate](T value, int i) { + if (!predicate(value, i)) { + throw LinqEndException(); + } + return true; + }); + } + + Linq, int>, T> takeWhile(std::function predicate) const + { + return takeWhile_i([predicate](T value, int /*i*/) { return predicate(value); }); + } + + Linq, int>, T> skip(int count) const + { + return where_i([count](T value, int i) { return i >= count; }); + } + + Linq, int, bool>, T> skipWhile_i(std::function predicate) const + { + return Linq, int, bool>, T>( + std::make_tuple(*this, 0, false), + [predicate](std::tuple, int, bool> &tuple) { + Linq &linq = std::get<0>(tuple); + int &index = std::get<1>(tuple); + bool &flag = std::get<2>(tuple); + + if (flag) { + return linq.next(); + } + while (true) { + T ret = linq.next(); + if (!predicate(ret, index++)) { + flag = true; + return ret; + } + } + } + ); + } + + Linq, int, bool>, T> skipWhile(std::function predicate) const + { + return skipWhile_i([predicate](T value, int /*i*/) { return predicate(value); }); + } + + template + Linq, std::vector, int>, T> append(Types ... newValues) const + { + return Linq, std::vector, int>, T>( + std::make_tuple(*this, std::vector{ newValues... }, -1), + [](std::tuple, std::vector, int> &tuple) { + Linq &linq = std::get<0>(tuple); + std::vector &values = std::get<1>(tuple); + int &index = std::get<2>(tuple); + + if (index == -1) { + try { + return linq.next(); + } + catch (LinqEndException &) { + index = 0; + } + } + + if (index < values.size()) { + return values[index++]; + } + + throw LinqEndException(); + } + ); + } + + template + Linq, std::vector, int>, T> prepend(Types ... newValues) const + { + return Linq, std::vector, int>, T>( + std::make_tuple(*this, std::vector{ newValues... }, 0), + [](std::tuple, std::vector, int> &tuple) { + Linq &linq = std::get<0>(tuple); + std::vector &values = std::get<1>(tuple); + int &index = std::get<2>(tuple); + + if (index < values.size()) { + return values[index++]; + } + return linq.next(); + } + ); + } + + template::type> + Linq, int>, _TRet> select_i(F apply) const + { + return Linq, int>, _TRet>( + std::make_tuple(*this, 0), + [apply](std::tuple, int> &tuple) { + Linq &linq = std::get<0>(tuple); + int &index = std::get<1>(tuple); + + return apply(linq.next(), index++); + } + ); + } + + template::type> + Linq, int>, _TRet> select(F apply) const + { + return select_i([apply](T value, int /*index*/) { return apply(value); }); + } + + template + Linq, int>, TRet> cast() const + { + return select_i([](T value, int /*i*/) { return TRet(value); }); + } + + template + Linq, Linq, bool>, T> concat(const Linq & rhs) const + { + return Linq, Linq, bool>, T>( + std::make_tuple(*this, rhs, false), + [](std::tuple, Linq, bool> &tuple){ + Linq &first = std::get<0>(tuple); + Linq &second = std::get<1>(tuple); + bool &flag = std::get<2>(tuple); + + if (!flag) { + try { + return first.next(); + } + catch (LinqEndException &) {} + } + return second.next(); + } + ); + } + + template< + typename F, + typename _TRet = typename std::result_of::type, + typename _TRetVal = typename _TRet::value_type + > + Linq, _TRet, int, bool>, _TRetVal> selectMany_i(F apply) const + { + return Linq, _TRet, int, bool>, _TRetVal>( + std::make_tuple(*this, _TRet(), 0, true), + [apply](std::tuple, _TRet, int, bool> &tuple) { + Linq &linq = std::get<0>(tuple); + _TRet ¤t = std::get<1>(tuple); + int &index = std::get<2>(tuple); + bool &finished = std::get<3>(tuple); + + while (true) { + if (finished) { + current = apply(linq.next(), index++); + finished = false; + } + try { + return current.next(); + } + catch (LinqEndException &) { + finished = true; + } + } + } + ); + } + + template< + typename F, + typename _TRet = typename std::result_of::type, + typename _TRetVal = typename _TRet::value_type + > + Linq, _TRet, int, bool>, _TRetVal> selectMany(F apply) const + { + return selectMany_i([apply](T value, int index) { return apply(value); }); + } + + template< + typename F, + typename _TKey = typename std::result_of::type, + typename _TValue = Linq, int>, T> // where(predicate) + > + Linq, Linq, std::unordered_set<_TKey> >, std::pair<_TKey, _TValue> > groupBy(F apply) const + { + return Linq, Linq, std::unordered_set<_TKey> >, std::pair<_TKey, _TValue> >( + std::make_tuple(*this, *this, std::unordered_set<_TKey>()), + [apply](std::tuple, Linq, std::unordered_set<_TKey> > &tuple){ + Linq &linq = std::get<0>(tuple); + Linq &linqCopy = std::get<1>(tuple); + std::unordered_set<_TKey> &set = std::get<2>(tuple); + + _TKey key = apply(linq.next()); + if (set.insert(key).second) { + return std::make_pair(key, linqCopy.where([apply, key](T v){ + return apply(v) == key; + })); + } + throw LinqEndException(); + } + ); + } + + template::type> + Linq, std::unordered_set<_TRet> >, T> distinct(F transform) const + { + return Linq, std::unordered_set<_TRet> >, T>( + std::make_tuple(*this, std::unordered_set<_TRet>()), + [transform](std::tuple, std::unordered_set<_TRet> > &tuple) { + Linq &linq = std::get<0>(tuple); + std::unordered_set<_TRet> &set = std::get<1>(tuple); + + while (true) { + T value = linq.next(); + if (set.insert(transform(value)).second) { + return value; + } + } + } + ); + } + + Linq, std::unordered_set >, T> distinct() const + { + return distinct([](T value) { return value; }); + } + + template::const_iterator> + Linq, _TIter, bool>, T> orderBy(F transform) const + { + std::vector items = toStdVector(); + std::sort(items.begin(), items.end(), [transform](const T &a, const T &b) { + return transform(a) < transform(b); + }); + + return Linq, _TIter, bool>, T>( + std::make_tuple(items, _TIter(), false), + [](std::tuple, _TIter, bool> &tuple) { + std::vector &vec = std::get<0>(tuple); + _TIter &it = std::get<1>(tuple); + bool &flag = std::get<2>(tuple); + + if (!flag) { + flag = true; + it = vec.cbegin(); + } + if (it == vec.cend()) { + throw LinqEndException(); + } + return *(it++); + } + ); + } + + Linq, typename std::vector::const_iterator, bool>, T> orderBy() const + { + return orderBy([](T value) { return value; }); + } + + template::const_reverse_iterator> + Linq, _TIter, bool>, T> reverse() const + { + return Linq, _TIter, bool>, T>( + std::make_tuple(toStdList(), _TIter(), false), + [](std::tuple, _TIter, bool> &tuple) { + std::list &list = std::get<0>(tuple); + _TIter &it = std::get<1>(tuple); + bool &flag = std::get<2>(tuple); + + if (!flag) { + flag = true; + it = list.crbegin(); + } + if (it == list.crend()) { + throw LinqEndException(); + } + return *(it++); + } + ); + } + + // Aggregators + + template + TRet aggregate(TRet start, std::function accumulate) const + { + Linq linq = *this; + try { + while (true) { + start = accumulate(start, linq.next()); + } + } + catch (LinqEndException &) {} + return start; + } + + template::type> + _TRet sum(F transform) const + { + return aggregate<_TRet>(_TRet(), [transform](_TRet accumulator, T value) { + return accumulator + transform(value); + }); + } + + template + TRet sum() const + { + return sum([](T value) { return TRet(value); }); + } + + template::type> + _TRet avg(F transform) const + { + int count = 0; + _TRet res = sum([transform, &count](T value) { + count++; + return transform(value); + }); + return res / count; + } + + template + TRet avg() const + { + return avg([](T value) { return TRet(value); }); + } + + int count() const + { + int index = 0; + for_each([&index](T /*a*/) { index++; }); + return index; + } + + int count(std::function predicate) const + { + return where(predicate).count(); + } + + int count(const T &item) const + { + return count([item](T value) { return item == value; }); + } + + // Bool aggregators + + bool any(std::function predicate) const + { + Linq linq = *this; + try { + while (true) { + if (predicate(linq.next())) + return true; + } + } + catch (LinqEndException &) {} + return false; + } + + bool any() const + { + return any([](T value) { return static_cast(value); }); + } + + bool all(std::function predicate) const + { + return !any([predicate](T value) { return !predicate(value); }); + } + + bool all() const + { + return all([](T value) { return static_cast(value); }); + } + + bool contains(const T &item) const + { + return any([&item](T value) { return value == item; }); + } + + // Election aggregators + + T elect(std::function accumulate) const + { + T result; + for_each_i([accumulate, &result](T value, int i) { + if (i == 0) { + result = value; + } else { + result = accumulate(result, value); + } + }); + return result; + } + + template + T max(F transform) const + { + return elect([transform](const T &a, const T &b) { + return (transform(a) < transform(b)) ? b : a; + }); + } + + T max() const + { + return max([](T value) { return value; }); + } + + template + T min(F transform) const + { + return elect([transform](const T &a, const T &b) { + return (transform(a) < transform(b)) ? a : b; + }); + } + + T min() const + { + return min([](T value) { return value; }); + } + + // Single object returners + + T elementAt(int index) const + { + return skip(index).next(); + } + + T first(std::function predicate) const + { + return where(predicate).next(); + } + + T first() const + { + return Linq(*this).next(); + } + + T firstOrDefault(std::function predicate, T const& defaultValue = T()) const + { + try { + return where(predicate).next(); + } + catch (LinqEndException &) {} + return defaultValue; + } + + T firstOrDefault(T const& defaultValue = T()) const + { + try { + return Linq(*this).next(); + } + catch (LinqEndException &) {} + return defaultValue; + } + + T last(std::function predicate) const + { + T res; + int index = -1; + where(predicate).for_each_i([&res, &index](T value, int i) { + res = value; + index = i; + }); + + if (index == -1) { + throw LinqEndException(); + } + return res; + } + + T last() const + { + return last([](T /*value*/) { return true; }); + } + + T lastOrDefault(std::function predicate, T const& defaultValue = T()) const + { + T res = defaultValue; + where(predicate).for_each([&res](T value) { + res = value; + }); + return res; + } + + T lastOrDefault(T const& defaultValue = T()) const + { + return lastOrDefault([](T /*value*/) { return true; }, defaultValue); + } + + // Export to containers + + std::vector toStdVector() const + { + std::vector items; + for_each([&items](T value) { + items.push_back(value); + }); + return items; + } + + std::list toStdList() const + { + std::list items; + for_each([&items](T value) { + items.push_back(value); + }); + return items; + } + + std::deque toStdDeque() const + { + std::deque items; + for_each([&items](T value) { + items.push_back(value); + }); + return items; + } + + std::set toStdSet() const + { + std::set items; + for_each([&items](T value) { + items.insert(value); + }); + return items; + } + + std::unordered_set toStdUnorderedSet() const + { + std::unordered_set items; + for_each([&items](T value) { + items.insert(value); + }); + return items; + } + + // Bits and bytes + + Linq, BytesDirection, T, int>, int> bytes(BytesDirection direction = BytesFirstToLast) const + { + return Linq, BytesDirection, T, int>, int>( + std::make_tuple(*this, direction, T(), sizeof(T)), + [](std::tuple, BytesDirection, T, int> &tuple) { + Linq &linq = std::get<0>(tuple); + BytesDirection &bytesDirection = std::get<1>(tuple); + T &value = std::get<2>(tuple); + int &index = std::get<3>(tuple); + + if (index == sizeof(T)) { + value = linq.next(); + index = 0; + } + + unsigned char *ptr = reinterpret_cast(&value); + + int byteIndex = index; + if (bytesDirection == BytesLastToFirst) { + byteIndex = sizeof(T) - 1 - byteIndex; + } + + index++; + return ptr[byteIndex]; + } + ); + } + + template + Linq, BytesDirection, int>, TRet> unbytes(BytesDirection direction = BytesFirstToLast) const + { + return Linq, BytesDirection, int>, TRet>( + std::make_tuple(*this, direction, 0), + [](std::tuple, BytesDirection, int> &tuple) { + Linq &linq = std::get<0>(tuple); + BytesDirection &bytesDirection = std::get<1>(tuple); + int &index = std::get<2>(tuple); + + TRet value; + unsigned char *ptr = reinterpret_cast(&value); + + for (int i = 0; i < sizeof(TRet); i++) { + int byteIndex = i; + if (bytesDirection == BytesLastToFirst) { + byteIndex = sizeof(TRet) - 1 - byteIndex; + } + + ptr[byteIndex] = linq.next(); + } + + return value; + } + ); + } + + Linq, BytesDirection, BitsDirection, T, int>, int> bits(BitsDirection bitsDir = BitsHighToLow, BytesDirection bytesDir = BytesFirstToLast) const + { + return Linq, BytesDirection, BitsDirection, T, int>, int>( + std::make_tuple(*this, bytesDir, bitsDir, T(), sizeof(T) * CHAR_BIT), + [](std::tuple, BytesDirection, BitsDirection, T, int> &tuple) { + Linq &linq = std::get<0>(tuple); + BytesDirection &bytesDirection = std::get<1>(tuple); + BitsDirection &bitsDirection = std::get<2>(tuple); + T &value = std::get<3>(tuple); + int &index = std::get<4>(tuple); + + if (index == sizeof(T) * CHAR_BIT) { + value = linq.next(); + index = 0; + } + + unsigned char *ptr = reinterpret_cast(&value); + + int byteIndex = index / CHAR_BIT; + if (bytesDirection == BytesLastToFirst) { + byteIndex = sizeof(T) - 1 - byteIndex; + } + + int bitIndex = index % CHAR_BIT; + if (bitsDirection == BitsHighToLow) { + bitIndex = CHAR_BIT - 1 - bitIndex; + } + + index++; + return (ptr[byteIndex] >> bitIndex) & 1; + } + ); + } + + template + Linq, BytesDirection, BitsDirection, int>, TRet> unbits(BitsDirection bitsDir = BitsHighToLow, BytesDirection bytesDir = BytesFirstToLast) const + { + return Linq, BytesDirection, BitsDirection, int>, TRet>( + std::make_tuple(*this, bytesDir, bitsDir, 0), + [](std::tuple, BytesDirection, BitsDirection, int> &tuple) { + Linq &linq = std::get<0>(tuple); + BytesDirection &bytesDirection = std::get<1>(tuple); + BitsDirection &bitsDirection = std::get<2>(tuple); + int &index = std::get<3>(tuple); + + TRet value = TRet(); + unsigned char *ptr = reinterpret_cast(&value); + + for (int i = 0; i < sizeof(TRet) * CHAR_BIT; i++) { + int byteIndex = i / CHAR_BIT; + if (bytesDirection == BytesLastToFirst) { + byteIndex = sizeof(TRet) - 1 - byteIndex; + } + + int bitIndex = i % CHAR_BIT; + if (bitsDirection == BitsHighToLow) { + bitIndex = CHAR_BIT - 1 - bitIndex; + } + + ptr[byteIndex] &= ~(1 << bitIndex); + ptr[byteIndex] |= bool(linq.next()) << bitIndex; + } + + return value; + } + ); + } + }; + + template + std::ostream &operator<<(std::ostream &stream, Linq linq) + { + try { + while (true) { + stream << linq.next() << ' '; + } + } + catch (LinqEndException &) {} + return stream; + } + + //////////////////////////////////////////////////////////////// + // Linq Creators + //////////////////////////////////////////////////////////////// + + template + Linq, typename std::iterator_traits::value_type> from(const T & begin, const T & end) + { + return Linq, typename std::iterator_traits::value_type>( + std::make_pair(begin, end), + [](std::pair &pair) { + if (pair.first == pair.second) { + throw LinqEndException(); + } + return *(pair.first++); + } + ); + } + + template + Linq, typename std::iterator_traits::value_type> from(const T & it, int n) + { + return from(it, it + n); + } + + template + Linq, T> from(T (&array)[N]) + { + return from((const T *)(&array), (const T *)(&array) + N); + } + + template class TV, typename TT> + auto from(const TV & container) + -> decltype(from(container.cbegin(), container.cend())) + { + return from(container.cbegin(), container.cend()); + } + + // std::list, std::vector, std::dequeue + template class TV, typename TT, typename TU> + auto from(const TV & container) + -> decltype(from(container.cbegin(), container.cend())) + { + return from(container.cbegin(), container.cend()); + } + + // std::set + template class TV, typename TT, typename TS, typename TU> + auto from(const TV & container) + -> decltype(from(container.cbegin(), container.cend())) + { + return from(container.cbegin(), container.cend()); + } + + // std::map + template class TV, typename TK, typename TT, typename TS, typename TU> + auto from(const TV & container) + -> decltype(from(container.cbegin(), container.cend())) + { + return from(container.cbegin(), container.cend()); + } + + // std::array + template class TV, typename TT, size_t TL> + auto from(const TV & container) + -> decltype(from(container.cbegin(), container.cend())) + { + return from(container.cbegin(), container.cend()); + } + + template + Linq, T> repeat(const T & value, int count) { + return Linq, T>( + std::make_pair(value, count), + [](std::pair &pair) { + if (pair.second > 0) { + pair.second--; + return pair.first; + } + throw LinqEndException(); + } + ); + } + + template + Linq, T> range(const T & start, const T & end, const T & step) { + return Linq, T>( + std::make_tuple(start, end, step), + [](std::tuple &tuple) { + T &start = std::get<0>(tuple); + T &end = std::get<1>(tuple); + T &step = std::get<2>(tuple); + + T value = start; + if (value < end) { + start += step; + return value; + } + throw LinqEndException(); + } + ); + } +} \ No newline at end of file diff --git a/src/librssguard/core/messagesmodel.cpp b/src/librssguard/core/messagesmodel.cpp index 7c75b9948..1607146c6 100644 --- a/src/librssguard/core/messagesmodel.cpp +++ b/src/librssguard/core/messagesmodel.cpp @@ -214,6 +214,16 @@ Qt::ItemFlags MessagesModel::flags(const QModelIndex& index) const { return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemNeverHasChildren; } +QList MessagesModel::messagesAt(QList row_indices) const { + QList msgs; + + for (int idx : row_indices) { + msgs << messageAt(idx); + } + + return msgs; +} + QVariant MessagesModel::data(int row, int column, int role) const { return data(index(row, column), role); } diff --git a/src/librssguard/core/messagesmodel.h b/src/librssguard/core/messagesmodel.h index 176d19667..b7ef9149d 100644 --- a/src/librssguard/core/messagesmodel.h +++ b/src/librssguard/core/messagesmodel.h @@ -44,6 +44,8 @@ class MessagesModel : public QSqlQueryModel, public MessagesModelSqlLayer { Qt::ItemFlags flags(const QModelIndex& index) const; // Returns message at given index. + + QList messagesAt(QList row_indices) const; Message messageAt(int row_index) const; int messageId(int row_index) const; RootItem::Importance messageImportance(int row_index) const; diff --git a/src/librssguard/gui/dialogs/formabout.cpp b/src/librssguard/gui/dialogs/formabout.cpp index cb7fb9695..632f27573 100644 --- a/src/librssguard/gui/dialogs/formabout.cpp +++ b/src/librssguard/gui/dialogs/formabout.cpp @@ -68,6 +68,13 @@ void FormAbout::loadLicenseAndInformation() { m_ui.m_txtLicenseBsd->setText(tr("License not found.")); } + try { + m_ui.m_txtLicenseMit->setText(IOFactory::readFile(APP_INFO_PATH + QL1S("/COPYING_MIT"))); + } + catch (...) { + m_ui.m_txtLicenseMit->setText(tr("License not found.")); + } + // Set other informative texts. m_ui.m_lblDesc->setText(tr("%8
" "Version: %1 (built on %2/%3)
" "Revision: %4
" "Build date: %5
" "Qt: %6 (compiled against %7)
").arg( diff --git a/src/librssguard/gui/dialogs/formabout.ui b/src/librssguard/gui/dialogs/formabout.ui index 84959f6dd..dba81fca3 100644 --- a/src/librssguard/gui/dialogs/formabout.ui +++ b/src/librssguard/gui/dialogs/formabout.ui @@ -160,7 +160,7 @@ p, li { white-space: pre-wrap; } 0 0 685 - 184 + 157 @@ -235,8 +235,8 @@ p, li { white-space: pre-wrap; } 0 0 - 98 - 69 + 685 + 157 @@ -288,6 +288,68 @@ p, li { white-space: pre-wrap; } <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'DejaVu Sans Mono'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;"><br /></p></body></html> + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + true + + + + + + + + MIT License (applies to boolinq source code) + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + DejaVu Sans Mono + + + + + + + QFrame::NoFrame + + + Qt::ScrollBarAlwaysOff + + + QTextEdit::AutoNone + + + false + + + QTextEdit::WidgetWidth + + + true + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'DejaVu Sans Mono'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;"><br /></p></body></html> diff --git a/src/librssguard/gui/dialogs/formmain.cpp b/src/librssguard/gui/dialogs/formmain.cpp index ebd6ae5bc..1f30788b5 100755 --- a/src/librssguard/gui/dialogs/formmain.cpp +++ b/src/librssguard/gui/dialogs/formmain.cpp @@ -312,7 +312,7 @@ void FormMain::updateRecycleBinMenu() { no_action->setEnabled(false); root_menu->addAction(no_action); } - else if ((context_menu = bin->contextMenu()).isEmpty()) { + else if ((context_menu = bin->contextMenuFeedsList()).isEmpty()) { QAction* no_action = new QAction(qApp->icons()->fromTheme(QSL("dialog-error")), tr("No actions possible"), m_ui->m_menuRecycleBin); diff --git a/src/librssguard/gui/feedsview.cpp b/src/librssguard/gui/feedsview.cpp index 9fcbc0f82..343ee9511 100755 --- a/src/librssguard/gui/feedsview.cpp +++ b/src/librssguard/gui/feedsview.cpp @@ -430,7 +430,7 @@ QMenu* FeedsView::initializeContextMenuBin(RootItem* clicked_item) { m_contextMenuBin->clear(); } - QList specific_actions = clicked_item->contextMenu(); + QList specific_actions = clicked_item->contextMenuFeedsList(); m_contextMenuBin->addActions(QList() << qApp->mainForm()->m_ui->m_actionViewSelectedItemsNewspaperMode << @@ -453,7 +453,7 @@ QMenu* FeedsView::initializeContextMenuService(RootItem* clicked_item) { m_contextMenuService->clear(); } - QList specific_actions = clicked_item->contextMenu(); + QList specific_actions = clicked_item->contextMenuFeedsList(); m_contextMenuService->addActions(QList() << qApp->mainForm()->m_ui->m_actionUpdateSelectedItems << @@ -511,7 +511,7 @@ QMenu* FeedsView::initializeContextMenuCategories(RootItem* clicked_item) { m_contextMenuCategories->clear(); } - QList specific_actions = clicked_item->contextMenu(); + QList specific_actions = clicked_item->contextMenuFeedsList(); m_contextMenuCategories->addActions(QList() << qApp->mainForm()->m_ui->m_actionUpdateSelectedItems << @@ -538,7 +538,7 @@ QMenu* FeedsView::initializeContextMenuFeeds(RootItem* clicked_item) { m_contextMenuFeeds->clear(); } - QList specific_actions = clicked_item->contextMenu(); + QList specific_actions = clicked_item->contextMenuFeedsList(); m_contextMenuFeeds->addActions(QList() << qApp->mainForm()->m_ui->m_actionUpdateSelectedItems << @@ -565,7 +565,7 @@ QMenu* FeedsView::initializeContextMenuImportant(RootItem* clicked_item) { m_contextMenuImportant->clear(); } - QList specific_actions = clicked_item->contextMenu(); + QList specific_actions = clicked_item->contextMenuFeedsList(); m_contextMenuImportant->addActions(QList() << qApp->mainForm()->m_ui->m_actionViewSelectedItemsNewspaperMode << @@ -598,7 +598,7 @@ QMenu* FeedsView::initializeContextMenuOtherItem(RootItem* clicked_item) { m_contextMenuOtherItems->clear(); } - QList specific_actions = clicked_item->contextMenu(); + QList specific_actions = clicked_item->contextMenuFeedsList(); if (!specific_actions.isEmpty()) { m_contextMenuOtherItems->addSeparator(); diff --git a/src/librssguard/gui/messagesview.cpp b/src/librssguard/gui/messagesview.cpp index 99febc4e0..ff789aaec 100644 --- a/src/librssguard/gui/messagesview.cpp +++ b/src/librssguard/gui/messagesview.cpp @@ -2,6 +2,7 @@ #include "gui/messagesview.h" +#include "3rd-party/boolinq/boolinq.h" #include "core/messagesmodel.h" #include "core/messagesproxymodel.h" #include "gui/dialogs/formmain.h" @@ -13,6 +14,7 @@ #include "miscellaneous/settings.h" #include "network-web/networkfactory.h" #include "network-web/webfactory.h" +#include "services/abstract/serviceroot.h" #include #include @@ -213,11 +215,32 @@ void MessagesView::initializeContextMenu() { m_contextMenu->addMenu(menu); m_contextMenu->addActions( - QList() << qApp->mainForm()->m_ui->m_actionSendMessageViaEmail << qApp->mainForm()->m_ui->m_actionOpenSelectedSourceArticlesExternally << qApp->mainForm()->m_ui->m_actionOpenSelectedMessagesInternally << qApp->mainForm()->m_ui->m_actionMarkSelectedMessagesAsRead << qApp->mainForm()->m_ui->m_actionMarkSelectedMessagesAsUnread << qApp->mainForm()->m_ui->m_actionSwitchImportanceOfSelectedMessages << - qApp->mainForm()->m_ui->m_actionDeleteSelectedMessages); + QList() + << qApp->mainForm()->m_ui->m_actionSendMessageViaEmail + << qApp->mainForm()->m_ui->m_actionOpenSelectedSourceArticlesExternally + << qApp->mainForm()->m_ui->m_actionOpenSelectedMessagesInternally + << qApp->mainForm()->m_ui->m_actionMarkSelectedMessagesAsRead + << qApp->mainForm()->m_ui->m_actionMarkSelectedMessagesAsUnread + << qApp->mainForm()->m_ui->m_actionSwitchImportanceOfSelectedMessages + << qApp->mainForm()->m_ui->m_actionDeleteSelectedMessages); - if (m_sourceModel->loadedItem() != nullptr && m_sourceModel->loadedItem()->kind() == RootItemKind::Bin) { - m_contextMenu->addAction(qApp->mainForm()->m_ui->m_actionRestoreSelectedMessages); + if (m_sourceModel->loadedItem() != nullptr) { + if (m_sourceModel->loadedItem()->kind() == RootItemKind::Bin) { + m_contextMenu->addAction(qApp->mainForm()->m_ui->m_actionRestoreSelectedMessages); + } + + QModelIndexList selected_indexes = selectionModel()->selectedRows(); + const QModelIndexList mapped_indexes = m_proxyModel->mapListToSource(selected_indexes); + auto rows = boolinq::from(mapped_indexes).select([](const QModelIndex& idx) { + return idx.row(); + }).toStdList(); + auto messages = m_sourceModel->messagesAt(QList::fromStdList(rows)); + auto extra_context_menu = m_sourceModel->loadedItem()->getParentServiceRoot()->contextMenuMessagesList(messages); + + if (!extra_context_menu.isEmpty()) { + m_contextMenu->addSeparator(); + m_contextMenu->addActions(extra_context_menu); + } } } diff --git a/src/librssguard/gui/messagesview.h b/src/librssguard/gui/messagesview.h index 5f948ee22..487019da1 100644 --- a/src/librssguard/gui/messagesview.h +++ b/src/librssguard/gui/messagesview.h @@ -19,14 +19,8 @@ class MessagesView : public QTreeView { explicit MessagesView(QWidget* parent = nullptr); virtual ~MessagesView(); - // Model accessors. - inline MessagesProxyModel* model() const { - return m_proxyModel; - } - - inline MessagesModel* sourceModel() const { - return m_sourceModel; - } + MessagesProxyModel* model() const; + MessagesModel* sourceModel() const; void reloadFontSettings(); @@ -110,4 +104,12 @@ class MessagesView : public QTreeView { bool m_columnsAdjusted; }; +inline MessagesProxyModel* MessagesView::model() const { + return m_proxyModel; +} + +inline MessagesModel* MessagesView::sourceModel() const { + return m_sourceModel; +} + #endif // MESSAGESVIEW_H diff --git a/src/librssguard/services/abstract/recyclebin.cpp b/src/librssguard/services/abstract/recyclebin.cpp index 525ef2529..5268d2f7e 100644 --- a/src/librssguard/services/abstract/recyclebin.cpp +++ b/src/librssguard/services/abstract/recyclebin.cpp @@ -46,7 +46,7 @@ void RecycleBin::updateCounts(bool update_total_count) { } } -QList RecycleBin::contextMenu() { +QList RecycleBin::contextMenuFeedsList() { if (m_contextMenu.isEmpty()) { QAction* restore_action = new QAction(qApp->icons()->fromTheme(QSL("view-refresh")), tr("Restore recycle bin"), diff --git a/src/librssguard/services/abstract/recyclebin.h b/src/librssguard/services/abstract/recyclebin.h index 78c1014fb..b1b42b8f8 100644 --- a/src/librssguard/services/abstract/recyclebin.h +++ b/src/librssguard/services/abstract/recyclebin.h @@ -14,7 +14,7 @@ class RecycleBin : public RootItem { QString additionalTooltip() const; - QList contextMenu(); + QList contextMenuFeedsList(); QList undeletedMessages() const; bool markAsReadUnread(ReadStatus status); diff --git a/src/librssguard/services/abstract/rootitem.cpp b/src/librssguard/services/abstract/rootitem.cpp index c2c29450f..b6ad95294 100644 --- a/src/librssguard/services/abstract/rootitem.cpp +++ b/src/librssguard/services/abstract/rootitem.cpp @@ -44,7 +44,7 @@ QString RootItem::additionalTooltip() const { return QString(); } -QList RootItem::contextMenu() { +QList RootItem::contextMenuFeedsList() { return QList(); } diff --git a/src/librssguard/services/abstract/rootitem.h b/src/librssguard/services/abstract/rootitem.h index b8e7bc64a..1020c097c 100644 --- a/src/librssguard/services/abstract/rootitem.h +++ b/src/librssguard/services/abstract/rootitem.h @@ -63,7 +63,7 @@ class RSSGUARD_DLLSPEC RootItem : public QObject { // Returns list of specific actions which can be done with the item. // Do not include general actions here like actions: Mark as read, Update, ... // NOTE: Ownership of returned actions is not switched to caller, free them when needed. - virtual QList contextMenu(); + virtual QList contextMenuFeedsList(); // Can properties of this item be edited? virtual bool canBeEdited() const; diff --git a/src/librssguard/services/abstract/serviceroot.cpp b/src/librssguard/services/abstract/serviceroot.cpp index b2938252c..61c52919e 100644 --- a/src/librssguard/services/abstract/serviceroot.cpp +++ b/src/librssguard/services/abstract/serviceroot.cpp @@ -68,11 +68,11 @@ bool ServiceRoot::downloadAttachmentOnMyOwn(const QUrl& url) const { return false; } -QList ServiceRoot::contextMenu() { +QList ServiceRoot::contextMenuFeedsList() { return serviceMenu(); } -QList ServiceRoot::contextMenuForMessages(const QList& messages) { +QList ServiceRoot::contextMenuMessagesList(const QList& messages) { Q_UNUSED(messages) return {}; } diff --git a/src/librssguard/services/abstract/serviceroot.h b/src/librssguard/services/abstract/serviceroot.h index 3cf8d5f83..37328ce4c 100644 --- a/src/librssguard/services/abstract/serviceroot.h +++ b/src/librssguard/services/abstract/serviceroot.h @@ -53,9 +53,11 @@ class ServiceRoot : public RootItem { // NOTE: Caller does NOT take ownership of created menu! virtual QList addItemMenu(); - // Returns actions to display as context menu. - virtual QList contextMenu(); - virtual QList contextMenuForMessages(const QList& messages); + // NOTE: Caller does NOT take ownership of created menu! + virtual QList contextMenuFeedsList(); + + // NOTE: Caller does NOT take ownership of created menu! + virtual QList contextMenuMessagesList(const QList& messages); // Returns list of specific actions to be shown in main window menu // bar in sections "Services -> 'this service'". diff --git a/src/librssguard/services/gmail/gmailserviceroot.cpp b/src/librssguard/services/gmail/gmailserviceroot.cpp index 4a8785704..64eebcbd1 100644 --- a/src/librssguard/services/gmail/gmailserviceroot.cpp +++ b/src/librssguard/services/gmail/gmailserviceroot.cpp @@ -18,7 +18,8 @@ #include -GmailServiceRoot::GmailServiceRoot(GmailNetworkFactory* network, RootItem* parent) : ServiceRoot(parent), m_network(network) { +GmailServiceRoot::GmailServiceRoot(GmailNetworkFactory* network, RootItem* parent) + : ServiceRoot(parent), m_network(network), m_actionReply(nullptr) { if (network == nullptr) { m_network = new GmailNetworkFactory(this); } @@ -36,6 +37,10 @@ void GmailServiceRoot::updateTitle() { setTitle(m_network->username() + QSL(" (Gmail)")); } +void GmailServiceRoot::replyToEmail() { + FormAddEditEmail(this, qApp->mainFormWidget()).execForReply(&m_replyToMessage); +} + RootItem* GmailServiceRoot::obtainNewTreeForSyncIn() const { auto* root = new RootItem(); GmailFeed* inbox = new GmailFeed(tr("Inbox"), QSL(GMAIL_SYSTEM_LABEL_INBOX), qApp->icons()->fromTheme(QSL("mail-inbox")), root); @@ -128,6 +133,22 @@ bool GmailServiceRoot::downloadAttachmentOnMyOwn(const QUrl& url) const { } } +QList GmailServiceRoot::contextMenuMessagesList(const QList& messages) { + if (messages.size() == 1) { + if (m_actionReply == nullptr) { + m_actionReply = new QAction(qApp->icons()->fromTheme(QSL("mail-reply-sender")), tr("Reply"), this); + + m_replyToMessage = messages.at(0); + connect(m_actionReply, &QAction::triggered, this, &GmailServiceRoot::replyToEmail); + } + + return { m_actionReply }; + } + else { + return {}; + } +} + QList GmailServiceRoot::serviceMenu() { if (m_serviceMenu.isEmpty()) { ServiceRoot::serviceMenu(); diff --git a/src/librssguard/services/gmail/gmailserviceroot.h b/src/librssguard/services/gmail/gmailserviceroot.h index 035d618ea..0227b1887 100644 --- a/src/librssguard/services/gmail/gmailserviceroot.h +++ b/src/librssguard/services/gmail/gmailserviceroot.h @@ -22,6 +22,7 @@ class GmailServiceRoot : public ServiceRoot, public CacheForServiceRoot { void setNetwork(GmailNetworkFactory* network); GmailNetworkFactory* network() const; + QList contextMenuMessagesList(const QList& messages); QList serviceMenu(); bool isSyncable() const; bool canBeEdited() const; @@ -41,6 +42,9 @@ class GmailServiceRoot : public ServiceRoot, public CacheForServiceRoot { public slots: void updateTitle(); + private slots: + void replyToEmail(); + protected: RootItem* obtainNewTreeForSyncIn() const; @@ -50,6 +54,8 @@ class GmailServiceRoot : public ServiceRoot, public CacheForServiceRoot { private: GmailNetworkFactory* m_network; + QAction* m_actionReply; + Message m_replyToMessage; }; inline void GmailServiceRoot::setNetwork(GmailNetworkFactory* network) { diff --git a/src/librssguard/services/gmail/gui/formaddeditemail.cpp b/src/librssguard/services/gmail/gui/formaddeditemail.cpp index f9a60b02e..d180fe3fe 100644 --- a/src/librssguard/services/gmail/gui/formaddeditemail.cpp +++ b/src/librssguard/services/gmail/gui/formaddeditemail.cpp @@ -112,15 +112,8 @@ void FormAddEditEmail::onOkClicked() { msg.set_plain(m_ui.m_txtMessage->toPlainText().toStdString()); msg.set_header("Content-Type", "text/plain; charset=utf-8"); - if (m_originalMessage == nullptr) { - // Send completely new message. - } - else { - // TODO: Reply to existing message. - } - try { - m_root->network()->sendEmail(msg); + m_root->network()->sendEmail(msg, m_originalMessage); accept(); } catch (const ApplicationException& ex) { @@ -141,7 +134,9 @@ void FormAddEditEmail::addRecipientRow(const QString& recipient) { mail_rec->setPossibleRecipients(rec); } - catch (const ApplicationException& ex) {} + catch (const ApplicationException& ex) { + qWarning("Failed to get recipients: '%s'.", qPrintable(ex.message())); + } m_ui.m_layout->insertRow(m_ui.m_layout->count() - 5, mail_rec); } diff --git a/src/librssguard/services/gmail/network/gmailnetworkfactory.cpp b/src/librssguard/services/gmail/network/gmailnetworkfactory.cpp index 9951650b4..d1c917515 100644 --- a/src/librssguard/services/gmail/network/gmailnetworkfactory.cpp +++ b/src/librssguard/services/gmail/network/gmailnetworkfactory.cpp @@ -52,13 +52,31 @@ void GmailNetworkFactory::setBatchSize(int batch_size) { m_batchSize = batch_size; } -QString GmailNetworkFactory::sendEmail(const Mimesis::Message& msg) { +QString GmailNetworkFactory::sendEmail(Mimesis::Message msg, Message* reply_to_message) { QString bearer = m_oauth2->bearer().toLocal8Bit(); if (bearer.isEmpty()) { throw ApplicationException(tr("you aren't logged in")); } + if (reply_to_message != nullptr) { + // We need to obtain some extra information. + + auto metadata = getMessageMetadata(reply_to_message->m_customId, { + QSL("References"), + QSL("Message-ID") + }); + + /*if (metadata.contains(QSL("References"))) { + + }*/ + + if (metadata.contains(QSL("Message-ID"))) { + msg["References"] = metadata.value(QSL("Message-ID")).toString().toStdString(); + msg["In-Reply-To"] = metadata.value(QSL("Message-ID")).toString().toStdString(); + } + } + QString rfc_email = QString::fromStdString(msg.to_string()); QByteArray input_data = rfc_email.toUtf8(); QList> headers; @@ -501,6 +519,36 @@ QStringList GmailNetworkFactory::getAllRecipients() { } } +QVariantMap GmailNetworkFactory::getMessageMetadata(const QString& msg_id, const QStringList& metadata) { + QString bearer = m_oauth2->bearer(); + + if (bearer.isEmpty()) { + throw ApplicationException(tr("you are not logged in")); + } + + QList> headers; + QByteArray output; + int timeout = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)).toInt(); + + headers.append(QPair(QString(HTTP_HEADERS_AUTHORIZATION).toLocal8Bit(), + bearer.toLocal8Bit())); + + QString query = QString("%1/%2?format=metadata&metadataHeaders=%3").arg(GMAIL_API_MSGS_LIST, + msg_id, + metadata.join(QSL("&metadataHeaders="))); + NetworkResult res = NetworkFactory::performNetworkOperation(query, + timeout, + QByteArray(), + output, + QNetworkAccessManager::Operation::GetOperation, + headers); + + if (res.first == QNetworkReply::NetworkError::NoError) {} + else { + throw ApplicationException(tr("failed to get metadata")); + } +} + bool GmailNetworkFactory::obtainAndDecodeFullMessages(const QList& lite_messages, const QString& feed_id, QList& full_messages) { diff --git a/src/librssguard/services/gmail/network/gmailnetworkfactory.h b/src/librssguard/services/gmail/network/gmailnetworkfactory.h index f7297a048..a8568ace9 100644 --- a/src/librssguard/services/gmail/network/gmailnetworkfactory.h +++ b/src/librssguard/services/gmail/network/gmailnetworkfactory.h @@ -36,7 +36,7 @@ class GmailNetworkFactory : public QObject { void setBatchSize(int batch_size); // Sends e-mail, returns its ID. - QString sendEmail(const Mimesis::Message& msg); + QString sendEmail(Mimesis::Message msg, Message* reply_to_message = nullptr); // Returns all possible recipients. QStringList getAllRecipients(); @@ -53,6 +53,7 @@ class GmailNetworkFactory : public QObject { private: bool fillFullMessage(Message& msg, const QJsonObject& json, const QString& feed_id); + QVariantMap getMessageMetadata(const QString& msg_id, const QStringList& metadata); bool obtainAndDecodeFullMessages(const QList& lite_messages, const QString& feed_id, QList& full_messages); QList decodeLiteMessages(const QString& messages_json_data, const QString& stream_id, QString& next_page_token); diff --git a/src/librssguard/services/owncloud/gui/formeditowncloudaccount.cpp b/src/librssguard/services/owncloud/gui/formeditowncloudaccount.cpp index 8dca47766..97f82f823 100644 --- a/src/librssguard/services/owncloud/gui/formeditowncloudaccount.cpp +++ b/src/librssguard/services/owncloud/gui/formeditowncloudaccount.cpp @@ -107,7 +107,7 @@ void FormEditOwnCloudAccount::performTest() { if (!SystemFactory::isVersionEqualOrNewer(result.version(), OWNCLOUD_MIN_VERSION)) { m_ui->m_lblTestResult->setStatus(WidgetWithStatus::StatusType::Error, tr( - "Selected Nextcloud News server is running unsupported version (%1). At least version %2 is required.").arg( + "Selected Nextcloud News server is running unsupported version %1. At least version %2 is required.").arg( result.version(), OWNCLOUD_MIN_VERSION), tr("Selected Nextcloud News server is running unsupported version.")); diff --git a/src/librssguard/services/owncloud/network/owncloudnetworkfactory.cpp b/src/librssguard/services/owncloud/network/owncloudnetworkfactory.cpp index 8db4f756c..6a1cd3068 100644 --- a/src/librssguard/services/owncloud/network/owncloudnetworkfactory.cpp +++ b/src/librssguard/services/owncloud/network/owncloudnetworkfactory.cpp @@ -120,6 +120,8 @@ OwnCloudStatusResponse OwnCloudNetworkFactory::status() { headers); OwnCloudStatusResponse status_response(QString::fromUtf8(result_raw)); + qDebug().noquote().nospace() << "Raw status data is:" << result_raw; + if (network_reply.first != QNetworkReply::NoError) { qWarning("Nextcloud: Obtaining status info failed with error %d.", network_reply.first); } diff --git a/src/librssguard/services/standard/standardfeed.cpp b/src/librssguard/services/standard/standardfeed.cpp index c07ff2c19..70de02350 100644 --- a/src/librssguard/services/standard/standardfeed.cpp +++ b/src/librssguard/services/standard/standardfeed.cpp @@ -51,7 +51,7 @@ StandardFeed::~StandardFeed() { qDebug("Destroying Feed instance."); } -QList StandardFeed::contextMenu() { +QList StandardFeed::contextMenuFeedsList() { return serviceRoot()->getContextMenuForFeed(this); } diff --git a/src/librssguard/services/standard/standardfeed.h b/src/librssguard/services/standard/standardfeed.h index af5f066cd..186d29b86 100644 --- a/src/librssguard/services/standard/standardfeed.h +++ b/src/librssguard/services/standard/standardfeed.h @@ -35,7 +35,7 @@ class StandardFeed : public Feed { StandardServiceRoot* serviceRoot() const; - QList contextMenu(); + QList contextMenuFeedsList(); QString additionalTooltip() const;