Merge branch 'master' of github.com:martinrotter/rssguard
This commit is contained in:
commit
b89fda7b6b
78 changed files with 1693 additions and 575 deletions
|
@ -37,6 +37,7 @@
|
||||||
<file>./graphics/Faenza/actions/64/mail-mark-read.png</file>
|
<file>./graphics/Faenza/actions/64/mail-mark-read.png</file>
|
||||||
<file>./graphics/Faenza/actions/64/mail-mark-unread.png</file>
|
<file>./graphics/Faenza/actions/64/mail-mark-unread.png</file>
|
||||||
<file>./graphics/Faenza/actions/64/mail-message-new.png</file>
|
<file>./graphics/Faenza/actions/64/mail-message-new.png</file>
|
||||||
|
<file>./graphics/Faenza/actions/64/mail-reply-sender.png</file>
|
||||||
<file>./graphics/Faenza/actions/64/mail-send.png</file>
|
<file>./graphics/Faenza/actions/64/mail-send.png</file>
|
||||||
<file>./graphics/Faenza/actions/64/mail-sent.png</file>
|
<file>./graphics/Faenza/actions/64/mail-sent.png</file>
|
||||||
<file>./graphics/Faenza/actions/64/media-playback-start.png</file>
|
<file>./graphics/Faenza/actions/64/media-playback-start.png</file>
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
<qresource prefix="/">
|
<qresource prefix="/">
|
||||||
<file>text/CHANGELOG</file>
|
<file>text/CHANGELOG</file>
|
||||||
<file>text/COPYING_BSD</file>
|
<file>text/COPYING_BSD</file>
|
||||||
|
<file>text/COPYING_MIT</file>
|
||||||
<file>text/COPYING_GNU_GPL</file>
|
<file>text/COPYING_GNU_GPL</file>
|
||||||
<file>text/COPYING_GNU_GPL_HTML</file>
|
<file>text/COPYING_GNU_GPL_HTML</file>
|
||||||
|
|
||||||
|
|
19
resources/text/COPYING_MIT
Executable file
19
resources/text/COPYING_MIT
Executable file
|
@ -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.
|
883
src/librssguard/3rd-party/boolinq/boolinq.h
vendored
Executable file
883
src/librssguard/3rd-party/boolinq/boolinq.h
vendored
Executable file
|
@ -0,0 +1,883 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <iostream>
|
||||||
|
#include <iterator>
|
||||||
|
#include <vector>
|
||||||
|
#include <deque>
|
||||||
|
#include <list>
|
||||||
|
#include <set>
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
namespace boolinq {
|
||||||
|
|
||||||
|
struct LinqEndException {};
|
||||||
|
|
||||||
|
enum BytesDirection {
|
||||||
|
BytesFirstToLast,
|
||||||
|
BytesLastToFirst,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum BitsDirection {
|
||||||
|
BitsHighToLow,
|
||||||
|
BitsLowToHigh,
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename S, typename T>
|
||||||
|
class Linq {
|
||||||
|
std::function<T(S &)> nextFunc;
|
||||||
|
S storage;
|
||||||
|
|
||||||
|
public:
|
||||||
|
typedef T value_type;
|
||||||
|
|
||||||
|
Linq() : nextFunc(), storage()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Linq(S storage, std::function<T(S &)> nextFunc) : nextFunc(nextFunc), storage(storage)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
T next()
|
||||||
|
{
|
||||||
|
return nextFunc(storage);
|
||||||
|
}
|
||||||
|
|
||||||
|
void for_each_i(std::function<void(T, int)> apply) const
|
||||||
|
{
|
||||||
|
Linq<S, T> linq = *this;
|
||||||
|
try {
|
||||||
|
for (int i = 0; ; i++) {
|
||||||
|
apply(linq.next(), i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (LinqEndException &) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
void for_each(std::function<void(T)> apply) const
|
||||||
|
{
|
||||||
|
return for_each_i([apply](T value, int) { return apply(value); });
|
||||||
|
}
|
||||||
|
|
||||||
|
Linq<std::tuple<Linq<S, T>, int>, T> where_i(std::function<bool(T, int)> filter) const
|
||||||
|
{
|
||||||
|
return Linq<std::tuple<Linq<S, T>, int>, T>(
|
||||||
|
std::make_tuple(*this, 0),
|
||||||
|
[filter](std::tuple<Linq<S, T>, int> &tuple) {
|
||||||
|
Linq<S, T> &linq = std::get<0>(tuple);
|
||||||
|
int &index = std::get<1>(tuple);
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
T ret = linq.next();
|
||||||
|
if (filter(ret, index++)) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Linq<std::tuple<Linq<S, T>, int>, T> where(std::function<bool(T)> filter) const
|
||||||
|
{
|
||||||
|
return where_i([filter](T value, int) { return filter(value); });
|
||||||
|
}
|
||||||
|
|
||||||
|
Linq<std::tuple<Linq<S, T>, int>, T> take(int count) const
|
||||||
|
{
|
||||||
|
return where_i([count](T /*value*/, int i) {
|
||||||
|
if (i == count) {
|
||||||
|
throw LinqEndException();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Linq<std::tuple<Linq<S, T>, int>, T> takeWhile_i(std::function<bool(T, int)> predicate) const
|
||||||
|
{
|
||||||
|
return where_i([predicate](T value, int i) {
|
||||||
|
if (!predicate(value, i)) {
|
||||||
|
throw LinqEndException();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Linq<std::tuple<Linq<S, T>, int>, T> takeWhile(std::function<bool(T)> predicate) const
|
||||||
|
{
|
||||||
|
return takeWhile_i([predicate](T value, int /*i*/) { return predicate(value); });
|
||||||
|
}
|
||||||
|
|
||||||
|
Linq<std::tuple<Linq<S, T>, int>, T> skip(int count) const
|
||||||
|
{
|
||||||
|
return where_i([count](T value, int i) { return i >= count; });
|
||||||
|
}
|
||||||
|
|
||||||
|
Linq<std::tuple<Linq<S, T>, int, bool>, T> skipWhile_i(std::function<bool(T, int)> predicate) const
|
||||||
|
{
|
||||||
|
return Linq<std::tuple<Linq<S, T>, int, bool>, T>(
|
||||||
|
std::make_tuple(*this, 0, false),
|
||||||
|
[predicate](std::tuple<Linq<S, T>, int, bool> &tuple) {
|
||||||
|
Linq<S, T> &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<std::tuple<Linq<S, T>, int, bool>, T> skipWhile(std::function<bool(T)> predicate) const
|
||||||
|
{
|
||||||
|
return skipWhile_i([predicate](T value, int /*i*/) { return predicate(value); });
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename ... Types>
|
||||||
|
Linq<std::tuple<Linq<S, T>, std::vector<T>, int>, T> append(Types ... newValues) const
|
||||||
|
{
|
||||||
|
return Linq<std::tuple<Linq<S, T>, std::vector<T>, int>, T>(
|
||||||
|
std::make_tuple(*this, std::vector<T>{ newValues... }, -1),
|
||||||
|
[](std::tuple<Linq<S, T>, std::vector<T>, int> &tuple) {
|
||||||
|
Linq<S, T> &linq = std::get<0>(tuple);
|
||||||
|
std::vector<T> &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<typename ... Types>
|
||||||
|
Linq<std::tuple<Linq<S, T>, std::vector<T>, int>, T> prepend(Types ... newValues) const
|
||||||
|
{
|
||||||
|
return Linq<std::tuple<Linq<S, T>, std::vector<T>, int>, T>(
|
||||||
|
std::make_tuple(*this, std::vector<T>{ newValues... }, 0),
|
||||||
|
[](std::tuple<Linq<S, T>, std::vector<T>, int> &tuple) {
|
||||||
|
Linq<S, T> &linq = std::get<0>(tuple);
|
||||||
|
std::vector<T> &values = std::get<1>(tuple);
|
||||||
|
int &index = std::get<2>(tuple);
|
||||||
|
|
||||||
|
if (index < values.size()) {
|
||||||
|
return values[index++];
|
||||||
|
}
|
||||||
|
return linq.next();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename F, typename _TRet = typename std::result_of<F(T, int)>::type>
|
||||||
|
Linq<std::tuple<Linq<S, T>, int>, _TRet> select_i(F apply) const
|
||||||
|
{
|
||||||
|
return Linq<std::tuple<Linq<S, T>, int>, _TRet>(
|
||||||
|
std::make_tuple(*this, 0),
|
||||||
|
[apply](std::tuple<Linq<S, T>, int> &tuple) {
|
||||||
|
Linq<S, T> &linq = std::get<0>(tuple);
|
||||||
|
int &index = std::get<1>(tuple);
|
||||||
|
|
||||||
|
return apply(linq.next(), index++);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename F, typename _TRet = typename std::result_of<F(T)>::type>
|
||||||
|
Linq<std::tuple<Linq<S, T>, int>, _TRet> select(F apply) const
|
||||||
|
{
|
||||||
|
return select_i([apply](T value, int /*index*/) { return apply(value); });
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename TRet>
|
||||||
|
Linq<std::tuple<Linq<S, T>, int>, TRet> cast() const
|
||||||
|
{
|
||||||
|
return select_i([](T value, int /*i*/) { return TRet(value); });
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename S2, typename T2>
|
||||||
|
Linq<std::tuple<Linq<S, T>, Linq<S2, T2>, bool>, T> concat(const Linq<S2, T2> & rhs) const
|
||||||
|
{
|
||||||
|
return Linq<std::tuple<Linq<S, T>, Linq<S2, T2>, bool>, T>(
|
||||||
|
std::make_tuple(*this, rhs, false),
|
||||||
|
[](std::tuple<Linq<S, T>, Linq<S2, T2>, bool> &tuple){
|
||||||
|
Linq<S, T> &first = std::get<0>(tuple);
|
||||||
|
Linq<S2, T2> &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<F(T, int)>::type,
|
||||||
|
typename _TRetVal = typename _TRet::value_type
|
||||||
|
>
|
||||||
|
Linq<std::tuple<Linq<S, T>, _TRet, int, bool>, _TRetVal> selectMany_i(F apply) const
|
||||||
|
{
|
||||||
|
return Linq<std::tuple<Linq<S, T>, _TRet, int, bool>, _TRetVal>(
|
||||||
|
std::make_tuple(*this, _TRet(), 0, true),
|
||||||
|
[apply](std::tuple<Linq<S, T>, _TRet, int, bool> &tuple) {
|
||||||
|
Linq<S, T> &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<F(T)>::type,
|
||||||
|
typename _TRetVal = typename _TRet::value_type
|
||||||
|
>
|
||||||
|
Linq<std::tuple<Linq<S, T>, _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<F(T)>::type,
|
||||||
|
typename _TValue = Linq<std::tuple<Linq<S, T>, int>, T> // where(predicate)
|
||||||
|
>
|
||||||
|
Linq<std::tuple<Linq<S, T>, Linq<S, T>, std::unordered_set<_TKey> >, std::pair<_TKey, _TValue> > groupBy(F apply) const
|
||||||
|
{
|
||||||
|
return Linq<std::tuple<Linq<S, T>, Linq<S, T>, std::unordered_set<_TKey> >, std::pair<_TKey, _TValue> >(
|
||||||
|
std::make_tuple(*this, *this, std::unordered_set<_TKey>()),
|
||||||
|
[apply](std::tuple<Linq<S, T>, Linq<S, T>, std::unordered_set<_TKey> > &tuple){
|
||||||
|
Linq<S, T> &linq = std::get<0>(tuple);
|
||||||
|
Linq<S, T> &linqCopy = std::get<1>(tuple);
|
||||||
|
std::unordered_set<_TKey> &set = std::get<2>(tuple);
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
_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;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename F, typename _TRet = typename std::result_of<F(T)>::type>
|
||||||
|
Linq<std::tuple<Linq<S, T>, std::unordered_set<_TRet> >, T> distinct(F transform) const
|
||||||
|
{
|
||||||
|
return Linq<std::tuple<Linq<S, T>, std::unordered_set<_TRet> >, T>(
|
||||||
|
std::make_tuple(*this, std::unordered_set<_TRet>()),
|
||||||
|
[transform](std::tuple<Linq<S, T>, std::unordered_set<_TRet> > &tuple) {
|
||||||
|
Linq<S, T> &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::tuple<Linq<S, T>, std::unordered_set<T> >, T> distinct() const
|
||||||
|
{
|
||||||
|
return distinct([](T value) { return value; });
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename F, typename _TIter = typename std::vector<T>::const_iterator>
|
||||||
|
Linq<std::tuple<std::vector<T>, _TIter, bool>, T> orderBy(F transform) const
|
||||||
|
{
|
||||||
|
std::vector<T> items = toStdVector();
|
||||||
|
std::sort(items.begin(), items.end(), [transform](const T &a, const T &b) {
|
||||||
|
return transform(a) < transform(b);
|
||||||
|
});
|
||||||
|
|
||||||
|
return Linq<std::tuple<std::vector<T>, _TIter, bool>, T>(
|
||||||
|
std::make_tuple(items, _TIter(), false),
|
||||||
|
[](std::tuple<std::vector<T>, _TIter, bool> &tuple) {
|
||||||
|
std::vector<T> &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<std::tuple<std::vector<T>, typename std::vector<T>::const_iterator, bool>, T> orderBy() const
|
||||||
|
{
|
||||||
|
return orderBy([](T value) { return value; });
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename _TIter = typename std::list<T>::const_reverse_iterator>
|
||||||
|
Linq<std::tuple<std::list<T>, _TIter, bool>, T> reverse() const
|
||||||
|
{
|
||||||
|
return Linq<std::tuple<std::list<T>, _TIter, bool>, T>(
|
||||||
|
std::make_tuple(toStdList(), _TIter(), false),
|
||||||
|
[](std::tuple<std::list<T>, _TIter, bool> &tuple) {
|
||||||
|
std::list<T> &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<typename TRet>
|
||||||
|
TRet aggregate(TRet start, std::function<TRet(TRet, T)> accumulate) const
|
||||||
|
{
|
||||||
|
Linq<S, T> linq = *this;
|
||||||
|
try {
|
||||||
|
while (true) {
|
||||||
|
start = accumulate(start, linq.next());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (LinqEndException &) {}
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename F, typename _TRet = typename std::result_of<F(T)>::type>
|
||||||
|
_TRet sum(F transform) const
|
||||||
|
{
|
||||||
|
return aggregate<_TRet>(_TRet(), [transform](_TRet accumulator, T value) {
|
||||||
|
return accumulator + transform(value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename TRet = T>
|
||||||
|
TRet sum() const
|
||||||
|
{
|
||||||
|
return sum([](T value) { return TRet(value); });
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename F, typename _TRet = typename std::result_of<F(T)>::type>
|
||||||
|
_TRet avg(F transform) const
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
_TRet res = sum([transform, &count](T value) {
|
||||||
|
count++;
|
||||||
|
return transform(value);
|
||||||
|
});
|
||||||
|
return res / count;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename TRet = T>
|
||||||
|
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<bool(T)> 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<bool(T)> predicate) const
|
||||||
|
{
|
||||||
|
Linq<S, T> 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<bool>(value); });
|
||||||
|
}
|
||||||
|
|
||||||
|
bool all(std::function<bool(T)> predicate) const
|
||||||
|
{
|
||||||
|
return !any([predicate](T value) { return !predicate(value); });
|
||||||
|
}
|
||||||
|
|
||||||
|
bool all() const
|
||||||
|
{
|
||||||
|
return all([](T value) { return static_cast<bool>(value); });
|
||||||
|
}
|
||||||
|
|
||||||
|
bool contains(const T &item) const
|
||||||
|
{
|
||||||
|
return any([&item](T value) { return value == item; });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Election aggregators
|
||||||
|
|
||||||
|
T elect(std::function<T(T, T)> 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<typename F>
|
||||||
|
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<typename F>
|
||||||
|
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<bool(T)> predicate) const
|
||||||
|
{
|
||||||
|
return where(predicate).next();
|
||||||
|
}
|
||||||
|
|
||||||
|
T first() const
|
||||||
|
{
|
||||||
|
return Linq<S, T>(*this).next();
|
||||||
|
}
|
||||||
|
|
||||||
|
T firstOrDefault(std::function<bool(T)> 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<S, T>(*this).next();
|
||||||
|
}
|
||||||
|
catch (LinqEndException &) {}
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
T last(std::function<bool(T)> 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<bool(T)> 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<T> toStdVector() const
|
||||||
|
{
|
||||||
|
std::vector<T> items;
|
||||||
|
for_each([&items](T value) {
|
||||||
|
items.push_back(value);
|
||||||
|
});
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::list<T> toStdList() const
|
||||||
|
{
|
||||||
|
std::list<T> items;
|
||||||
|
for_each([&items](T value) {
|
||||||
|
items.push_back(value);
|
||||||
|
});
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::deque<T> toStdDeque() const
|
||||||
|
{
|
||||||
|
std::deque<T> items;
|
||||||
|
for_each([&items](T value) {
|
||||||
|
items.push_back(value);
|
||||||
|
});
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::set<T> toStdSet() const
|
||||||
|
{
|
||||||
|
std::set<T> items;
|
||||||
|
for_each([&items](T value) {
|
||||||
|
items.insert(value);
|
||||||
|
});
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unordered_set<T> toStdUnorderedSet() const
|
||||||
|
{
|
||||||
|
std::unordered_set<T> items;
|
||||||
|
for_each([&items](T value) {
|
||||||
|
items.insert(value);
|
||||||
|
});
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bits and bytes
|
||||||
|
|
||||||
|
Linq<std::tuple<Linq<S, T>, BytesDirection, T, int>, int> bytes(BytesDirection direction = BytesFirstToLast) const
|
||||||
|
{
|
||||||
|
return Linq<std::tuple<Linq<S, T>, BytesDirection, T, int>, int>(
|
||||||
|
std::make_tuple(*this, direction, T(), sizeof(T)),
|
||||||
|
[](std::tuple<Linq<S, T>, BytesDirection, T, int> &tuple) {
|
||||||
|
Linq<S, T> &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<unsigned char *>(&value);
|
||||||
|
|
||||||
|
int byteIndex = index;
|
||||||
|
if (bytesDirection == BytesLastToFirst) {
|
||||||
|
byteIndex = sizeof(T) - 1 - byteIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
index++;
|
||||||
|
return ptr[byteIndex];
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename TRet>
|
||||||
|
Linq<std::tuple<Linq<S, T>, BytesDirection, int>, TRet> unbytes(BytesDirection direction = BytesFirstToLast) const
|
||||||
|
{
|
||||||
|
return Linq<std::tuple<Linq<S, T>, BytesDirection, int>, TRet>(
|
||||||
|
std::make_tuple(*this, direction, 0),
|
||||||
|
[](std::tuple<Linq<S, T>, BytesDirection, int> &tuple) {
|
||||||
|
Linq<S, T> &linq = std::get<0>(tuple);
|
||||||
|
BytesDirection &bytesDirection = std::get<1>(tuple);
|
||||||
|
int &index = std::get<2>(tuple);
|
||||||
|
|
||||||
|
TRet value;
|
||||||
|
unsigned char *ptr = reinterpret_cast<unsigned char *>(&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<std::tuple<Linq<S, T>, BytesDirection, BitsDirection, T, int>, int> bits(BitsDirection bitsDir = BitsHighToLow, BytesDirection bytesDir = BytesFirstToLast) const
|
||||||
|
{
|
||||||
|
return Linq<std::tuple<Linq<S, T>, BytesDirection, BitsDirection, T, int>, int>(
|
||||||
|
std::make_tuple(*this, bytesDir, bitsDir, T(), sizeof(T) * CHAR_BIT),
|
||||||
|
[](std::tuple<Linq<S, T>, BytesDirection, BitsDirection, T, int> &tuple) {
|
||||||
|
Linq<S, T> &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<unsigned char *>(&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<typename TRet = unsigned char>
|
||||||
|
Linq<std::tuple<Linq<S, T>, BytesDirection, BitsDirection, int>, TRet> unbits(BitsDirection bitsDir = BitsHighToLow, BytesDirection bytesDir = BytesFirstToLast) const
|
||||||
|
{
|
||||||
|
return Linq<std::tuple<Linq<S, T>, BytesDirection, BitsDirection, int>, TRet>(
|
||||||
|
std::make_tuple(*this, bytesDir, bitsDir, 0),
|
||||||
|
[](std::tuple<Linq<S, T>, BytesDirection, BitsDirection, int> &tuple) {
|
||||||
|
Linq<S, T> &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<unsigned char *>(&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<typename S, typename T>
|
||||||
|
std::ostream &operator<<(std::ostream &stream, Linq<S, T> linq)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
while (true) {
|
||||||
|
stream << linq.next() << ' ';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (LinqEndException &) {}
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////
|
||||||
|
// Linq Creators
|
||||||
|
////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
Linq<std::pair<T, T>, typename std::iterator_traits<T>::value_type> from(const T & begin, const T & end)
|
||||||
|
{
|
||||||
|
return Linq<std::pair<T, T>, typename std::iterator_traits<T>::value_type>(
|
||||||
|
std::make_pair(begin, end),
|
||||||
|
[](std::pair<T, T> &pair) {
|
||||||
|
if (pair.first == pair.second) {
|
||||||
|
throw LinqEndException();
|
||||||
|
}
|
||||||
|
return *(pair.first++);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
Linq<std::pair<T, T>, typename std::iterator_traits<T>::value_type> from(const T & it, int n)
|
||||||
|
{
|
||||||
|
return from(it, it + n);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, int N>
|
||||||
|
Linq<std::pair<const T *, const T *>, T> from(T (&array)[N])
|
||||||
|
{
|
||||||
|
return from((const T *)(&array), (const T *)(&array) + N);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<template<class> class TV, typename TT>
|
||||||
|
auto from(const TV<TT> & container)
|
||||||
|
-> decltype(from(container.cbegin(), container.cend()))
|
||||||
|
{
|
||||||
|
return from(container.cbegin(), container.cend());
|
||||||
|
}
|
||||||
|
|
||||||
|
// std::list, std::vector, std::dequeue
|
||||||
|
template<template<class, class> class TV, typename TT, typename TU>
|
||||||
|
auto from(const TV<TT, TU> & container)
|
||||||
|
-> decltype(from(container.cbegin(), container.cend()))
|
||||||
|
{
|
||||||
|
return from(container.cbegin(), container.cend());
|
||||||
|
}
|
||||||
|
|
||||||
|
// std::set
|
||||||
|
template<template<class, class, class> class TV, typename TT, typename TS, typename TU>
|
||||||
|
auto from(const TV<TT, TS, TU> & container)
|
||||||
|
-> decltype(from(container.cbegin(), container.cend()))
|
||||||
|
{
|
||||||
|
return from(container.cbegin(), container.cend());
|
||||||
|
}
|
||||||
|
|
||||||
|
// std::map
|
||||||
|
template<template<class, class, class, class> class TV, typename TK, typename TT, typename TS, typename TU>
|
||||||
|
auto from(const TV<TK, TT, TS, TU> & container)
|
||||||
|
-> decltype(from(container.cbegin(), container.cend()))
|
||||||
|
{
|
||||||
|
return from(container.cbegin(), container.cend());
|
||||||
|
}
|
||||||
|
|
||||||
|
// std::array
|
||||||
|
template<template<class, size_t> class TV, typename TT, size_t TL>
|
||||||
|
auto from(const TV<TT, TL> & container)
|
||||||
|
-> decltype(from(container.cbegin(), container.cend()))
|
||||||
|
{
|
||||||
|
return from(container.cbegin(), container.cend());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
Linq<std::pair<T, int>, T> repeat(const T & value, int count) {
|
||||||
|
return Linq<std::pair<T, int>, T>(
|
||||||
|
std::make_pair(value, count),
|
||||||
|
[](std::pair<T, int> &pair) {
|
||||||
|
if (pair.second > 0) {
|
||||||
|
pair.second--;
|
||||||
|
return pair.first;
|
||||||
|
}
|
||||||
|
throw LinqEndException();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
Linq<std::tuple<T, T, T>, T> range(const T & start, const T & end, const T & step) {
|
||||||
|
return Linq<std::tuple<T, T, T>, T>(
|
||||||
|
std::make_tuple(start, end, step),
|
||||||
|
[](std::tuple<T, T, T> &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();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include "core/feedsmodel.h"
|
#include "core/feedsmodel.h"
|
||||||
|
|
||||||
|
#include "3rd-party/boolinq/boolinq.h"
|
||||||
#include "definitions/definitions.h"
|
#include "definitions/definitions.h"
|
||||||
#include "gui/dialogs/formmain.h"
|
#include "gui/dialogs/formmain.h"
|
||||||
#include "miscellaneous/databasefactory.h"
|
#include "miscellaneous/databasefactory.h"
|
||||||
|
@ -68,7 +69,7 @@ QMimeData* FeedsModel::mimeData(const QModelIndexList& indexes) const {
|
||||||
|
|
||||||
RootItem* item_for_index = itemForIndex(index);
|
RootItem* item_for_index = itemForIndex(index);
|
||||||
|
|
||||||
if (item_for_index->kind() != RootItemKind::Root) {
|
if (item_for_index->kind() != RootItem::Kind::Root) {
|
||||||
stream << quintptr(item_for_index);
|
stream << quintptr(item_for_index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -291,10 +292,10 @@ void FeedsModel::reassignNodeToNewParent(RootItem* original_node, RootItem* new_
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<ServiceRoot*>FeedsModel::serviceRoots() const {
|
QList<ServiceRoot*>FeedsModel::serviceRoots() const {
|
||||||
QList<ServiceRoot*>roots;
|
QList<ServiceRoot*> roots;
|
||||||
|
|
||||||
for (RootItem* root : m_rootItem->childItems()) {
|
for (RootItem* root : m_rootItem->childItems()) {
|
||||||
if (root->kind() == RootItemKind::ServiceRoot) {
|
if (root->kind() == RootItem::Kind::ServiceRoot) {
|
||||||
roots.append(root->toServiceRoot());
|
roots.append(root->toServiceRoot());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -303,13 +304,9 @@ QList<ServiceRoot*>FeedsModel::serviceRoots() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FeedsModel::containsServiceRootFromEntryPoint(const ServiceEntryPoint* point) const {
|
bool FeedsModel::containsServiceRootFromEntryPoint(const ServiceEntryPoint* point) const {
|
||||||
for (const ServiceRoot* root : serviceRoots()) {
|
return boolinq::from(serviceRoots()).any([=](ServiceRoot* root) {
|
||||||
if (root->code() == point->code()) {
|
return root->code() == point->code();
|
||||||
return true;
|
});
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StandardServiceRoot* FeedsModel::standardServiceRoot() const {
|
StandardServiceRoot* FeedsModel::standardServiceRoot() const {
|
||||||
|
@ -329,12 +326,12 @@ QList<Feed*>FeedsModel::feedsForScheduledUpdate(bool auto_update_now) {
|
||||||
|
|
||||||
for (Feed* feed : m_rootItem->getSubTreeFeeds()) {
|
for (Feed* feed : m_rootItem->getSubTreeFeeds()) {
|
||||||
switch (feed->autoUpdateType()) {
|
switch (feed->autoUpdateType()) {
|
||||||
case Feed::DontAutoUpdate:
|
case Feed::AutoUpdateType::DontAutoUpdate:
|
||||||
|
|
||||||
// Do not auto-update this feed ever.
|
// Do not auto-update this feed ever.
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
case Feed::DefaultAutoUpdate:
|
case Feed::AutoUpdateType::DefaultAutoUpdate:
|
||||||
|
|
||||||
if (auto_update_now) {
|
if (auto_update_now) {
|
||||||
feeds_for_update.append(feed);
|
feeds_for_update.append(feed);
|
||||||
|
@ -342,7 +339,7 @@ QList<Feed*>FeedsModel::feedsForScheduledUpdate(bool auto_update_now) {
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Feed::SpecificAutoUpdate:
|
case Feed::AutoUpdateType::SpecificAutoUpdate:
|
||||||
default:
|
default:
|
||||||
int remaining_interval = feed->autoUpdateRemainingInterval();
|
int remaining_interval = feed->autoUpdateRemainingInterval();
|
||||||
|
|
||||||
|
@ -383,7 +380,7 @@ RootItem* FeedsModel::itemForIndex(const QModelIndex& index) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
QModelIndex FeedsModel::indexForItem(const RootItem* item) const {
|
QModelIndex FeedsModel::indexForItem(const RootItem* item) const {
|
||||||
if (item == nullptr || item->kind() == RootItemKind::Root) {
|
if (item == nullptr || item->kind() == RootItem::Kind::Root) {
|
||||||
|
|
||||||
// Root item lies on invalid index.
|
// Root item lies on invalid index.
|
||||||
return QModelIndex();
|
return QModelIndex();
|
||||||
|
@ -391,7 +388,7 @@ QModelIndex FeedsModel::indexForItem(const RootItem* item) const {
|
||||||
|
|
||||||
QStack<const RootItem*> chain;
|
QStack<const RootItem*> chain;
|
||||||
|
|
||||||
while (item->kind() != RootItemKind::Root) {
|
while (item->kind() != RootItem::Kind::Root) {
|
||||||
chain.push(item);
|
chain.push(item);
|
||||||
item = item->parent();
|
item = item->parent();
|
||||||
}
|
}
|
||||||
|
@ -412,13 +409,9 @@ QModelIndex FeedsModel::indexForItem(const RootItem* item) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FeedsModel::hasAnyFeedNewMessages() const {
|
bool FeedsModel::hasAnyFeedNewMessages() const {
|
||||||
for (const Feed* feed : m_rootItem->getSubTreeFeeds()) {
|
return boolinq::from(m_rootItem->getSubTreeFeeds()).any([](const Feed* feed) {
|
||||||
if (feed->status() == Feed::NewMessages) {
|
return feed->status() == Feed::Status::NewMessages;
|
||||||
return true;
|
});
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RootItem* FeedsModel::rootItem() const {
|
RootItem* FeedsModel::rootItem() const {
|
||||||
|
@ -545,9 +538,7 @@ void FeedsModel::loadActivatedServiceAccounts() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (serviceRoots().isEmpty()) {
|
if (serviceRoots().isEmpty()) {
|
||||||
QTimer::singleShot(3000,
|
QTimer::singleShot(3000, qApp->mainForm(), []() {
|
||||||
qApp->mainForm(),
|
|
||||||
[]() {
|
|
||||||
qApp->mainForm()->showAddAccountDialog();
|
qApp->mainForm()->showAddAccountDialog();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,11 +26,11 @@ FeedsProxyModel::FeedsProxyModel(FeedsModel* source_model, QObject* parent)
|
||||||
// means it should be more on top when sorting
|
// means it should be more on top when sorting
|
||||||
// in ascending order.
|
// in ascending order.
|
||||||
m_priorities = {
|
m_priorities = {
|
||||||
RootItemKind::Kind::Category,
|
RootItem::Kind::Category,
|
||||||
RootItemKind::Kind::Feed,
|
RootItem::Kind::Feed,
|
||||||
RootItemKind::Kind::Labels,
|
RootItem::Kind::Labels,
|
||||||
RootItemKind::Kind::Important,
|
RootItem::Kind::Important,
|
||||||
RootItemKind::Kind::Bin
|
RootItem::Kind::Bin
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -218,7 +218,7 @@ bool FeedsProxyModel::filterAcceptsRowInternal(int source_row, const QModelIndex
|
||||||
|
|
||||||
const RootItem* item = m_sourceModel->itemForIndex(idx);
|
const RootItem* item = m_sourceModel->itemForIndex(idx);
|
||||||
|
|
||||||
if (item->kind() != RootItemKind::Category && item->kind() != RootItemKind::Feed) {
|
if (item->kind() != RootItem::Kind::Category && item->kind() != RootItem::Kind::Feed) {
|
||||||
// Some items are always visible.
|
// Some items are always visible.
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,7 +48,7 @@ class FeedsProxyModel : public QSortFilterProxyModel {
|
||||||
const RootItem* m_selectedItem;
|
const RootItem* m_selectedItem;
|
||||||
bool m_showUnreadOnly;
|
bool m_showUnreadOnly;
|
||||||
QList<QPair<int, QModelIndex>> m_hiddenIndices;
|
QList<QPair<int, QModelIndex>> m_hiddenIndices;
|
||||||
QList<RootItemKind::Kind> m_priorities;
|
QList<RootItem::Kind> m_priorities;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // FEEDSPROXYMODEL_H
|
#endif // FEEDSPROXYMODEL_H
|
||||||
|
|
|
@ -111,7 +111,7 @@ bool MessagesModel::setMessageImportantById(int id, RootItem::Importance importa
|
||||||
int found_id = data(i, MSG_DB_ID_INDEX, Qt::EditRole).toInt();
|
int found_id = data(i, MSG_DB_ID_INDEX, Qt::EditRole).toInt();
|
||||||
|
|
||||||
if (found_id == id) {
|
if (found_id == id) {
|
||||||
bool set = setData(index(i, MSG_DB_IMPORTANT_INDEX), important);
|
bool set = setData(index(i, MSG_DB_IMPORTANT_INDEX), int(important));
|
||||||
|
|
||||||
if (set) {
|
if (set) {
|
||||||
emit dataChanged(index(i, 0), index(i, MSG_DB_CUSTOM_HASH_INDEX));
|
emit dataChanged(index(i, 0), index(i, MSG_DB_CUSTOM_HASH_INDEX));
|
||||||
|
@ -214,6 +214,16 @@ Qt::ItemFlags MessagesModel::flags(const QModelIndex& index) const {
|
||||||
return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemNeverHasChildren;
|
return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemNeverHasChildren;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QList<Message> MessagesModel::messagesAt(QList<int> row_indices) const {
|
||||||
|
QList<Message> msgs;
|
||||||
|
|
||||||
|
for (int idx : row_indices) {
|
||||||
|
msgs << messageAt(idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
return msgs;
|
||||||
|
}
|
||||||
|
|
||||||
QVariant MessagesModel::data(int row, int column, int role) const {
|
QVariant MessagesModel::data(int row, int column, int role) const {
|
||||||
return data(index(row, column), role);
|
return data(index(row, column), role);
|
||||||
}
|
}
|
||||||
|
@ -337,7 +347,7 @@ QVariant MessagesModel::data(const QModelIndex& idx, int role) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MessagesModel::setMessageRead(int row_index, RootItem::ReadStatus read) {
|
bool MessagesModel::setMessageRead(int row_index, RootItem::ReadStatus read) {
|
||||||
if (data(row_index, MSG_DB_READ_INDEX, Qt::EditRole).toInt() == read) {
|
if (data(row_index, MSG_DB_READ_INDEX, Qt::EditRole).toInt() == int(read)) {
|
||||||
// Read status is the same is the one currently set.
|
// Read status is the same is the one currently set.
|
||||||
// In that case, no extra work is needed.
|
// In that case, no extra work is needed.
|
||||||
return true;
|
return true;
|
||||||
|
@ -351,7 +361,7 @@ bool MessagesModel::setMessageRead(int row_index, RootItem::ReadStatus read) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rewrite "visible" data in the model.
|
// Rewrite "visible" data in the model.
|
||||||
bool working_change = setData(index(row_index, MSG_DB_READ_INDEX), read);
|
bool working_change = setData(index(row_index, MSG_DB_READ_INDEX), int(read));
|
||||||
|
|
||||||
if (!working_change) {
|
if (!working_change) {
|
||||||
// If rewriting in the model failed, then cancel all actions.
|
// If rewriting in the model failed, then cancel all actions.
|
||||||
|
@ -372,7 +382,7 @@ bool MessagesModel::setMessageReadById(int id, RootItem::ReadStatus read) {
|
||||||
int found_id = data(i, MSG_DB_ID_INDEX, Qt::EditRole).toInt();
|
int found_id = data(i, MSG_DB_ID_INDEX, Qt::EditRole).toInt();
|
||||||
|
|
||||||
if (found_id == id) {
|
if (found_id == id) {
|
||||||
bool set = setData(index(i, MSG_DB_READ_INDEX), read);
|
bool set = setData(index(i, MSG_DB_READ_INDEX), int(read));
|
||||||
|
|
||||||
if (set) {
|
if (set) {
|
||||||
emit dataChanged(index(i, 0), index(i, MSG_DB_CUSTOM_HASH_INDEX));
|
emit dataChanged(index(i, 0), index(i, MSG_DB_CUSTOM_HASH_INDEX));
|
||||||
|
@ -388,8 +398,9 @@ bool MessagesModel::setMessageReadById(int id, RootItem::ReadStatus read) {
|
||||||
bool MessagesModel::switchMessageImportance(int row_index) {
|
bool MessagesModel::switchMessageImportance(int row_index) {
|
||||||
const QModelIndex target_index = index(row_index, MSG_DB_IMPORTANT_INDEX);
|
const QModelIndex target_index = index(row_index, MSG_DB_IMPORTANT_INDEX);
|
||||||
const RootItem::Importance current_importance = (RootItem::Importance) data(target_index, Qt::EditRole).toInt();
|
const RootItem::Importance current_importance = (RootItem::Importance) data(target_index, Qt::EditRole).toInt();
|
||||||
const RootItem::Importance next_importance = current_importance == RootItem::Important ?
|
const RootItem::Importance next_importance = current_importance == RootItem::Importance::Important
|
||||||
RootItem::NotImportant : RootItem::Important;
|
? RootItem::Importance::NotImportant
|
||||||
|
: RootItem::Importance::Important;
|
||||||
const Message message = messageAt(row_index);
|
const Message message = messageAt(row_index);
|
||||||
const QPair<Message, RootItem::Importance> pair(message, next_importance);
|
const QPair<Message, RootItem::Importance> pair(message, next_importance);
|
||||||
|
|
||||||
|
@ -399,7 +410,7 @@ bool MessagesModel::switchMessageImportance(int row_index) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rewrite "visible" data in the model.
|
// Rewrite "visible" data in the model.
|
||||||
const bool working_change = setData(target_index, next_importance);
|
const bool working_change = setData(target_index, int(next_importance));
|
||||||
|
|
||||||
if (!working_change) {
|
if (!working_change) {
|
||||||
// If rewriting in the model failed, then cancel all actions.
|
// If rewriting in the model failed, then cancel all actions.
|
||||||
|
@ -429,15 +440,15 @@ bool MessagesModel::switchBatchMessageImportance(const QModelIndexList& messages
|
||||||
|
|
||||||
RootItem::Importance message_importance = messageImportance((message.row()));
|
RootItem::Importance message_importance = messageImportance((message.row()));
|
||||||
|
|
||||||
message_states.append(QPair<Message, RootItem::Importance>(msg, message_importance == RootItem::Important ?
|
message_states.append(QPair<Message, RootItem::Importance>(msg, message_importance == RootItem::Importance::Important
|
||||||
RootItem::NotImportant :
|
? RootItem::Importance::NotImportant
|
||||||
RootItem::Important));
|
: RootItem::Importance::Important));
|
||||||
message_ids.append(QString::number(msg.m_id));
|
message_ids.append(QString::number(msg.m_id));
|
||||||
QModelIndex idx_msg_imp = index(message.row(), MSG_DB_IMPORTANT_INDEX);
|
QModelIndex idx_msg_imp = index(message.row(), MSG_DB_IMPORTANT_INDEX);
|
||||||
|
|
||||||
setData(idx_msg_imp, message_importance == RootItem::Important ?
|
setData(idx_msg_imp, message_importance == RootItem::Importance::Important
|
||||||
(int) RootItem::NotImportant :
|
? int(RootItem::Importance::NotImportant)
|
||||||
(int) RootItem::Important);
|
: int(RootItem::Importance::Important));
|
||||||
}
|
}
|
||||||
|
|
||||||
reloadWholeLayout();
|
reloadWholeLayout();
|
||||||
|
@ -481,7 +492,7 @@ bool MessagesModel::setBatchMessagesDeleted(const QModelIndexList& messages) {
|
||||||
|
|
||||||
bool deleted;
|
bool deleted;
|
||||||
|
|
||||||
if (m_selectedItem->kind() != RootItemKind::Bin) {
|
if (m_selectedItem->kind() != RootItem::Kind::Bin) {
|
||||||
deleted = DatabaseQueries::deleteOrRestoreMessagesToFromBin(m_db, message_ids, true);
|
deleted = DatabaseQueries::deleteOrRestoreMessagesToFromBin(m_db, message_ids, true);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -44,6 +44,8 @@ class MessagesModel : public QSqlQueryModel, public MessagesModelSqlLayer {
|
||||||
Qt::ItemFlags flags(const QModelIndex& index) const;
|
Qt::ItemFlags flags(const QModelIndex& index) const;
|
||||||
|
|
||||||
// Returns message at given index.
|
// Returns message at given index.
|
||||||
|
|
||||||
|
QList<Message> messagesAt(QList<int> row_indices) const;
|
||||||
Message messageAt(int row_index) const;
|
Message messageAt(int row_index) const;
|
||||||
int messageId(int row_index) const;
|
int messageId(int row_index) const;
|
||||||
RootItem::Importance messageImportance(int row_index) const;
|
RootItem::Importance messageImportance(int row_index) const;
|
||||||
|
|
|
@ -141,6 +141,26 @@
|
||||||
#define APP_NO_THEME ""
|
#define APP_NO_THEME ""
|
||||||
#define APP_THEME_SUFFIX ".png"
|
#define APP_THEME_SUFFIX ".png"
|
||||||
|
|
||||||
|
#ifndef qDebugNN
|
||||||
|
#define qDebugNN qDebug().noquote().nospace()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef qWarningNN
|
||||||
|
#define qWarningNN qWarning().noquote().nospace()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef qCriticalNN
|
||||||
|
#define qCriticalNN qCritical().noquote().nospace()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef qFatalNN
|
||||||
|
#define qFatalNN qFatal().noquote().nospace()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef qInfoNN
|
||||||
|
#define qInfoNN qInfo().noquote().nospace()
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef QSL
|
#ifndef QSL
|
||||||
|
|
||||||
// Thin macro wrapper for literal strings.
|
// Thin macro wrapper for literal strings.
|
||||||
|
|
|
@ -25,7 +25,7 @@ FormAbout::~FormAbout() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void FormAbout::loadSettingsAndPaths() {
|
void FormAbout::loadSettingsAndPaths() {
|
||||||
if (qApp->settings()->type() == SettingsProperties::Portable) {
|
if (qApp->settings()->type() == SettingsProperties::SettingsType::Portable) {
|
||||||
m_ui.m_txtPathsSettingsType->setText(tr("FULLY portable"));
|
m_ui.m_txtPathsSettingsType->setText(tr("FULLY portable"));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -68,6 +68,13 @@ void FormAbout::loadLicenseAndInformation() {
|
||||||
m_ui.m_txtLicenseBsd->setText(tr("License not found."));
|
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.
|
// Set other informative texts.
|
||||||
m_ui.m_lblDesc->setText(tr("<b>%8</b><br>" "<b>Version:</b> %1 (built on %2/%3)<br>" "<b>Revision:</b> %4<br>" "<b>Build date:</b> %5<br>"
|
m_ui.m_lblDesc->setText(tr("<b>%8</b><br>" "<b>Version:</b> %1 (built on %2/%3)<br>" "<b>Revision:</b> %4<br>" "<b>Build date:</b> %5<br>"
|
||||||
"<b>Qt:</b> %6 (compiled against %7)<br>").arg(
|
"<b>Qt:</b> %6 (compiled against %7)<br>").arg(
|
||||||
|
|
|
@ -160,7 +160,7 @@ p, li { white-space: pre-wrap; }
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>685</width>
|
<width>685</width>
|
||||||
<height>184</height>
|
<height>157</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="autoFillBackground">
|
<property name="autoFillBackground">
|
||||||
|
@ -235,8 +235,8 @@ p, li { white-space: pre-wrap; }
|
||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>98</width>
|
<width>685</width>
|
||||||
<height>69</height>
|
<height>157</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<attribute name="label">
|
<attribute name="label">
|
||||||
|
@ -288,6 +288,68 @@ p, li { white-space: pre-wrap; }
|
||||||
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||||
p, li { white-space: pre-wrap; }
|
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;">
|
</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></string>
|
||||||
|
</property>
|
||||||
|
<property name="textInteractionFlags">
|
||||||
|
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||||
|
</property>
|
||||||
|
<property name="openExternalLinks">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="page_MIT">
|
||||||
|
<attribute name="label">
|
||||||
|
<string>MIT License (applies to boolinq source code)</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_6">
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QTextBrowser" name="m_txtLicenseMit">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>DejaVu Sans Mono</family>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true"/>
|
||||||
|
</property>
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::NoFrame</enum>
|
||||||
|
</property>
|
||||||
|
<property name="horizontalScrollBarPolicy">
|
||||||
|
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||||
|
</property>
|
||||||
|
<property name="autoFormatting">
|
||||||
|
<set>QTextEdit::AutoNone</set>
|
||||||
|
</property>
|
||||||
|
<property name="undoRedoEnabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="lineWrapMode">
|
||||||
|
<enum>QTextEdit::WidgetWidth</enum>
|
||||||
|
</property>
|
||||||
|
<property name="readOnly">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="html">
|
||||||
|
<string notr="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></string>
|
<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></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="textInteractionFlags">
|
<property name="textInteractionFlags">
|
||||||
|
|
|
@ -312,7 +312,7 @@ void FormMain::updateRecycleBinMenu() {
|
||||||
no_action->setEnabled(false);
|
no_action->setEnabled(false);
|
||||||
root_menu->addAction(no_action);
|
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")),
|
QAction* no_action = new QAction(qApp->icons()->fromTheme(QSL("dialog-error")),
|
||||||
tr("No actions possible"),
|
tr("No actions possible"),
|
||||||
m_ui->m_menuRecycleBin);
|
m_ui->m_menuRecycleBin);
|
||||||
|
@ -391,7 +391,7 @@ void FormMain::updateMessageButtonsAvailability() {
|
||||||
const bool one_message_selected = tabWidget()->feedMessageViewer()->messagesView()->selectionModel()->selectedRows().size() == 1;
|
const bool one_message_selected = tabWidget()->feedMessageViewer()->messagesView()->selectionModel()->selectedRows().size() == 1;
|
||||||
const bool atleast_one_message_selected = !tabWidget()->feedMessageViewer()->messagesView()->selectionModel()->selectedRows().isEmpty();
|
const bool atleast_one_message_selected = !tabWidget()->feedMessageViewer()->messagesView()->selectionModel()->selectedRows().isEmpty();
|
||||||
const bool bin_loaded = tabWidget()->feedMessageViewer()->messagesView()->sourceModel()->loadedItem() != nullptr
|
const bool bin_loaded = tabWidget()->feedMessageViewer()->messagesView()->sourceModel()->loadedItem() != nullptr
|
||||||
&& tabWidget()->feedMessageViewer()->messagesView()->sourceModel()->loadedItem()->kind() == RootItemKind::Bin;
|
&& tabWidget()->feedMessageViewer()->messagesView()->sourceModel()->loadedItem()->kind() == RootItem::Kind::Bin;
|
||||||
|
|
||||||
m_ui->m_actionDeleteSelectedMessages->setEnabled(atleast_one_message_selected);
|
m_ui->m_actionDeleteSelectedMessages->setEnabled(atleast_one_message_selected);
|
||||||
m_ui->m_actionRestoreSelectedMessages->setEnabled(atleast_one_message_selected && bin_loaded);
|
m_ui->m_actionRestoreSelectedMessages->setEnabled(atleast_one_message_selected && bin_loaded);
|
||||||
|
@ -408,9 +408,9 @@ void FormMain::updateFeedButtonsAvailability() {
|
||||||
const bool critical_action_running = qApp->feedUpdateLock()->isLocked();
|
const bool critical_action_running = qApp->feedUpdateLock()->isLocked();
|
||||||
const RootItem* selected_item = tabWidget()->feedMessageViewer()->feedsView()->selectedItem();
|
const RootItem* selected_item = tabWidget()->feedMessageViewer()->feedsView()->selectedItem();
|
||||||
const bool anything_selected = selected_item != nullptr;
|
const bool anything_selected = selected_item != nullptr;
|
||||||
const bool feed_selected = anything_selected && selected_item->kind() == RootItemKind::Feed;
|
const bool feed_selected = anything_selected && selected_item->kind() == RootItem::Kind::Feed;
|
||||||
const bool category_selected = anything_selected && selected_item->kind() == RootItemKind::Category;
|
const bool category_selected = anything_selected && selected_item->kind() == RootItem::Kind::Category;
|
||||||
const bool service_selected = anything_selected && selected_item->kind() == RootItemKind::ServiceRoot;
|
const bool service_selected = anything_selected && selected_item->kind() == RootItem::Kind::ServiceRoot;
|
||||||
|
|
||||||
m_ui->m_actionStopRunningItemsUpdate->setEnabled(is_update_running);
|
m_ui->m_actionStopRunningItemsUpdate->setEnabled(is_update_running);
|
||||||
m_ui->m_actionBackupDatabaseSettings->setEnabled(!critical_action_running);
|
m_ui->m_actionBackupDatabaseSettings->setEnabled(!critical_action_running);
|
||||||
|
|
|
@ -95,7 +95,7 @@ void FeedsView::saveAllExpandStates() {
|
||||||
|
|
||||||
void FeedsView::saveExpandStates(RootItem* item) {
|
void FeedsView::saveExpandStates(RootItem* item) {
|
||||||
Settings* settings = qApp->settings();
|
Settings* settings = qApp->settings();
|
||||||
QList<RootItem*> items = item->getSubTree(RootItemKind::Category | RootItemKind::ServiceRoot);
|
QList<RootItem*> items = item->getSubTree(RootItem::Kind::Category | RootItem::Kind::ServiceRoot);
|
||||||
|
|
||||||
// Iterate all categories and save their expand statuses.
|
// Iterate all categories and save their expand statuses.
|
||||||
for (const RootItem* it : items) {
|
for (const RootItem* it : items) {
|
||||||
|
@ -113,7 +113,7 @@ void FeedsView::loadAllExpandStates() {
|
||||||
const Settings* settings = qApp->settings();
|
const Settings* settings = qApp->settings();
|
||||||
QList<RootItem*> expandable_items;
|
QList<RootItem*> expandable_items;
|
||||||
|
|
||||||
expandable_items.append(sourceModel()->rootItem()->getSubTree(RootItemKind::Category | RootItemKind::ServiceRoot));
|
expandable_items.append(sourceModel()->rootItem()->getSubTree(RootItem::Kind::Category | RootItem::Kind::ServiceRoot));
|
||||||
|
|
||||||
// Iterate all categories and save their expand statuses.
|
// Iterate all categories and save their expand statuses.
|
||||||
for (const RootItem* item : expandable_items) {
|
for (const RootItem* item : expandable_items) {
|
||||||
|
@ -305,11 +305,11 @@ void FeedsView::markSelectedItemReadStatus(RootItem::ReadStatus read) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void FeedsView::markSelectedItemRead() {
|
void FeedsView::markSelectedItemRead() {
|
||||||
markSelectedItemReadStatus(RootItem::Read);
|
markSelectedItemReadStatus(RootItem::ReadStatus::Read);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FeedsView::markSelectedItemUnread() {
|
void FeedsView::markSelectedItemUnread() {
|
||||||
markSelectedItemReadStatus(RootItem::Unread);
|
markSelectedItemReadStatus(RootItem::ReadStatus::Unread);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FeedsView::markAllItemsReadStatus(RootItem::ReadStatus read) {
|
void FeedsView::markAllItemsReadStatus(RootItem::ReadStatus read) {
|
||||||
|
@ -317,7 +317,7 @@ void FeedsView::markAllItemsReadStatus(RootItem::ReadStatus read) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void FeedsView::markAllItemsRead() {
|
void FeedsView::markAllItemsRead() {
|
||||||
markAllItemsReadStatus(RootItem::Read);
|
markAllItemsReadStatus(RootItem::ReadStatus::Read);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FeedsView::openSelectedItemsInNewspaperMode() {
|
void FeedsView::openSelectedItemsInNewspaperMode() {
|
||||||
|
@ -430,7 +430,7 @@ QMenu* FeedsView::initializeContextMenuBin(RootItem* clicked_item) {
|
||||||
m_contextMenuBin->clear();
|
m_contextMenuBin->clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<QAction*> specific_actions = clicked_item->contextMenu();
|
QList<QAction*> specific_actions = clicked_item->contextMenuFeedsList();
|
||||||
|
|
||||||
m_contextMenuBin->addActions(QList<QAction*>() <<
|
m_contextMenuBin->addActions(QList<QAction*>() <<
|
||||||
qApp->mainForm()->m_ui->m_actionViewSelectedItemsNewspaperMode <<
|
qApp->mainForm()->m_ui->m_actionViewSelectedItemsNewspaperMode <<
|
||||||
|
@ -453,7 +453,7 @@ QMenu* FeedsView::initializeContextMenuService(RootItem* clicked_item) {
|
||||||
m_contextMenuService->clear();
|
m_contextMenuService->clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<QAction*> specific_actions = clicked_item->contextMenu();
|
QList<QAction*> specific_actions = clicked_item->contextMenuFeedsList();
|
||||||
|
|
||||||
m_contextMenuService->addActions(QList<QAction*>() <<
|
m_contextMenuService->addActions(QList<QAction*>() <<
|
||||||
qApp->mainForm()->m_ui->m_actionUpdateSelectedItems <<
|
qApp->mainForm()->m_ui->m_actionUpdateSelectedItems <<
|
||||||
|
@ -511,7 +511,7 @@ QMenu* FeedsView::initializeContextMenuCategories(RootItem* clicked_item) {
|
||||||
m_contextMenuCategories->clear();
|
m_contextMenuCategories->clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<QAction*> specific_actions = clicked_item->contextMenu();
|
QList<QAction*> specific_actions = clicked_item->contextMenuFeedsList();
|
||||||
|
|
||||||
m_contextMenuCategories->addActions(QList<QAction*>() <<
|
m_contextMenuCategories->addActions(QList<QAction*>() <<
|
||||||
qApp->mainForm()->m_ui->m_actionUpdateSelectedItems <<
|
qApp->mainForm()->m_ui->m_actionUpdateSelectedItems <<
|
||||||
|
@ -538,7 +538,7 @@ QMenu* FeedsView::initializeContextMenuFeeds(RootItem* clicked_item) {
|
||||||
m_contextMenuFeeds->clear();
|
m_contextMenuFeeds->clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<QAction*> specific_actions = clicked_item->contextMenu();
|
QList<QAction*> specific_actions = clicked_item->contextMenuFeedsList();
|
||||||
|
|
||||||
m_contextMenuFeeds->addActions(QList<QAction*>() <<
|
m_contextMenuFeeds->addActions(QList<QAction*>() <<
|
||||||
qApp->mainForm()->m_ui->m_actionUpdateSelectedItems <<
|
qApp->mainForm()->m_ui->m_actionUpdateSelectedItems <<
|
||||||
|
@ -565,7 +565,7 @@ QMenu* FeedsView::initializeContextMenuImportant(RootItem* clicked_item) {
|
||||||
m_contextMenuImportant->clear();
|
m_contextMenuImportant->clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<QAction*> specific_actions = clicked_item->contextMenu();
|
QList<QAction*> specific_actions = clicked_item->contextMenuFeedsList();
|
||||||
|
|
||||||
m_contextMenuImportant->addActions(QList<QAction*>() <<
|
m_contextMenuImportant->addActions(QList<QAction*>() <<
|
||||||
qApp->mainForm()->m_ui->m_actionViewSelectedItemsNewspaperMode <<
|
qApp->mainForm()->m_ui->m_actionViewSelectedItemsNewspaperMode <<
|
||||||
|
@ -598,7 +598,7 @@ QMenu* FeedsView::initializeContextMenuOtherItem(RootItem* clicked_item) {
|
||||||
m_contextMenuOtherItems->clear();
|
m_contextMenuOtherItems->clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<QAction*> specific_actions = clicked_item->contextMenu();
|
QList<QAction*> specific_actions = clicked_item->contextMenuFeedsList();
|
||||||
|
|
||||||
if (!specific_actions.isEmpty()) {
|
if (!specific_actions.isEmpty()) {
|
||||||
m_contextMenuOtherItems->addSeparator();
|
m_contextMenuOtherItems->addSeparator();
|
||||||
|
@ -660,21 +660,21 @@ void FeedsView::contextMenuEvent(QContextMenuEvent* event) {
|
||||||
const QModelIndex mapped_index = model()->mapToSource(clicked_index);
|
const QModelIndex mapped_index = model()->mapToSource(clicked_index);
|
||||||
RootItem* clicked_item = sourceModel()->itemForIndex(mapped_index);
|
RootItem* clicked_item = sourceModel()->itemForIndex(mapped_index);
|
||||||
|
|
||||||
if (clicked_item->kind() == RootItemKind::Category) {
|
if (clicked_item->kind() == RootItem::Kind::Category) {
|
||||||
// Display context menu for categories.
|
// Display context menu for categories.
|
||||||
initializeContextMenuCategories(clicked_item)->exec(event->globalPos());
|
initializeContextMenuCategories(clicked_item)->exec(event->globalPos());
|
||||||
}
|
}
|
||||||
else if (clicked_item->kind() == RootItemKind::Feed) {
|
else if (clicked_item->kind() == RootItem::Kind::Feed) {
|
||||||
// Display context menu for feeds.
|
// Display context menu for feeds.
|
||||||
initializeContextMenuFeeds(clicked_item)->exec(event->globalPos());
|
initializeContextMenuFeeds(clicked_item)->exec(event->globalPos());
|
||||||
}
|
}
|
||||||
else if (clicked_item->kind() == RootItemKind::Important) {
|
else if (clicked_item->kind() == RootItem::Kind::Important) {
|
||||||
initializeContextMenuImportant(clicked_item)->exec(event->globalPos());
|
initializeContextMenuImportant(clicked_item)->exec(event->globalPos());
|
||||||
}
|
}
|
||||||
else if (clicked_item->kind() == RootItemKind::Bin) {
|
else if (clicked_item->kind() == RootItem::Kind::Bin) {
|
||||||
initializeContextMenuBin(clicked_item)->exec(event->globalPos());
|
initializeContextMenuBin(clicked_item)->exec(event->globalPos());
|
||||||
}
|
}
|
||||||
else if (clicked_item->kind() == RootItemKind::ServiceRoot) {
|
else if (clicked_item->kind() == RootItem::Kind::ServiceRoot) {
|
||||||
initializeContextMenuService(clicked_item)->exec(event->globalPos());
|
initializeContextMenuService(clicked_item)->exec(event->globalPos());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -693,7 +693,7 @@ void FeedsView::mouseDoubleClickEvent(QMouseEvent* event) {
|
||||||
if (idx.isValid()) {
|
if (idx.isValid()) {
|
||||||
RootItem* item = m_sourceModel->itemForIndex(m_proxyModel->mapToSource(idx));
|
RootItem* item = m_sourceModel->itemForIndex(m_proxyModel->mapToSource(idx));
|
||||||
|
|
||||||
if (item->kind() == RootItemKind::Feed || item->kind() == RootItemKind::Bin) {
|
if (item->kind() == RootItem::Kind::Feed || item->kind() == RootItem::Kind::Bin) {
|
||||||
const QList<Message> messages = m_sourceModel->messagesForItem(item);
|
const QList<Message> messages = m_sourceModel->messagesForItem(item);
|
||||||
|
|
||||||
if (!messages.isEmpty()) {
|
if (!messages.isEmpty()) {
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include "gui/messagesview.h"
|
#include "gui/messagesview.h"
|
||||||
|
|
||||||
|
#include "3rd-party/boolinq/boolinq.h"
|
||||||
#include "core/messagesmodel.h"
|
#include "core/messagesmodel.h"
|
||||||
#include "core/messagesproxymodel.h"
|
#include "core/messagesproxymodel.h"
|
||||||
#include "gui/dialogs/formmain.h"
|
#include "gui/dialogs/formmain.h"
|
||||||
|
@ -13,6 +14,7 @@
|
||||||
#include "miscellaneous/settings.h"
|
#include "miscellaneous/settings.h"
|
||||||
#include "network-web/networkfactory.h"
|
#include "network-web/networkfactory.h"
|
||||||
#include "network-web/webfactory.h"
|
#include "network-web/webfactory.h"
|
||||||
|
#include "services/abstract/serviceroot.h"
|
||||||
|
|
||||||
#include <QFileIconProvider>
|
#include <QFileIconProvider>
|
||||||
#include <QKeyEvent>
|
#include <QKeyEvent>
|
||||||
|
@ -213,12 +215,33 @@ void MessagesView::initializeContextMenu() {
|
||||||
|
|
||||||
m_contextMenu->addMenu(menu);
|
m_contextMenu->addMenu(menu);
|
||||||
m_contextMenu->addActions(
|
m_contextMenu->addActions(
|
||||||
QList<QAction*>() << 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 <<
|
QList<QAction*>()
|
||||||
qApp->mainForm()->m_ui->m_actionDeleteSelectedMessages);
|
<< 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) {
|
if (m_sourceModel->loadedItem() != nullptr) {
|
||||||
|
if (m_sourceModel->loadedItem()->kind() == RootItem::Kind::Bin) {
|
||||||
m_contextMenu->addAction(qApp->mainForm()->m_ui->m_actionRestoreSelectedMessages);
|
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<int>::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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MessagesView::mousePressEvent(QMouseEvent* event) {
|
void MessagesView::mousePressEvent(QMouseEvent* event) {
|
||||||
|
@ -285,7 +308,7 @@ void MessagesView::selectionChanged(const QItemSelection& selected, const QItemS
|
||||||
|
|
||||||
// Set this message as read only if current item
|
// Set this message as read only if current item
|
||||||
// wasn't changed by "mark selected messages unread" action.
|
// wasn't changed by "mark selected messages unread" action.
|
||||||
m_sourceModel->setMessageRead(mapped_current_index.row(), RootItem::Read);
|
m_sourceModel->setMessageRead(mapped_current_index.row(), RootItem::ReadStatus::Read);
|
||||||
message.m_isRead = true;
|
message.m_isRead = true;
|
||||||
|
|
||||||
emit currentMessageChanged(message, m_sourceModel->loadedItem());
|
emit currentMessageChanged(message, m_sourceModel->loadedItem());
|
||||||
|
@ -366,11 +389,11 @@ void MessagesView::sendSelectedMessageViaEmail() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MessagesView::markSelectedMessagesRead() {
|
void MessagesView::markSelectedMessagesRead() {
|
||||||
setSelectedMessagesReadStatus(RootItem::Read);
|
setSelectedMessagesReadStatus(RootItem::ReadStatus::Read);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MessagesView::markSelectedMessagesUnread() {
|
void MessagesView::markSelectedMessagesUnread() {
|
||||||
setSelectedMessagesReadStatus(RootItem::Unread);
|
setSelectedMessagesReadStatus(RootItem::ReadStatus::Unread);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MessagesView::setSelectedMessagesReadStatus(RootItem::ReadStatus read) {
|
void MessagesView::setSelectedMessagesReadStatus(RootItem::ReadStatus read) {
|
||||||
|
|
|
@ -19,14 +19,8 @@ class MessagesView : public QTreeView {
|
||||||
explicit MessagesView(QWidget* parent = nullptr);
|
explicit MessagesView(QWidget* parent = nullptr);
|
||||||
virtual ~MessagesView();
|
virtual ~MessagesView();
|
||||||
|
|
||||||
// Model accessors.
|
MessagesProxyModel* model() const;
|
||||||
inline MessagesProxyModel* model() const {
|
MessagesModel* sourceModel() const;
|
||||||
return m_proxyModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline MessagesModel* sourceModel() const {
|
|
||||||
return m_sourceModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
void reloadFontSettings();
|
void reloadFontSettings();
|
||||||
|
|
||||||
|
@ -110,4 +104,12 @@ class MessagesView : public QTreeView {
|
||||||
bool m_columnsAdjusted;
|
bool m_columnsAdjusted;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline MessagesProxyModel* MessagesView::model() const {
|
||||||
|
return m_proxyModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline MessagesModel* MessagesView::sourceModel() const {
|
||||||
|
return m_sourceModel;
|
||||||
|
}
|
||||||
|
|
||||||
#endif // MESSAGESVIEW_H
|
#endif // MESSAGESVIEW_H
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include "definitions/definitions.h"
|
#include "definitions/definitions.h"
|
||||||
#include "gui/plaintoolbutton.h"
|
#include "gui/plaintoolbutton.h"
|
||||||
#include "miscellaneous/settings.h"
|
#include "miscellaneous/settings.h"
|
||||||
|
#include "miscellaneous/templates.h"
|
||||||
|
|
||||||
#include <QMouseEvent>
|
#include <QMouseEvent>
|
||||||
#include <QStyle>
|
#include <QStyle>
|
||||||
|
@ -25,8 +26,8 @@ void TabBar::setTabType(int index, const TabBar::TabType& type) {
|
||||||
this));
|
this));
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case TabBar::DownloadManager:
|
case TabBar::TabType::DownloadManager:
|
||||||
case TabBar::Closable: {
|
case TabBar::TabType::Closable: {
|
||||||
auto* close_button = new PlainToolButton(this);
|
auto* close_button = new PlainToolButton(this);
|
||||||
|
|
||||||
close_button->setIcon(qApp->icons()->fromTheme(QSL("application-exit")));
|
close_button->setIcon(qApp->icons()->fromTheme(QSL("application-exit")));
|
||||||
|
@ -45,7 +46,7 @@ void TabBar::setTabType(int index, const TabBar::TabType& type) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
setTabData(index, QVariant(type));
|
setTabData(index, QVariant(int(type)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void TabBar::closeTabViaButton() {
|
void TabBar::closeTabViaButton() {
|
||||||
|
@ -99,7 +100,7 @@ void TabBar::mousePressEvent(QMouseEvent* event) {
|
||||||
// destination does not know the original event.
|
// destination does not know the original event.
|
||||||
if ((event->button() & Qt::MiddleButton) == Qt::MiddleButton &&
|
if ((event->button() & Qt::MiddleButton) == Qt::MiddleButton &&
|
||||||
qApp->settings()->value(GROUP(GUI), SETTING(GUI::TabCloseMiddleClick)).toBool()) {
|
qApp->settings()->value(GROUP(GUI), SETTING(GUI::TabCloseMiddleClick)).toBool()) {
|
||||||
if (tabType(tab_index) == TabBar::Closable || tabType(tab_index) == TabBar::DownloadManager) {
|
if (tabType(tab_index) == TabBar::TabType::Closable || tabType(tab_index) == TabBar::TabType::DownloadManager) {
|
||||||
// This tab is closable, so we can close it.
|
// This tab is closable, so we can close it.
|
||||||
emit tabCloseRequested(tab_index);
|
emit tabCloseRequested(tab_index);
|
||||||
}
|
}
|
||||||
|
@ -118,7 +119,7 @@ void TabBar::mouseDoubleClickEvent(QMouseEvent* event) {
|
||||||
// destination does not know the original event.
|
// destination does not know the original event.
|
||||||
if ((event->button() & Qt::LeftButton) == Qt::LeftButton &&
|
if ((event->button() & Qt::LeftButton) == Qt::LeftButton &&
|
||||||
qApp->settings()->value(GROUP(GUI), SETTING(GUI::TabCloseDoubleClick)).toBool()) {
|
qApp->settings()->value(GROUP(GUI), SETTING(GUI::TabCloseDoubleClick)).toBool()) {
|
||||||
if ((tabType(tab_index) & (TabBar::Closable | TabBar::DownloadManager)) > 0) {
|
if (int(tabType(tab_index) & (TabBar::TabType::Closable | TabBar::TabType::DownloadManager)) > 0) {
|
||||||
// This tab is closable, so we can close it.
|
// This tab is closable, so we can close it.
|
||||||
emit tabCloseRequested(tab_index);
|
emit tabCloseRequested(tab_index);
|
||||||
}
|
}
|
||||||
|
@ -128,3 +129,19 @@ void TabBar::mouseDoubleClickEvent(QMouseEvent* event) {
|
||||||
emit emptySpaceDoubleClicked();
|
emit emptySpaceDoubleClicked();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TabBar::TabType& operator&=(TabBar::TabType& a, TabBar::TabType b) {
|
||||||
|
return (TabBar::TabType&)((int&)a &= (int)b);
|
||||||
|
}
|
||||||
|
|
||||||
|
TabBar::TabType& operator|=(TabBar::TabType& a, TabBar::TabType b) {
|
||||||
|
return (TabBar::TabType&)((int&)a |= (int)b);
|
||||||
|
}
|
||||||
|
|
||||||
|
TabBar::TabType operator&(TabBar::TabType a, TabBar::TabType b) {
|
||||||
|
return (TabBar::TabType)((int)a & (int)b);
|
||||||
|
}
|
||||||
|
|
||||||
|
TabBar::TabType operator|(TabBar::TabType a, TabBar::TabType b) {
|
||||||
|
return (TabBar::TabType)((int)a | (int)b);
|
||||||
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ class TabBar : public QTabBar {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum TabType {
|
enum class TabType {
|
||||||
FeedReader = 1,
|
FeedReader = 1,
|
||||||
DownloadManager = 2,
|
DownloadManager = 2,
|
||||||
NonClosable = 4,
|
NonClosable = 4,
|
||||||
|
@ -20,15 +20,12 @@ class TabBar : public QTabBar {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Constructors.
|
// Constructors.
|
||||||
explicit TabBar(QWidget* parent = 0);
|
explicit TabBar(QWidget* parent = nullptr);
|
||||||
virtual ~TabBar();
|
virtual ~TabBar();
|
||||||
|
|
||||||
// Getter/setter for tab type.
|
// Getter/setter for tab type.
|
||||||
void setTabType(int index, const TabBar::TabType& type);
|
void setTabType(int index, const TabBar::TabType& type);
|
||||||
|
TabBar::TabType tabType(int index) const;
|
||||||
inline TabBar::TabType tabType(int index) const {
|
|
||||||
return static_cast<TabBar::TabType>(tabData(index).toInt());
|
|
||||||
}
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
|
||||||
|
@ -48,4 +45,13 @@ class TabBar : public QTabBar {
|
||||||
void emptySpaceDoubleClicked();
|
void emptySpaceDoubleClicked();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline TabBar::TabType TabBar::tabType(int index) const {
|
||||||
|
return static_cast<TabBar::TabType>(tabData(index).toInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
TabBar::TabType operator| (TabBar::TabType a, TabBar::TabType b);
|
||||||
|
TabBar::TabType operator& (TabBar::TabType a, TabBar::TabType b);
|
||||||
|
TabBar::TabType& operator|= (TabBar::TabType& a, TabBar::TabType b);
|
||||||
|
TabBar::TabType& operator&= (TabBar::TabType& a, TabBar::TabType b);
|
||||||
|
|
||||||
#endif // TABBAR_H
|
#endif // TABBAR_H
|
||||||
|
|
|
@ -77,7 +77,10 @@ void TabWidget::showDownloadManager() {
|
||||||
|
|
||||||
// Download manager is not opened. Create tab with it.
|
// Download manager is not opened. Create tab with it.
|
||||||
qApp->downloadManager()->setParent(this);
|
qApp->downloadManager()->setParent(this);
|
||||||
addTab(qApp->downloadManager(), qApp->icons()->fromTheme(QSL("emblem-downloads")), tr("Downloads"), TabBar::DownloadManager);
|
addTab(qApp->downloadManager(),
|
||||||
|
qApp->icons()->fromTheme(QSL("emblem-downloads")),
|
||||||
|
tr("Downloads"),
|
||||||
|
TabBar::TabType::DownloadManager);
|
||||||
setCurrentIndex(count() - 1);
|
setCurrentIndex(count() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,7 +133,7 @@ void TabWidget::createConnections() {
|
||||||
void TabWidget::initializeTabs() {
|
void TabWidget::initializeTabs() {
|
||||||
// Create widget for "Feeds" page and add it.
|
// Create widget for "Feeds" page and add it.
|
||||||
m_feedMessageViewer = new FeedMessageViewer(this);
|
m_feedMessageViewer = new FeedMessageViewer(this);
|
||||||
const int index_of_browser = addTab(m_feedMessageViewer, QIcon(), tr("Feeds"), TabBar::FeedReader);
|
const int index_of_browser = addTab(m_feedMessageViewer, QIcon(), tr("Feeds"), TabBar::TabType::FeedReader);
|
||||||
|
|
||||||
setTabToolTip(index_of_browser, tr("Browse your feeds and messages"));
|
setTabToolTip(index_of_browser, tr("Browse your feeds and messages"));
|
||||||
}
|
}
|
||||||
|
@ -140,18 +143,18 @@ void TabWidget::setupIcons() {
|
||||||
// accordingly.
|
// accordingly.
|
||||||
for (int index = 0; index < count(); index++) {
|
for (int index = 0; index < count(); index++) {
|
||||||
// Index 0 usually contains widget which displays feeds & messages.
|
// Index 0 usually contains widget which displays feeds & messages.
|
||||||
if (tabBar()->tabType(index) == TabBar::FeedReader) {
|
if (tabBar()->tabType(index) == TabBar::TabType::FeedReader) {
|
||||||
setTabIcon(index, qApp->icons()->fromTheme(QSL("application-rss+xml")));
|
setTabIcon(index, qApp->icons()->fromTheme(QSL("application-rss+xml")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TabWidget::closeTab(int index) {
|
bool TabWidget::closeTab(int index) {
|
||||||
if (tabBar()->tabType(index) == TabBar::Closable) {
|
if (tabBar()->tabType(index) == TabBar::TabType::Closable) {
|
||||||
removeTab(index, true);
|
removeTab(index, true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (tabBar()->tabType(index) == TabBar::DownloadManager) {
|
else if (tabBar()->tabType(index) == TabBar::TabType::DownloadManager) {
|
||||||
removeTab(index, false);
|
removeTab(index, false);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -198,7 +201,10 @@ int TabWidget::addNewspaperView(RootItem* root, const QList<Message>& messages)
|
||||||
m_feedMessageViewer->messagesView()->sourceModel(), &MessagesModel::setMessageImportantById);
|
m_feedMessageViewer->messagesView()->sourceModel(), &MessagesModel::setMessageImportantById);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int index = addTab(prev, qApp->icons()->fromTheme(QSL("format-justify-fill")), tr("Newspaper view"), TabBar::Closable);
|
int index = addTab(prev,
|
||||||
|
qApp->icons()->fromTheme(QSL("format-justify-fill")),
|
||||||
|
tr("Newspaper view"),
|
||||||
|
TabBar::TabType::Closable);
|
||||||
|
|
||||||
// NOTE: Do not bring "newspaper" tabs to front anymore.
|
// NOTE: Do not bring "newspaper" tabs to front anymore.
|
||||||
//setCurrentIndex(index);
|
//setCurrentIndex(index);
|
||||||
|
@ -236,13 +242,13 @@ int TabWidget::addBrowser(bool move_after_current, bool make_active, const QUrl&
|
||||||
if (move_after_current) {
|
if (move_after_current) {
|
||||||
// Insert web browser after current tab.
|
// Insert web browser after current tab.
|
||||||
final_index = insertTab(currentIndex() + 1, browser, qApp->icons()->fromTheme(QSL("text-html")),
|
final_index = insertTab(currentIndex() + 1, browser, qApp->icons()->fromTheme(QSL("text-html")),
|
||||||
browser_tab_name, TabBar::Closable);
|
browser_tab_name, TabBar::TabType::Closable);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Add new browser as the last tab.
|
// Add new browser as the last tab.
|
||||||
final_index = addTab(browser, qApp->icons()->fromTheme(QSL("text-html")),
|
final_index = addTab(browser, qApp->icons()->fromTheme(QSL("text-html")),
|
||||||
browser_tab_name,
|
browser_tab_name,
|
||||||
TabBar::Closable);
|
TabBar::TabType::Closable);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make connections.
|
// Make connections.
|
||||||
|
|
|
@ -22,33 +22,27 @@ class TabWidget : public QTabWidget {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// Constructors and destructors.
|
// Constructors and destructors.
|
||||||
explicit TabWidget(QWidget* parent = 0);
|
explicit TabWidget(QWidget* parent = nullptr);
|
||||||
virtual ~TabWidget();
|
virtual ~TabWidget();
|
||||||
|
|
||||||
// Manimulators for tabs.
|
// Manimulators for tabs.
|
||||||
int addTab(TabContent* widget, const QString&,
|
int addTab(TabContent* widget, const QString&,
|
||||||
const TabBar::TabType& type = TabBar::NonClosable);
|
const TabBar::TabType& type = TabBar::TabType::NonClosable);
|
||||||
int addTab(TabContent* widget, const QIcon& icon,
|
int addTab(TabContent* widget, const QIcon& icon,
|
||||||
const QString& label, const TabBar::TabType& type = TabBar::NonClosable);
|
const QString& label, const TabBar::TabType& type = TabBar::TabType::NonClosable);
|
||||||
int insertTab(int index, QWidget* widget, const QString& label,
|
int insertTab(int index, QWidget* widget, const QString& label,
|
||||||
const TabBar::TabType& type = TabBar::Closable);
|
const TabBar::TabType& type = TabBar::TabType::Closable);
|
||||||
int insertTab(int index, QWidget* widget, const QIcon& icon,
|
int insertTab(int index, QWidget* widget, const QIcon& icon,
|
||||||
const QString& label, const TabBar::TabType& type = TabBar::NonClosable);
|
const QString& label, const TabBar::TabType& type = TabBar::TabType::NonClosable);
|
||||||
void removeTab(int index, bool clear_from_memory);
|
void removeTab(int index, bool clear_from_memory);
|
||||||
|
|
||||||
// Returns tab bar.
|
// Returns tab bar.
|
||||||
inline TabBar* tabBar() const {
|
TabBar* tabBar() const;
|
||||||
return static_cast<TabBar*>(QTabWidget::tabBar());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the central widget of this tab.
|
// Returns the central widget of this tab.
|
||||||
inline TabContent* widget(int index) const {
|
TabContent* widget(int index) const;
|
||||||
return static_cast<TabContent*>(QTabWidget::widget(index));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline TabContent* currentWidget() const {
|
TabContent* currentWidget() const;
|
||||||
return static_cast<TabContent*>(QTabWidget::currentWidget());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initializes TabWidget with tabs, this includes initialization
|
// Initializes TabWidget with tabs, this includes initialization
|
||||||
// of main "Feeds" widget.
|
// of main "Feeds" widget.
|
||||||
|
@ -58,21 +52,7 @@ class TabWidget : public QTabWidget {
|
||||||
void setupIcons();
|
void setupIcons();
|
||||||
|
|
||||||
// Accessor to feed/message viewer.
|
// Accessor to feed/message viewer.
|
||||||
inline FeedMessageViewer* feedMessageViewer() const {
|
FeedMessageViewer* feedMessageViewer() const;
|
||||||
return m_feedMessageViewer;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
// Creates necesary connections.
|
|
||||||
void createConnections();
|
|
||||||
|
|
||||||
// Sets up properties of custom corner button.
|
|
||||||
void setupMainMenuButton();
|
|
||||||
|
|
||||||
// Handlers of insertin/removing of tabs.
|
|
||||||
void tabInserted(int index);
|
|
||||||
void tabRemoved(int index);
|
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|
||||||
|
@ -117,10 +97,31 @@ class TabWidget : public QTabWidget {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void indentTabText(int index);
|
void indentTabText(int index);
|
||||||
|
void createConnections();
|
||||||
|
void setupMainMenuButton();
|
||||||
|
|
||||||
|
void tabInserted(int index);
|
||||||
|
void tabRemoved(int index);
|
||||||
|
|
||||||
PlainToolButton* m_btnMainMenu;
|
PlainToolButton* m_btnMainMenu;
|
||||||
QMenu* m_menuMain;
|
QMenu* m_menuMain;
|
||||||
FeedMessageViewer* m_feedMessageViewer;
|
FeedMessageViewer* m_feedMessageViewer;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline TabBar* TabWidget::tabBar() const {
|
||||||
|
return static_cast<TabBar*>(QTabWidget::tabBar());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline TabContent* TabWidget::widget(int index) const {
|
||||||
|
return static_cast<TabContent*>(QTabWidget::widget(index));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline TabContent* TabWidget::currentWidget() const {
|
||||||
|
return static_cast<TabContent*>(QTabWidget::currentWidget());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline FeedMessageViewer* TabWidget::feedMessageViewer() const {
|
||||||
|
return m_feedMessageViewer;
|
||||||
|
}
|
||||||
|
|
||||||
#endif // TABWIDGET_H
|
#endif // TABWIDGET_H
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
#include <QMouseEvent>
|
#include <QMouseEvent>
|
||||||
|
|
||||||
TreeWidget::TreeWidget(QWidget* parent)
|
TreeWidget::TreeWidget(QWidget* parent)
|
||||||
: QTreeWidget(parent), m_refreshAllItemsNeeded(true), m_showMode(ItemsCollapsed) {
|
: QTreeWidget(parent), m_refreshAllItemsNeeded(true), m_showMode(ItemShowMode::ItemsCollapsed) {
|
||||||
connect(this, SIGNAL(itemChanged(QTreeWidgetItem*,int)), this, SLOT(sheduleRefresh()));
|
connect(this, SIGNAL(itemChanged(QTreeWidgetItem*,int)), this, SLOT(sheduleRefresh()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,7 +123,7 @@ void TreeWidget::filterString(const QString& string) {
|
||||||
parentItem->setHidden(false);
|
parentItem->setHidden(false);
|
||||||
|
|
||||||
if (stringIsEmpty) {
|
if (stringIsEmpty) {
|
||||||
parentItem->setExpanded(m_showMode == ItemsExpanded);
|
parentItem->setExpanded(m_showMode == ItemShowMode::ItemsExpanded);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
parentItem->setExpanded(true);
|
parentItem->setExpanded(true);
|
||||||
|
|
|
@ -28,7 +28,10 @@ class TreeWidget : public QTreeWidget {
|
||||||
public:
|
public:
|
||||||
explicit TreeWidget(QWidget* parent = 0);
|
explicit TreeWidget(QWidget* parent = 0);
|
||||||
|
|
||||||
enum ItemShowMode { ItemsCollapsed = 0, ItemsExpanded = 1 };
|
enum class ItemShowMode {
|
||||||
|
ItemsCollapsed = 0,
|
||||||
|
ItemsExpanded = 1
|
||||||
|
};
|
||||||
|
|
||||||
ItemShowMode defaultItemShowMode() {
|
ItemShowMode defaultItemShowMode() {
|
||||||
return m_showMode;
|
return m_showMode;
|
||||||
|
@ -69,7 +72,6 @@ class TreeWidget : public QTreeWidget {
|
||||||
void iterateAllItems(QTreeWidgetItem* parent);
|
void iterateAllItems(QTreeWidgetItem* parent);
|
||||||
|
|
||||||
bool m_refreshAllItemsNeeded;
|
bool m_refreshAllItemsNeeded;
|
||||||
|
|
||||||
QList<QTreeWidgetItem*> m_allTreeItems;
|
QList<QTreeWidgetItem*> m_allTreeItems;
|
||||||
ItemShowMode m_showMode;
|
ItemShowMode m_showMode;
|
||||||
};
|
};
|
||||||
|
|
|
@ -156,19 +156,19 @@ bool WebBrowser::eventFilter(QObject* watched, QEvent* event) {
|
||||||
|
|
||||||
void WebBrowser::receiveMessageStatusChangeRequest(int message_id, WebPage::MessageStatusChange change) {
|
void WebBrowser::receiveMessageStatusChangeRequest(int message_id, WebPage::MessageStatusChange change) {
|
||||||
switch (change) {
|
switch (change) {
|
||||||
case WebPage::MarkRead:
|
case WebPage::MessageStatusChange::MarkRead:
|
||||||
markMessageAsRead(message_id, true);
|
markMessageAsRead(message_id, true);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WebPage::MarkUnread:
|
case WebPage::MessageStatusChange::MarkUnread:
|
||||||
markMessageAsRead(message_id, false);
|
markMessageAsRead(message_id, false);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WebPage::MarkStarred:
|
case WebPage::MessageStatusChange::MarkStarred:
|
||||||
switchMessageImportance(message_id, true);
|
switchMessageImportance(message_id, true);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WebPage::MarkUnstarred:
|
case WebPage::MessageStatusChange::MarkUnstarred:
|
||||||
switchMessageImportance(message_id, false);
|
switchMessageImportance(message_id, false);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -265,16 +265,18 @@ void WebBrowser::markMessageAsRead(int id, bool read) {
|
||||||
|
|
||||||
if (msg != nullptr && m_root->getParentServiceRoot()->onBeforeSetMessagesRead(m_root.data(),
|
if (msg != nullptr && m_root->getParentServiceRoot()->onBeforeSetMessagesRead(m_root.data(),
|
||||||
QList<Message>() << *msg,
|
QList<Message>() << *msg,
|
||||||
read ? RootItem::Read : RootItem::Unread)) {
|
read
|
||||||
|
? RootItem::ReadStatus::Read
|
||||||
|
: RootItem::ReadStatus::Unread)) {
|
||||||
DatabaseQueries::markMessagesReadUnread(qApp->database()->connection(objectName()),
|
DatabaseQueries::markMessagesReadUnread(qApp->database()->connection(objectName()),
|
||||||
QStringList() << QString::number(msg->m_id),
|
QStringList() << QString::number(msg->m_id),
|
||||||
read ? RootItem::Read : RootItem::Unread);
|
read ? RootItem::ReadStatus::Read : RootItem::ReadStatus::Unread);
|
||||||
m_root->getParentServiceRoot()->onAfterSetMessagesRead(m_root.data(),
|
m_root->getParentServiceRoot()->onAfterSetMessagesRead(m_root.data(),
|
||||||
QList<Message>() << *msg,
|
QList<Message>() << *msg,
|
||||||
read ? RootItem::Read : RootItem::Unread);
|
read ? RootItem::ReadStatus::Read : RootItem::ReadStatus::Unread);
|
||||||
emit markMessageRead(msg->m_id, read ? RootItem::Read : RootItem::Unread);
|
emit markMessageRead(msg->m_id, read ? RootItem::ReadStatus::Read : RootItem::ReadStatus::Unread);
|
||||||
|
|
||||||
msg->m_isRead = read ? RootItem::Read : RootItem::Unread;
|
msg->m_isRead = read;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -283,23 +285,24 @@ void WebBrowser::switchMessageImportance(int id, bool checked) {
|
||||||
if (!m_root.isNull()) {
|
if (!m_root.isNull()) {
|
||||||
Message* msg = findMessage(id);
|
Message* msg = findMessage(id);
|
||||||
|
|
||||||
if (msg != nullptr && m_root->getParentServiceRoot()->onBeforeSwitchMessageImportance(m_root.data(),
|
if (msg != nullptr &&
|
||||||
QList<ImportanceChange>() <<
|
m_root->getParentServiceRoot()->onBeforeSwitchMessageImportance(m_root.data(),
|
||||||
ImportanceChange(*msg,
|
QList<ImportanceChange>()
|
||||||
msg
|
<< ImportanceChange(*msg,
|
||||||
->m_isImportant ?
|
msg->m_isImportant
|
||||||
RootItem
|
? RootItem::Importance::NotImportant
|
||||||
::NotImportant :
|
: RootItem::Importance::Important))) {
|
||||||
RootItem
|
|
||||||
::Important))) {
|
|
||||||
DatabaseQueries::switchMessagesImportance(qApp->database()->connection(objectName()),
|
DatabaseQueries::switchMessagesImportance(qApp->database()->connection(objectName()),
|
||||||
QStringList() << QString::number(msg->m_id));
|
QStringList() << QString::number(msg->m_id));
|
||||||
m_root->getParentServiceRoot()->onAfterSwitchMessageImportance(m_root.data(),
|
m_root->getParentServiceRoot()->onAfterSwitchMessageImportance(m_root.data(),
|
||||||
QList<ImportanceChange>() << ImportanceChange(*msg,
|
QList<ImportanceChange>()
|
||||||
|
<< ImportanceChange(*msg,
|
||||||
msg->m_isImportant ?
|
msg->m_isImportant ?
|
||||||
RootItem::NotImportant :
|
RootItem::Importance::NotImportant :
|
||||||
RootItem::Important));
|
RootItem::Importance::Important));
|
||||||
emit markMessageImportant(msg->m_id, msg->m_isImportant ? RootItem::NotImportant : RootItem::Important);
|
emit markMessageImportant(msg->m_id, msg->m_isImportant
|
||||||
|
? RootItem::Importance::NotImportant
|
||||||
|
: RootItem::Importance::Important);
|
||||||
|
|
||||||
msg->m_isImportant = checked;
|
msg->m_isImportant = checked;
|
||||||
}
|
}
|
||||||
|
|
|
@ -109,6 +109,7 @@ HEADERS += core/feeddownloader.h \
|
||||||
miscellaneous/simplecrypt/simplecrypt.h \
|
miscellaneous/simplecrypt/simplecrypt.h \
|
||||||
miscellaneous/skinfactory.h \
|
miscellaneous/skinfactory.h \
|
||||||
miscellaneous/systemfactory.h \
|
miscellaneous/systemfactory.h \
|
||||||
|
miscellaneous/templates.h \
|
||||||
miscellaneous/textfactory.h \
|
miscellaneous/textfactory.h \
|
||||||
network-web/basenetworkaccessmanager.h \
|
network-web/basenetworkaccessmanager.h \
|
||||||
network-web/downloader.h \
|
network-web/downloader.h \
|
||||||
|
@ -417,6 +418,9 @@ else {
|
||||||
SOURCES += $$files(3rd-party/mimesis/*.cpp, false)
|
SOURCES += $$files(3rd-party/mimesis/*.cpp, false)
|
||||||
HEADERS += $$files(3rd-party/mimesis/*.hpp, false)
|
HEADERS += $$files(3rd-party/mimesis/*.hpp, false)
|
||||||
|
|
||||||
|
# Add boolinq.
|
||||||
|
HEADERS += $$files(3rd-party/boolinq/*.h, false)
|
||||||
|
|
||||||
INCLUDEPATH += $$PWD/. \
|
INCLUDEPATH += $$PWD/. \
|
||||||
$$PWD/gui \
|
$$PWD/gui \
|
||||||
$$PWD/gui/dialogs \
|
$$PWD/gui/dialogs \
|
||||||
|
|
|
@ -57,6 +57,8 @@ Application::Application(const QString& id, int& argc, char** argv)
|
||||||
// Setup debug output system.
|
// Setup debug output system.
|
||||||
qInstallMessageHandler(Debugging::debugHandler);
|
qInstallMessageHandler(Debugging::debugHandler);
|
||||||
|
|
||||||
|
determineFirstRuns();
|
||||||
|
|
||||||
//: Abbreviation of language, e.g. en.
|
//: Abbreviation of language, e.g. en.
|
||||||
//: Use ISO 639-1 code here combined with ISO 3166-1 (alpha-2) code.
|
//: Use ISO 639-1 code here combined with ISO 3166-1 (alpha-2) code.
|
||||||
//: Examples: "cs", "en", "it", "cs_CZ", "en_GB", "en_US".
|
//: Examples: "cs", "en", "it", "cs_CZ", "en_GB", "en_US".
|
||||||
|
@ -129,7 +131,7 @@ void Application::showPolls() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::offerChanges() const {
|
void Application::offerChanges() const {
|
||||||
if (isFirstRun() || isFirstRun(APP_VERSION)) {
|
if (isFirstRunCurrentVersion()) {
|
||||||
qApp->showGuiMessage(QSL(APP_NAME), QObject::tr("Welcome to %1.\n\nPlease, check NEW stuff included in this\n"
|
qApp->showGuiMessage(QSL(APP_NAME), QObject::tr("Welcome to %1.\n\nPlease, check NEW stuff included in this\n"
|
||||||
"version by clicking this popup notification.").arg(APP_LONG_NAME),
|
"version by clicking this popup notification.").arg(APP_LONG_NAME),
|
||||||
QSystemTrayIcon::NoIcon, nullptr, false, [] {
|
QSystemTrayIcon::NoIcon, nullptr, false, [] {
|
||||||
|
@ -159,17 +161,11 @@ QList<QAction*> Application::userActions() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Application::isFirstRun() const {
|
bool Application::isFirstRun() const {
|
||||||
return settings()->value(GROUP(General), SETTING(General::FirstRun)).toBool();
|
return m_firstRunEver;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Application::isFirstRun(const QString& version) const {
|
bool Application::isFirstRunCurrentVersion() const {
|
||||||
if (version == APP_VERSION) {
|
return m_firstRunCurrentVersion;
|
||||||
// Check this only if checked version is equal to actual version.
|
|
||||||
return settings()->value(GROUP(General), QString(General::FirstRun) + QL1C('_') + version, true).toBool();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
WebFactory* Application::web() const {
|
WebFactory* Application::web() const {
|
||||||
|
@ -192,12 +188,9 @@ DatabaseFactory* Application::database() {
|
||||||
return m_database;
|
return m_database;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::eliminateFirstRun() {
|
void Application::eliminateFirstRuns() {
|
||||||
settings()->setValue(GROUP(General), General::FirstRun, false);
|
settings()->setValue(GROUP(General), General::FirstRun, false);
|
||||||
}
|
settings()->setValue(GROUP(General), QString(General::FirstRun) + QL1C('_') + APP_VERSION, false);
|
||||||
|
|
||||||
void Application::eliminateFirstRun(const QString& version) {
|
|
||||||
settings()->setValue(GROUP(General), QString(General::FirstRun) + QL1C('_') + version, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::setFeedReader(FeedReader* feed_reader) {
|
void Application::setFeedReader(FeedReader* feed_reader) {
|
||||||
|
@ -253,7 +246,7 @@ QString Application::userDataAppFolder() {
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Application::userDataFolder() {
|
QString Application::userDataFolder() {
|
||||||
if (settings()->type() == SettingsProperties::Portable) {
|
if (settings()->type() == SettingsProperties::SettingsType::Portable) {
|
||||||
return userDataAppFolder();
|
return userDataAppFolder();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -447,9 +440,6 @@ void Application::onAboutToQuit() {
|
||||||
|
|
||||||
m_quitLogicDone = true;
|
m_quitLogicDone = true;
|
||||||
|
|
||||||
eliminateFirstRun();
|
|
||||||
eliminateFirstRun(APP_VERSION);
|
|
||||||
|
|
||||||
#if defined(USE_WEBENGINE)
|
#if defined(USE_WEBENGINE)
|
||||||
AdBlockManager::instance()->save();
|
AdBlockManager::instance()->save();
|
||||||
#endif
|
#endif
|
||||||
|
@ -527,3 +517,13 @@ void Application::onFeedUpdatesFinished(const FeedDownloadResults& results) {
|
||||||
nullptr, false);
|
nullptr, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Application::determineFirstRuns() {
|
||||||
|
m_firstRunEver = settings()->value(GROUP(General),
|
||||||
|
SETTING(General::FirstRun)).toBool();
|
||||||
|
m_firstRunCurrentVersion = settings()->value(GROUP(General),
|
||||||
|
QString(General::FirstRun) + QL1C('_') + APP_VERSION,
|
||||||
|
true).toBool();
|
||||||
|
|
||||||
|
eliminateFirstRuns();
|
||||||
|
}
|
||||||
|
|
|
@ -55,7 +55,6 @@ class RSSGUARD_DLLSPEC Application : public QtSingleApplication {
|
||||||
bool isAlreadyRunning();
|
bool isAlreadyRunning();
|
||||||
|
|
||||||
FeedReader* feedReader();
|
FeedReader* feedReader();
|
||||||
|
|
||||||
void setFeedReader(FeedReader* feed_reader);
|
void setFeedReader(FeedReader* feed_reader);
|
||||||
|
|
||||||
// Globally accessible actions.
|
// Globally accessible actions.
|
||||||
|
@ -64,8 +63,8 @@ class RSSGUARD_DLLSPEC Application : public QtSingleApplication {
|
||||||
// Check whether this application starts for the first time (ever).
|
// Check whether this application starts for the first time (ever).
|
||||||
bool isFirstRun() const;
|
bool isFirstRun() const;
|
||||||
|
|
||||||
// Check whether GIVEN VERSION of the application starts for the first time.
|
// Check whether CURRENT VERSION of the application starts for the first time.
|
||||||
bool isFirstRun(const QString& version) const;
|
bool isFirstRunCurrentVersion() const;
|
||||||
|
|
||||||
WebFactory* web() const;
|
WebFactory* web() const;
|
||||||
SystemFactory* system();
|
SystemFactory* system();
|
||||||
|
@ -139,8 +138,8 @@ class RSSGUARD_DLLSPEC Application : public QtSingleApplication {
|
||||||
void onFeedUpdatesFinished(const FeedDownloadResults& results);
|
void onFeedUpdatesFinished(const FeedDownloadResults& results);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void eliminateFirstRun();
|
void determineFirstRuns();
|
||||||
void eliminateFirstRun(const QString& version);
|
void eliminateFirstRuns();
|
||||||
|
|
||||||
#if defined(USE_WEBENGINE)
|
#if defined(USE_WEBENGINE)
|
||||||
NetworkUrlInterceptor* m_urlInterceptor;
|
NetworkUrlInterceptor* m_urlInterceptor;
|
||||||
|
@ -176,6 +175,8 @@ class RSSGUARD_DLLSPEC Application : public QtSingleApplication {
|
||||||
DatabaseFactory* m_database;
|
DatabaseFactory* m_database;
|
||||||
DownloadManager* m_downloadManager;
|
DownloadManager* m_downloadManager;
|
||||||
bool m_shouldRestart;
|
bool m_shouldRestart;
|
||||||
|
bool m_firstRunEver;
|
||||||
|
bool m_firstRunCurrentVersion;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline Application* Application::instance() {
|
inline Application* Application::instance() {
|
||||||
|
|
|
@ -37,7 +37,7 @@ bool DatabaseQueries::markImportantMessagesReadUnread(const QSqlDatabase& db, in
|
||||||
q.setForwardOnly(true);
|
q.setForwardOnly(true);
|
||||||
q.prepare("UPDATE Messages SET is_read = :read "
|
q.prepare("UPDATE Messages SET is_read = :read "
|
||||||
"WHERE is_important = 1 AND is_deleted = 0 AND is_pdeleted = 0 AND account_id = :account_id;");
|
"WHERE is_important = 1 AND is_deleted = 0 AND is_pdeleted = 0 AND account_id = :account_id;");
|
||||||
q.bindValue(QSL(":read"), read == RootItem::Read ? 1 : 0);
|
q.bindValue(QSL(":read"), read == RootItem::ReadStatus::Read ? 1 : 0);
|
||||||
q.bindValue(QSL(":account_id"), account_id);
|
q.bindValue(QSL(":account_id"), account_id);
|
||||||
return q.exec();
|
return q.exec();
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,7 @@ bool DatabaseQueries::markMessagesReadUnread(const QSqlDatabase& db, const QStri
|
||||||
|
|
||||||
q.setForwardOnly(true);
|
q.setForwardOnly(true);
|
||||||
return q.exec(QString(QSL("UPDATE Messages SET is_read = %2 WHERE id IN (%1);"))
|
return q.exec(QString(QSL("UPDATE Messages SET is_read = %2 WHERE id IN (%1);"))
|
||||||
.arg(ids.join(QSL(", ")), read == RootItem::Read ? QSL("1") : QSL("0")));
|
.arg(ids.join(QSL(", ")), read == RootItem::ReadStatus::Read ? QSL("1") : QSL("0")));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DatabaseQueries::markMessageImportant(const QSqlDatabase& db, int id, RootItem::Importance importance) {
|
bool DatabaseQueries::markMessageImportant(const QSqlDatabase& db, int id, RootItem::Importance importance) {
|
||||||
|
@ -73,7 +73,7 @@ bool DatabaseQueries::markFeedsReadUnread(const QSqlDatabase& db, const QStringL
|
||||||
q.setForwardOnly(true);
|
q.setForwardOnly(true);
|
||||||
q.prepare(QString("UPDATE Messages SET is_read = :read "
|
q.prepare(QString("UPDATE Messages SET is_read = :read "
|
||||||
"WHERE feed IN (%1) AND is_deleted = 0 AND is_pdeleted = 0 AND account_id = :account_id;").arg(ids.join(QSL(", "))));
|
"WHERE feed IN (%1) AND is_deleted = 0 AND is_pdeleted = 0 AND account_id = :account_id;").arg(ids.join(QSL(", "))));
|
||||||
q.bindValue(QSL(":read"), read == RootItem::Read ? 1 : 0);
|
q.bindValue(QSL(":read"), read == RootItem::ReadStatus::Read ? 1 : 0);
|
||||||
q.bindValue(QSL(":account_id"), account_id);
|
q.bindValue(QSL(":account_id"), account_id);
|
||||||
return q.exec();
|
return q.exec();
|
||||||
}
|
}
|
||||||
|
@ -84,7 +84,7 @@ bool DatabaseQueries::markBinReadUnread(const QSqlDatabase& db, int account_id,
|
||||||
q.setForwardOnly(true);
|
q.setForwardOnly(true);
|
||||||
q.prepare("UPDATE Messages SET is_read = :read "
|
q.prepare("UPDATE Messages SET is_read = :read "
|
||||||
"WHERE is_deleted = 1 AND is_pdeleted = 0 AND account_id = :account_id;");
|
"WHERE is_deleted = 1 AND is_pdeleted = 0 AND account_id = :account_id;");
|
||||||
q.bindValue(QSL(":read"), read == RootItem::Read ? 1 : 0);
|
q.bindValue(QSL(":read"), read == RootItem::ReadStatus::Read ? 1 : 0);
|
||||||
q.bindValue(QSL(":account_id"), account_id);
|
q.bindValue(QSL(":account_id"), account_id);
|
||||||
return q.exec();
|
return q.exec();
|
||||||
}
|
}
|
||||||
|
@ -95,7 +95,7 @@ bool DatabaseQueries::markAccountReadUnread(const QSqlDatabase& db, int account_
|
||||||
q.setForwardOnly(true);
|
q.setForwardOnly(true);
|
||||||
q.prepare(QSL("UPDATE Messages SET is_read = :read WHERE is_pdeleted = 0 AND account_id = :account_id;"));
|
q.prepare(QSL("UPDATE Messages SET is_read = :read WHERE is_pdeleted = 0 AND account_id = :account_id;"));
|
||||||
q.bindValue(QSL(":account_id"), account_id);
|
q.bindValue(QSL(":account_id"), account_id);
|
||||||
q.bindValue(QSL(":read"), read == RootItem::Read ? 1 : 0);
|
q.bindValue(QSL(":read"), read == RootItem::ReadStatus::Read ? 1 : 0);
|
||||||
return q.exec();
|
return q.exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -915,7 +915,7 @@ bool DatabaseQueries::storeAccountTree(const QSqlDatabase& db, RootItem* tree_ro
|
||||||
|
|
||||||
// Iterate all children.
|
// Iterate all children.
|
||||||
for (RootItem* child : tree_root->getSubTree()) {
|
for (RootItem* child : tree_root->getSubTree()) {
|
||||||
if (child->kind() == RootItemKind::Category) {
|
if (child->kind() == RootItem::Kind::Category) {
|
||||||
query_category.bindValue(QSL(":parent_id"), child->parent()->id());
|
query_category.bindValue(QSL(":parent_id"), child->parent()->id());
|
||||||
query_category.bindValue(QSL(":title"), child->title());
|
query_category.bindValue(QSL(":title"), child->title());
|
||||||
query_category.bindValue(QSL(":account_id"), account_id);
|
query_category.bindValue(QSL(":account_id"), account_id);
|
||||||
|
@ -928,7 +928,7 @@ bool DatabaseQueries::storeAccountTree(const QSqlDatabase& db, RootItem* tree_ro
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (child->kind() == RootItemKind::Feed) {
|
else if (child->kind() == RootItem::Kind::Feed) {
|
||||||
Feed* feed = child->toFeed();
|
Feed* feed = child->toFeed();
|
||||||
|
|
||||||
query_feed.bindValue(QSL(":title"), feed->title());
|
query_feed.bindValue(QSL(":title"), feed->title());
|
||||||
|
@ -1400,7 +1400,7 @@ bool DatabaseQueries::editStandardFeed(const QSqlDatabase& db, int parent_id, in
|
||||||
|
|
||||||
q.bindValue(QSL(":update_type"), int(auto_update_type));
|
q.bindValue(QSL(":update_type"), int(auto_update_type));
|
||||||
q.bindValue(QSL(":update_interval"), auto_update_interval);
|
q.bindValue(QSL(":update_interval"), auto_update_interval);
|
||||||
q.bindValue(QSL(":type"), feed_format);
|
q.bindValue(QSL(":type"), int(feed_format));
|
||||||
q.bindValue(QSL(":id"), feed_id);
|
q.bindValue(QSL(":id"), feed_id);
|
||||||
|
|
||||||
bool suc = q.exec();
|
bool suc = q.exec();
|
||||||
|
@ -1720,6 +1720,28 @@ bool DatabaseQueries::createTtRssAccount(const QSqlDatabase& db, int id_to_assig
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QStringList DatabaseQueries::getAllRecipients(const QSqlDatabase& db, int account_id) {
|
||||||
|
QSqlQuery query(db);
|
||||||
|
QStringList rec;
|
||||||
|
|
||||||
|
query.prepare(QSL("SELECT DISTINCT author "
|
||||||
|
"FROM Messages "
|
||||||
|
"WHERE account_id = :account_id AND author IS NOT NULL AND author != '' "
|
||||||
|
"ORDER BY lower(author) ASC;"));
|
||||||
|
query.bindValue(QSL(":account_id"), account_id);
|
||||||
|
|
||||||
|
if (query.exec()) {
|
||||||
|
while (query.next()) {
|
||||||
|
rec.append(query.value(0).toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
qWarningNN << "Query for all recipients failed: '" << query.lastError().text() << "'.";
|
||||||
|
}
|
||||||
|
|
||||||
|
return rec;
|
||||||
|
}
|
||||||
|
|
||||||
QList<ServiceRoot*> DatabaseQueries::getGmailAccounts(const QSqlDatabase& db, bool* ok) {
|
QList<ServiceRoot*> DatabaseQueries::getGmailAccounts(const QSqlDatabase& db, bool* ok) {
|
||||||
QSqlQuery query(db);
|
QSqlQuery query(db);
|
||||||
QList<ServiceRoot*> roots;
|
QList<ServiceRoot*> roots;
|
||||||
|
|
|
@ -145,6 +145,7 @@ class DatabaseQueries {
|
||||||
bool force_server_side_feed_update, bool download_only_unread_messages);
|
bool force_server_side_feed_update, bool download_only_unread_messages);
|
||||||
|
|
||||||
// Gmail account.
|
// Gmail account.
|
||||||
|
static QStringList getAllRecipients(const QSqlDatabase& db, int account_id);
|
||||||
static bool deleteGmailAccount(const QSqlDatabase& db, int account_id);
|
static bool deleteGmailAccount(const QSqlDatabase& db, int account_id);
|
||||||
static QList<ServiceRoot*> getGmailAccounts(const QSqlDatabase& db, bool* ok = nullptr);
|
static QList<ServiceRoot*> getGmailAccounts(const QSqlDatabase& db, bool* ok = nullptr);
|
||||||
static bool overwriteGmailAccount(const QSqlDatabase& db, const QString& username, const QString& app_id,
|
static bool overwriteGmailAccount(const QSqlDatabase& db, const QString& username, const QString& app_id,
|
||||||
|
@ -182,10 +183,10 @@ inline void DatabaseQueries::fillFeedData(StandardFeed* feed, const QSqlRecord&
|
||||||
StandardFeed::Type type = static_cast<StandardFeed::Type>(sql_record.value(FDS_DB_TYPE_INDEX).toInt());
|
StandardFeed::Type type = static_cast<StandardFeed::Type>(sql_record.value(FDS_DB_TYPE_INDEX).toInt());
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case StandardFeed::Atom10:
|
case StandardFeed::Type::Atom10:
|
||||||
case StandardFeed::Rdf:
|
case StandardFeed::Type::Rdf:
|
||||||
case StandardFeed::Rss0X:
|
case StandardFeed::Type::Rss0X:
|
||||||
case StandardFeed::Rss2X: {
|
case StandardFeed::Type::Rss2X: {
|
||||||
feed->setType(type);
|
feed->setType(type);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -270,7 +270,7 @@ DVALUE(QString) Downloads::TargetDirectoryDef = IOFactory::getSystemFolder(QStan
|
||||||
|
|
||||||
DKEY Downloads::RemovePolicy = "remove_policy";
|
DKEY Downloads::RemovePolicy = "remove_policy";
|
||||||
|
|
||||||
DVALUE(int) Downloads::RemovePolicyDef = DownloadManager::Never;
|
DVALUE(int) Downloads::RemovePolicyDef = int(DownloadManager::RemovePolicy::Never);
|
||||||
|
|
||||||
DKEY Downloads::TargetExplicitDirectory = "target_explicit_directory";
|
DKEY Downloads::TargetExplicitDirectory = "target_explicit_directory";
|
||||||
|
|
||||||
|
@ -436,7 +436,7 @@ Settings* Settings::setupSettings(QObject* parent) {
|
||||||
new_settings = new Settings(properties.m_absoluteSettingsFileName, QSettings::IniFormat, properties.m_type, parent);
|
new_settings = new Settings(properties.m_absoluteSettingsFileName, QSettings::IniFormat, properties.m_type, parent);
|
||||||
|
|
||||||
// Check if portable settings are available.
|
// Check if portable settings are available.
|
||||||
if (properties.m_type == SettingsProperties::Portable) {
|
if (properties.m_type == SettingsProperties::SettingsType::Portable) {
|
||||||
qDebug("Initializing settings in '%s' (portable way).", qPrintable(QDir::toNativeSeparators(properties.m_absoluteSettingsFileName)));
|
qDebug("Initializing settings in '%s' (portable way).", qPrintable(QDir::toNativeSeparators(properties.m_absoluteSettingsFileName)));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -468,11 +468,11 @@ SettingsProperties Settings::determineProperties() {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (will_we_use_portable_settings) {
|
if (will_we_use_portable_settings) {
|
||||||
properties.m_type = SettingsProperties::Portable;
|
properties.m_type = SettingsProperties::SettingsType::Portable;
|
||||||
properties.m_baseDirectory = app_path;
|
properties.m_baseDirectory = app_path;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
properties.m_type = SettingsProperties::NonPortable;
|
properties.m_type = SettingsProperties::SettingsType::NonPortable;
|
||||||
properties.m_baseDirectory = home_path;
|
properties.m_baseDirectory = home_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,10 +7,11 @@
|
||||||
|
|
||||||
// Describes characteristics of settings.
|
// Describes characteristics of settings.
|
||||||
struct SettingsProperties {
|
struct SettingsProperties {
|
||||||
enum SettingsType {
|
enum class SettingsType {
|
||||||
Portable,
|
Portable,
|
||||||
NonPortable
|
NonPortable
|
||||||
};
|
};
|
||||||
|
|
||||||
SettingsType m_type;
|
SettingsType m_type;
|
||||||
QString m_baseDirectory;
|
QString m_baseDirectory;
|
||||||
QString m_settingsSuffix;
|
QString m_settingsSuffix;
|
||||||
|
|
4
src/librssguard/miscellaneous/templates.h
Executable file
4
src/librssguard/miscellaneous/templates.h
Executable file
|
@ -0,0 +1,4 @@
|
||||||
|
#ifndef TEMPLATES_H
|
||||||
|
#define TEMPLATES_H
|
||||||
|
|
||||||
|
#endif // TEMPLATES_H
|
|
@ -30,7 +30,7 @@
|
||||||
AdBlockTreeWidget::AdBlockTreeWidget(AdBlockSubscription* subscription, QWidget* parent)
|
AdBlockTreeWidget::AdBlockTreeWidget(AdBlockSubscription* subscription, QWidget* parent)
|
||||||
: TreeWidget(parent), m_subscription(subscription), m_topItem(nullptr), m_itemChangingBlock(false) {
|
: TreeWidget(parent), m_subscription(subscription), m_topItem(nullptr), m_itemChangingBlock(false) {
|
||||||
setContextMenuPolicy(Qt::CustomContextMenu);
|
setContextMenuPolicy(Qt::CustomContextMenu);
|
||||||
setDefaultItemShowMode(TreeWidget::ItemsExpanded);
|
setDefaultItemShowMode(TreeWidget::ItemShowMode::ItemsExpanded);
|
||||||
setHeaderHidden(true);
|
setHeaderHidden(true);
|
||||||
setAlternatingRowColors(true);
|
setAlternatingRowColors(true);
|
||||||
setLayoutDirection(Qt::LeftToRight);
|
setLayoutDirection(Qt::LeftToRight);
|
||||||
|
|
|
@ -135,17 +135,14 @@ QString DownloadItem::saveFileName(const QString& directory) const {
|
||||||
QString path;
|
QString path;
|
||||||
|
|
||||||
if (m_reply->hasRawHeader("Content-Disposition")) {
|
if (m_reply->hasRawHeader("Content-Disposition")) {
|
||||||
const QString value = QLatin1String(m_reply->rawHeader("Content-Disposition"));
|
QString value = QLatin1String(m_reply->rawHeader("Content-Disposition"));
|
||||||
const int pos = value.indexOf(QL1S("filename="));
|
QRegularExpression exp(".*filename=?\"([^\"]+)\"?");
|
||||||
|
QRegularExpressionMatch match = exp.match(value);
|
||||||
|
|
||||||
if (pos != -1) {
|
if (match.isValid()) {
|
||||||
QString name = value.mid(pos + 9);
|
QString name = match.captured(1);
|
||||||
|
|
||||||
if (name.startsWith(QL1C('"')) && name.endsWith(QL1C('"'))) {
|
path = QUrl::fromPercentEncoding(name.toLocal8Bit());
|
||||||
name = name.mid(1, name.size() - 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
path = name;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -427,7 +424,7 @@ void DownloadItem::updateInfoAndUrlLabel() {
|
||||||
|
|
||||||
DownloadManager::DownloadManager(QWidget* parent) : TabContent(parent), m_ui(new Ui::DownloadManager),
|
DownloadManager::DownloadManager(QWidget* parent) : TabContent(parent), m_ui(new Ui::DownloadManager),
|
||||||
m_autoSaver(new AutoSaver(this)), m_model(new DownloadModel(this)),
|
m_autoSaver(new AutoSaver(this)), m_model(new DownloadModel(this)),
|
||||||
m_networkManager(new SilentNetworkAccessManager(this)), m_iconProvider(nullptr), m_removePolicy(Never) {
|
m_networkManager(new SilentNetworkAccessManager(this)), m_iconProvider(nullptr), m_removePolicy(RemovePolicy::Never) {
|
||||||
m_ui->setupUi(this);
|
m_ui->setupUi(this);
|
||||||
m_ui->m_viewDownloads->setShowGrid(false);
|
m_ui->m_viewDownloads->setShowGrid(false);
|
||||||
m_ui->m_viewDownloads->verticalHeader()->hide();
|
m_ui->m_viewDownloads->verticalHeader()->hide();
|
||||||
|
@ -585,7 +582,7 @@ void DownloadManager::updateRow(DownloadItem* item) {
|
||||||
// a) It is not downloading and private browsing is enabled.
|
// a) It is not downloading and private browsing is enabled.
|
||||||
// OR
|
// OR
|
||||||
// b) Item is already downloaded and it should be remove from downloader list.
|
// b) Item is already downloaded and it should be remove from downloader list.
|
||||||
bool remove = item->downloadedSuccessfully() && removePolicy() == DownloadManager::OnSuccessfullDownload;
|
bool remove = item->downloadedSuccessfully() && removePolicy() == RemovePolicy::OnSuccessfullDownload;
|
||||||
|
|
||||||
if (remove) {
|
if (remove) {
|
||||||
m_model->removeRow(row);
|
m_model->removeRow(row);
|
||||||
|
@ -608,7 +605,7 @@ void DownloadManager::setRemovePolicy(RemovePolicy policy) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DownloadManager::save() const {
|
void DownloadManager::save() const {
|
||||||
if (m_removePolicy == OnExit) {
|
if (m_removePolicy == RemovePolicy::OnExit) {
|
||||||
// No saving.
|
// No saving.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,7 +94,7 @@ class DownloadManager : public TabContent {
|
||||||
friend class DownloadModel;
|
friend class DownloadModel;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum RemovePolicy {
|
enum class RemovePolicy {
|
||||||
Never,
|
Never,
|
||||||
OnExit,
|
OnExit,
|
||||||
OnSuccessfullDownload
|
OnSuccessfullDownload
|
||||||
|
|
|
@ -27,16 +27,16 @@ void WebPage::javaScriptAlert(const QUrl& securityOrigin, const QString& msg) {
|
||||||
const QString& action = parts.at(1);
|
const QString& action = parts.at(1);
|
||||||
|
|
||||||
if (action == QSL("read")) {
|
if (action == QSL("read")) {
|
||||||
emit messageStatusChangeRequested(message_id, MarkRead);
|
emit messageStatusChangeRequested(message_id, MessageStatusChange::MarkRead);
|
||||||
}
|
}
|
||||||
else if (action == QSL("unread")) {
|
else if (action == QSL("unread")) {
|
||||||
emit messageStatusChangeRequested(message_id, MarkUnread);
|
emit messageStatusChangeRequested(message_id, MessageStatusChange::MarkUnread);
|
||||||
}
|
}
|
||||||
else if (action == QSL("starred")) {
|
else if (action == QSL("starred")) {
|
||||||
emit messageStatusChangeRequested(message_id, MarkStarred);
|
emit messageStatusChangeRequested(message_id, MessageStatusChange::MarkStarred);
|
||||||
}
|
}
|
||||||
else if (action == QSL("unstarred")) {
|
else if (action == QSL("unstarred")) {
|
||||||
emit messageStatusChangeRequested(message_id, MarkUnstarred);
|
emit messageStatusChangeRequested(message_id, MessageStatusChange::MarkUnstarred);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
QWebEnginePage::javaScriptAlert(securityOrigin, msg);
|
QWebEnginePage::javaScriptAlert(securityOrigin, msg);
|
||||||
|
|
|
@ -11,7 +11,7 @@ class WebPage : public QWebEnginePage {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum MessageStatusChange {
|
enum class MessageStatusChange {
|
||||||
MarkRead,
|
MarkRead,
|
||||||
MarkUnread,
|
MarkUnread,
|
||||||
MarkStarred,
|
MarkStarred,
|
||||||
|
|
|
@ -44,7 +44,7 @@ void AccountCheckModel::setRootItem(RootItem* root_item, bool delete_previous_ro
|
||||||
void AccountCheckModel::checkAllItems() {
|
void AccountCheckModel::checkAllItems() {
|
||||||
if (m_rootItem != nullptr) {
|
if (m_rootItem != nullptr) {
|
||||||
for (RootItem* root_child : m_rootItem->childItems()) {
|
for (RootItem* root_child : m_rootItem->childItems()) {
|
||||||
if (root_child->kind() == RootItemKind::Feed || root_child->kind() == RootItemKind::Category) {
|
if (root_child->kind() == RootItem::Kind::Feed || root_child->kind() == RootItem::Kind::Category) {
|
||||||
setItemChecked(root_child, Qt::Checked);
|
setItemChecked(root_child, Qt::Checked);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,7 @@ void AccountCheckModel::checkAllItems() {
|
||||||
void AccountCheckModel::uncheckAllItems() {
|
void AccountCheckModel::uncheckAllItems() {
|
||||||
if (m_rootItem != nullptr) {
|
if (m_rootItem != nullptr) {
|
||||||
for (RootItem* root_child : m_rootItem->childItems()) {
|
for (RootItem* root_child : m_rootItem->childItems()) {
|
||||||
if (root_child->kind() == RootItemKind::Feed || root_child->kind() == RootItemKind::Category) {
|
if (root_child->kind() == RootItem::Kind::Feed || root_child->kind() == RootItem::Kind::Category) {
|
||||||
setData(indexForItem(root_child), Qt::Unchecked, Qt::CheckStateRole);
|
setData(indexForItem(root_child), Qt::Unchecked, Qt::CheckStateRole);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -78,7 +78,7 @@ QModelIndex AccountCheckModel::index(int row, int column, const QModelIndex& par
|
||||||
}
|
}
|
||||||
|
|
||||||
QModelIndex AccountCheckModel::indexForItem(RootItem* item) const {
|
QModelIndex AccountCheckModel::indexForItem(RootItem* item) const {
|
||||||
if (item == nullptr || item->kind() == RootItemKind::ServiceRoot || item->kind() == RootItemKind::Root) {
|
if (item == nullptr || item->kind() == RootItem::Kind::ServiceRoot || item->kind() == RootItem::Kind::Root) {
|
||||||
// Root item lies on invalid index.
|
// Root item lies on invalid index.
|
||||||
return QModelIndex();
|
return QModelIndex();
|
||||||
}
|
}
|
||||||
|
@ -107,7 +107,7 @@ QModelIndex AccountCheckModel::indexForItem(RootItem* item) const {
|
||||||
for (int i = 0; i < row_count; i++) {
|
for (int i = 0; i < row_count; i++) {
|
||||||
RootItem* possible_category = active_item->child(i);
|
RootItem* possible_category = active_item->child(i);
|
||||||
|
|
||||||
if (possible_category->kind() == RootItemKind::Category) {
|
if (possible_category->kind() == RootItem::Kind::Category) {
|
||||||
parents << index(i, 0, active_index);
|
parents << index(i, 0, active_index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -180,10 +180,10 @@ QVariant AccountCheckModel::data(const QModelIndex& index, int role) const {
|
||||||
}
|
}
|
||||||
else if (role == Qt::DisplayRole) {
|
else if (role == Qt::DisplayRole) {
|
||||||
switch (item->kind()) {
|
switch (item->kind()) {
|
||||||
case RootItemKind::Category:
|
case RootItem::Kind::Category:
|
||||||
return QVariant(item->data(index.column(), role).toString() + QSL(" ") + tr("(category)"));
|
return QVariant(item->data(index.column(), role).toString() + QSL(" ") + tr("(category)"));
|
||||||
|
|
||||||
case RootItemKind::Feed:
|
case RootItem::Kind::Feed:
|
||||||
return QVariant(item->data(index.column(), role).toString() + QSL(" ") + tr("(feed)"));
|
return QVariant(item->data(index.column(), role).toString() + QSL(" ") + tr("(feed)"));
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -261,8 +261,8 @@ bool AccountCheckModel::setData(const QModelIndex& index, const QVariant& value,
|
||||||
}
|
}
|
||||||
|
|
||||||
Qt::ItemFlags AccountCheckModel::flags(const QModelIndex& index) const {
|
Qt::ItemFlags AccountCheckModel::flags(const QModelIndex& index) const {
|
||||||
if (!index.isValid() || (itemForIndex(index)->kind() != RootItemKind::Kind::Category &&
|
if (!index.isValid() || (itemForIndex(index)->kind() != RootItem::Kind::Category &&
|
||||||
itemForIndex(index)->kind() != RootItemKind::Kind::Feed)) {
|
itemForIndex(index)->kind() != RootItem::Kind::Feed)) {
|
||||||
return Qt::NoItemFlags;
|
return Qt::NoItemFlags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,9 @@ void CacheForServiceRoot::addMessageStatesToCache(const QList<Message>& ids_of_m
|
||||||
m_cacheSaveMutex->lock();
|
m_cacheSaveMutex->lock();
|
||||||
|
|
||||||
QList<Message>& list_act = m_cachedStatesImportant[importance];
|
QList<Message>& list_act = m_cachedStatesImportant[importance];
|
||||||
QList<Message>& list_other = m_cachedStatesImportant[importance == RootItem::Important ? RootItem::NotImportant : RootItem::Important];
|
QList<Message>& list_other = m_cachedStatesImportant[importance == RootItem::Importance::Important
|
||||||
|
? RootItem::Importance::NotImportant
|
||||||
|
: RootItem::Importance::Important];
|
||||||
|
|
||||||
// Store changes, they will be sent to server later.
|
// Store changes, they will be sent to server later.
|
||||||
list_act.append(ids_of_messages);
|
list_act.append(ids_of_messages);
|
||||||
|
@ -45,7 +47,9 @@ void CacheForServiceRoot::addMessageStatesToCache(const QStringList& ids_of_mess
|
||||||
m_cacheSaveMutex->lock();
|
m_cacheSaveMutex->lock();
|
||||||
|
|
||||||
QStringList& list_act = m_cachedStatesRead[read];
|
QStringList& list_act = m_cachedStatesRead[read];
|
||||||
QStringList& list_other = m_cachedStatesRead[read == RootItem::Read ? RootItem::Unread : RootItem::Read];
|
QStringList& list_other = m_cachedStatesRead[read == RootItem::ReadStatus::Read
|
||||||
|
? RootItem::ReadStatus::Unread
|
||||||
|
: RootItem::ReadStatus::Read];
|
||||||
|
|
||||||
// Store changes, they will be sent to server later.
|
// Store changes, they will be sent to server later.
|
||||||
list_act.append(ids_of_messages);
|
list_act.append(ids_of_messages);
|
||||||
|
@ -134,9 +138,11 @@ QPair<QMap<RootItem::ReadStatus, QStringList>, QMap<RootItem::Importance, QList<
|
||||||
|
|
||||||
// Make copy of changes.
|
// Make copy of changes.
|
||||||
QMap<RootItem::ReadStatus, QStringList> cached_data_read = m_cachedStatesRead;
|
QMap<RootItem::ReadStatus, QStringList> cached_data_read = m_cachedStatesRead;
|
||||||
|
|
||||||
cached_data_read.detach();
|
cached_data_read.detach();
|
||||||
|
|
||||||
QMap<RootItem::Importance, QList<Message>> cached_data_imp = m_cachedStatesImportant;
|
QMap<RootItem::Importance, QList<Message>> cached_data_imp = m_cachedStatesImportant;
|
||||||
|
|
||||||
cached_data_imp.detach();
|
cached_data_imp.detach();
|
||||||
|
|
||||||
clearCache();
|
clearCache();
|
||||||
|
|
|
@ -11,11 +11,11 @@
|
||||||
#include "services/abstract/serviceroot.h"
|
#include "services/abstract/serviceroot.h"
|
||||||
|
|
||||||
Category::Category(RootItem* parent) : RootItem(parent) {
|
Category::Category(RootItem* parent) : RootItem(parent) {
|
||||||
setKind(RootItemKind::Category);
|
setKind(RootItem::Kind::Category);
|
||||||
}
|
}
|
||||||
|
|
||||||
Category::Category(const Category& other) : RootItem(other) {
|
Category::Category(const Category& other) : RootItem(other) {
|
||||||
setKind(RootItemKind::Category);
|
setKind(RootItem::Kind::Category);
|
||||||
}
|
}
|
||||||
|
|
||||||
Category::Category(const QSqlRecord& record) : Category(nullptr) {
|
Category::Category(const QSqlRecord& record) : Category(nullptr) {
|
||||||
|
@ -38,10 +38,10 @@ void Category::updateCounts(bool including_total_count) {
|
||||||
QList<Feed*> feeds;
|
QList<Feed*> feeds;
|
||||||
|
|
||||||
for (RootItem* child : getSubTree()) {
|
for (RootItem* child : getSubTree()) {
|
||||||
if (child->kind() == RootItemKind::Feed) {
|
if (child->kind() == RootItem::Kind::Feed) {
|
||||||
feeds.append(child->toFeed());
|
feeds.append(child->toFeed());
|
||||||
}
|
}
|
||||||
else if (child->kind() != RootItemKind::Category && child->kind() != RootItemKind::ServiceRoot) {
|
else if (child->kind() != RootItem::Kind::Category && child->kind() != RootItem::Kind::ServiceRoot) {
|
||||||
child->updateCounts(including_total_count);
|
child->updateCounts(including_total_count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,10 +17,10 @@
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
|
|
||||||
Feed::Feed(RootItem* parent)
|
Feed::Feed(RootItem* parent)
|
||||||
: RootItem(parent), m_url(QString()), m_status(Normal), m_autoUpdateType(DefaultAutoUpdate),
|
: RootItem(parent), m_url(QString()), m_status(Status::Normal), m_autoUpdateType(AutoUpdateType::DefaultAutoUpdate),
|
||||||
m_autoUpdateInitialInterval(DEFAULT_AUTO_UPDATE_INTERVAL), m_autoUpdateRemainingInterval(DEFAULT_AUTO_UPDATE_INTERVAL),
|
m_autoUpdateInitialInterval(DEFAULT_AUTO_UPDATE_INTERVAL), m_autoUpdateRemainingInterval(DEFAULT_AUTO_UPDATE_INTERVAL),
|
||||||
m_messageFilters(QList<QPointer<MessageFilter>>()) {
|
m_messageFilters(QList<QPointer<MessageFilter>>()) {
|
||||||
setKind(RootItemKind::Feed);
|
setKind(RootItem::Kind::Feed);
|
||||||
}
|
}
|
||||||
|
|
||||||
Feed::Feed(const QSqlRecord& record) : Feed(nullptr) {
|
Feed::Feed(const QSqlRecord& record) : Feed(nullptr) {
|
||||||
|
@ -43,7 +43,7 @@ Feed::Feed(const QSqlRecord& record) : Feed(nullptr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Feed::Feed(const Feed& other) : RootItem(other) {
|
Feed::Feed(const Feed& other) : RootItem(other) {
|
||||||
setKind(RootItemKind::Feed);
|
setKind(RootItem::Kind::Feed);
|
||||||
|
|
||||||
setCountOfAllMessages(other.countOfAllMessages());
|
setCountOfAllMessages(other.countOfAllMessages());
|
||||||
setCountOfUnreadMessages(other.countOfUnreadMessages());
|
setCountOfUnreadMessages(other.countOfUnreadMessages());
|
||||||
|
@ -67,13 +67,13 @@ QVariant Feed::data(int column, int role) const {
|
||||||
switch (role) {
|
switch (role) {
|
||||||
case Qt::ForegroundRole:
|
case Qt::ForegroundRole:
|
||||||
switch (status()) {
|
switch (status()) {
|
||||||
case NewMessages:
|
case Status::NewMessages:
|
||||||
return QColor(Qt::blue);
|
return QColor(Qt::blue);
|
||||||
|
|
||||||
case NetworkError:
|
case Status::NetworkError:
|
||||||
case ParsingError:
|
case Status::ParsingError:
|
||||||
case AuthError:
|
case Status::AuthError:
|
||||||
case OtherError:
|
case Status::OtherError:
|
||||||
return QColor(Qt::red);
|
return QColor(Qt::red);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -102,8 +102,8 @@ void Feed::setCountOfAllMessages(int count_all_messages) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Feed::setCountOfUnreadMessages(int count_unread_messages) {
|
void Feed::setCountOfUnreadMessages(int count_unread_messages) {
|
||||||
if (status() == NewMessages && count_unread_messages < countOfUnreadMessages()) {
|
if (status() == Status::NewMessages && count_unread_messages < countOfUnreadMessages()) {
|
||||||
setStatus(Normal);
|
setStatus(Status::Normal);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_unreadCount = count_unread_messages;
|
m_unreadCount = count_unread_messages;
|
||||||
|
@ -209,7 +209,7 @@ int Feed::updateMessages(const QList<Message>& messages, bool error_during_obtai
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ok) {
|
if (ok) {
|
||||||
setStatus(updated_messages > 0 ? NewMessages : Normal);
|
setStatus(updated_messages > 0 ? Status::NewMessages : Status::Normal);
|
||||||
updateCounts(true);
|
updateCounts(true);
|
||||||
|
|
||||||
if (getParentServiceRoot()->recycleBin() != nullptr && anything_updated) {
|
if (getParentServiceRoot()->recycleBin() != nullptr && anything_updated) {
|
||||||
|
@ -238,13 +238,13 @@ QString Feed::getAutoUpdateStatusDescription() const {
|
||||||
QString auto_update_string;
|
QString auto_update_string;
|
||||||
|
|
||||||
switch (autoUpdateType()) {
|
switch (autoUpdateType()) {
|
||||||
case DontAutoUpdate:
|
case AutoUpdateType::DontAutoUpdate:
|
||||||
|
|
||||||
//: Describes feed auto-update status.
|
//: Describes feed auto-update status.
|
||||||
auto_update_string = tr("does not use auto-update");
|
auto_update_string = tr("does not use auto-update");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DefaultAutoUpdate:
|
case AutoUpdateType::DefaultAutoUpdate:
|
||||||
|
|
||||||
//: Describes feed auto-update status.
|
//: Describes feed auto-update status.
|
||||||
auto_update_string = qApp->feedReader()->autoUpdateEnabled()
|
auto_update_string = qApp->feedReader()->autoUpdateEnabled()
|
||||||
|
@ -254,7 +254,7 @@ QString Feed::getAutoUpdateStatusDescription() const {
|
||||||
: tr("uses global settings (global feed auto-updating is disabled)");
|
: tr("uses global settings (global feed auto-updating is disabled)");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SpecificAutoUpdate:
|
case AutoUpdateType::SpecificAutoUpdate:
|
||||||
default:
|
default:
|
||||||
|
|
||||||
//: Describes feed auto-update status.
|
//: Describes feed auto-update status.
|
||||||
|
|
|
@ -18,7 +18,7 @@ class Feed : public RootItem {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// Specifies the auto-update strategy for the feed.
|
// Specifies the auto-update strategy for the feed.
|
||||||
enum AutoUpdateType {
|
enum class AutoUpdateType {
|
||||||
DontAutoUpdate = 0,
|
DontAutoUpdate = 0,
|
||||||
DefaultAutoUpdate = 1,
|
DefaultAutoUpdate = 1,
|
||||||
SpecificAutoUpdate = 2
|
SpecificAutoUpdate = 2
|
||||||
|
@ -27,7 +27,7 @@ class Feed : public RootItem {
|
||||||
// Specifies the actual "status" of the feed.
|
// Specifies the actual "status" of the feed.
|
||||||
// For example if it has new messages, error
|
// For example if it has new messages, error
|
||||||
// occurred, and so on.
|
// occurred, and so on.
|
||||||
enum Status {
|
enum class Status {
|
||||||
Normal = 0,
|
Normal = 0,
|
||||||
NewMessages = 1,
|
NewMessages = 1,
|
||||||
NetworkError = 2,
|
NetworkError = 2,
|
||||||
|
|
|
@ -59,10 +59,10 @@ int FormFeedDetails::addEditFeed(Feed* input_feed, RootItem* parent_to_select, c
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parent_to_select != nullptr) {
|
if (parent_to_select != nullptr) {
|
||||||
if (parent_to_select->kind() == RootItemKind::Category) {
|
if (parent_to_select->kind() == RootItem::Kind::Category) {
|
||||||
m_ui->m_cmbParentCategory->setCurrentIndex(m_ui->m_cmbParentCategory->findData(QVariant::fromValue((void*) parent_to_select)));
|
m_ui->m_cmbParentCategory->setCurrentIndex(m_ui->m_cmbParentCategory->findData(QVariant::fromValue((void*) parent_to_select)));
|
||||||
}
|
}
|
||||||
else if (parent_to_select->kind() == RootItemKind::Feed) {
|
else if (parent_to_select->kind() == RootItem::Kind::Feed) {
|
||||||
int target_item = m_ui->m_cmbParentCategory->findData(QVariant::fromValue((void*) parent_to_select->parent()));
|
int target_item = m_ui->m_cmbParentCategory->findData(QVariant::fromValue((void*) parent_to_select->parent()));
|
||||||
|
|
||||||
if (target_item >= 0) {
|
if (target_item >= 0) {
|
||||||
|
@ -153,8 +153,8 @@ void FormFeedDetails::onAutoUpdateTypeChanged(int new_index) {
|
||||||
Feed::AutoUpdateType auto_update_type = static_cast<Feed::AutoUpdateType>(m_ui->m_cmbAutoUpdateType->itemData(new_index).toInt());
|
Feed::AutoUpdateType auto_update_type = static_cast<Feed::AutoUpdateType>(m_ui->m_cmbAutoUpdateType->itemData(new_index).toInt());
|
||||||
|
|
||||||
switch (auto_update_type) {
|
switch (auto_update_type) {
|
||||||
case Feed::DontAutoUpdate:
|
case Feed::AutoUpdateType::DontAutoUpdate:
|
||||||
case Feed::DefaultAutoUpdate:
|
case Feed::AutoUpdateType::DefaultAutoUpdate:
|
||||||
m_ui->m_spinAutoUpdateInterval->setEnabled(false);
|
m_ui->m_spinAutoUpdateInterval->setEnabled(false);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -315,10 +315,10 @@ void FormFeedDetails::initialize() {
|
||||||
m_ui->m_txtPassword->lineEdit()->setToolTip(tr("Set password to access the feed."));
|
m_ui->m_txtPassword->lineEdit()->setToolTip(tr("Set password to access the feed."));
|
||||||
|
|
||||||
// Add standard feed types.
|
// Add standard feed types.
|
||||||
m_ui->m_cmbType->addItem(StandardFeed::typeToString(StandardFeed::Atom10), QVariant::fromValue((int) StandardFeed::Atom10));
|
m_ui->m_cmbType->addItem(StandardFeed::typeToString(StandardFeed::Type::Atom10), QVariant::fromValue(int(StandardFeed::Type::Atom10)));
|
||||||
m_ui->m_cmbType->addItem(StandardFeed::typeToString(StandardFeed::Rdf), QVariant::fromValue((int) StandardFeed::Rdf));
|
m_ui->m_cmbType->addItem(StandardFeed::typeToString(StandardFeed::Type::Rdf), QVariant::fromValue(int(StandardFeed::Type::Rdf)));
|
||||||
m_ui->m_cmbType->addItem(StandardFeed::typeToString(StandardFeed::Rss0X), QVariant::fromValue((int) StandardFeed::Rss0X));
|
m_ui->m_cmbType->addItem(StandardFeed::typeToString(StandardFeed::Type::Rss0X), QVariant::fromValue(int(StandardFeed::Type::Rss0X)));
|
||||||
m_ui->m_cmbType->addItem(StandardFeed::typeToString(StandardFeed::Rss2X), QVariant::fromValue((int) StandardFeed::Rss2X));
|
m_ui->m_cmbType->addItem(StandardFeed::typeToString(StandardFeed::Type::Rss2X), QVariant::fromValue(int(StandardFeed::Type::Rss2X)));
|
||||||
|
|
||||||
// Load available encodings.
|
// Load available encodings.
|
||||||
const QList<QByteArray> encodings = QTextCodec::availableCodecs();
|
const QList<QByteArray> encodings = QTextCodec::availableCodecs();
|
||||||
|
@ -358,9 +358,12 @@ void FormFeedDetails::initialize() {
|
||||||
|
|
||||||
// Setup auto-update options.
|
// Setup auto-update options.
|
||||||
m_ui->m_spinAutoUpdateInterval->setValue(DEFAULT_AUTO_UPDATE_INTERVAL);
|
m_ui->m_spinAutoUpdateInterval->setValue(DEFAULT_AUTO_UPDATE_INTERVAL);
|
||||||
m_ui->m_cmbAutoUpdateType->addItem(tr("Auto-update using global interval"), QVariant::fromValue((int) Feed::DefaultAutoUpdate));
|
m_ui->m_cmbAutoUpdateType->addItem(tr("Auto-update using global interval"),
|
||||||
m_ui->m_cmbAutoUpdateType->addItem(tr("Auto-update every"), QVariant::fromValue((int) Feed::SpecificAutoUpdate));
|
QVariant::fromValue(int(Feed::AutoUpdateType::DefaultAutoUpdate)));
|
||||||
m_ui->m_cmbAutoUpdateType->addItem(tr("Do not auto-update at all"), QVariant::fromValue((int) Feed::DontAutoUpdate));
|
m_ui->m_cmbAutoUpdateType->addItem(tr("Auto-update every"),
|
||||||
|
QVariant::fromValue(int(Feed::AutoUpdateType::SpecificAutoUpdate)));
|
||||||
|
m_ui->m_cmbAutoUpdateType->addItem(tr("Do not auto-update at all"),
|
||||||
|
QVariant::fromValue(int(Feed::AutoUpdateType::DontAutoUpdate)));
|
||||||
|
|
||||||
// Set tab order.
|
// Set tab order.
|
||||||
setTabOrder(m_ui->m_cmbParentCategory, m_ui->m_cmbType);
|
setTabOrder(m_ui->m_cmbParentCategory, m_ui->m_cmbType);
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
|
|
||||||
ImportantNode::ImportantNode(RootItem* parent_item) : RootItem(parent_item) {
|
ImportantNode::ImportantNode(RootItem* parent_item) : RootItem(parent_item) {
|
||||||
setKind(RootItemKind::Important);
|
setKind(RootItem::Kind::Important);
|
||||||
setId(ID_IMPORTANT);
|
setId(ID_IMPORTANT);
|
||||||
setIcon(qApp->icons()->fromTheme(QSL("mail-mark-important")));
|
setIcon(qApp->icons()->fromTheme(QSL("mail-mark-important")));
|
||||||
setTitle(tr("Important messages"));
|
setTitle(tr("Important messages"));
|
||||||
|
@ -67,7 +67,7 @@ bool ImportantNode::markAsReadUnread(RootItem::ReadStatus status) {
|
||||||
if (DatabaseQueries::markImportantMessagesReadUnread(database, service->accountId(), status)) {
|
if (DatabaseQueries::markImportantMessagesReadUnread(database, service->accountId(), status)) {
|
||||||
service->updateCounts(true);
|
service->updateCounts(true);
|
||||||
service->itemChanged(getSubTree());
|
service->itemChanged(getSubTree());
|
||||||
service->requestReloadMessageList(status == RootItem::Read);
|
service->requestReloadMessageList(status == RootItem::ReadStatus::Read);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
|
|
||||||
RecycleBin::RecycleBin(RootItem* parent_item) : RootItem(parent_item), m_totalCount(0),
|
RecycleBin::RecycleBin(RootItem* parent_item) : RootItem(parent_item), m_totalCount(0),
|
||||||
m_unreadCount(0) {
|
m_unreadCount(0) {
|
||||||
setKind(RootItemKind::Bin);
|
setKind(RootItem::Kind::Bin);
|
||||||
setId(ID_RECYCLE_BIN);
|
setId(ID_RECYCLE_BIN);
|
||||||
setIcon(qApp->icons()->fromTheme(QSL("user-trash")));
|
setIcon(qApp->icons()->fromTheme(QSL("user-trash")));
|
||||||
setTitle(tr("Recycle bin"));
|
setTitle(tr("Recycle bin"));
|
||||||
|
@ -46,7 +46,7 @@ void RecycleBin::updateCounts(bool update_total_count) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<QAction*> RecycleBin::contextMenu() {
|
QList<QAction*> RecycleBin::contextMenuFeedsList() {
|
||||||
if (m_contextMenu.isEmpty()) {
|
if (m_contextMenu.isEmpty()) {
|
||||||
QAction* restore_action = new QAction(qApp->icons()->fromTheme(QSL("view-refresh")),
|
QAction* restore_action = new QAction(qApp->icons()->fromTheme(QSL("view-refresh")),
|
||||||
tr("Restore recycle bin"),
|
tr("Restore recycle bin"),
|
||||||
|
@ -84,7 +84,7 @@ bool RecycleBin::markAsReadUnread(RootItem::ReadStatus status) {
|
||||||
if (DatabaseQueries::markBinReadUnread(database, parent_root->accountId(), status)) {
|
if (DatabaseQueries::markBinReadUnread(database, parent_root->accountId(), status)) {
|
||||||
updateCounts(false);
|
updateCounts(false);
|
||||||
parent_root->itemChanged(QList<RootItem*>() << this);
|
parent_root->itemChanged(QList<RootItem*>() << this);
|
||||||
parent_root->requestReloadMessageList(status == RootItem::Read);
|
parent_root->requestReloadMessageList(status == RootItem::ReadStatus::Read);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -14,7 +14,7 @@ class RecycleBin : public RootItem {
|
||||||
|
|
||||||
QString additionalTooltip() const;
|
QString additionalTooltip() const;
|
||||||
|
|
||||||
QList<QAction*> contextMenu();
|
QList<QAction*> contextMenuFeedsList();
|
||||||
QList<Message> undeletedMessages() const;
|
QList<Message> undeletedMessages() const;
|
||||||
|
|
||||||
bool markAsReadUnread(ReadStatus status);
|
bool markAsReadUnread(ReadStatus status);
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include "services/abstract/rootitem.h"
|
#include "services/abstract/rootitem.h"
|
||||||
|
|
||||||
|
#include "3rd-party/boolinq/boolinq.h"
|
||||||
#include "miscellaneous/application.h"
|
#include "miscellaneous/application.h"
|
||||||
#include "miscellaneous/iconfactory.h"
|
#include "miscellaneous/iconfactory.h"
|
||||||
#include "services/abstract/category.h"
|
#include "services/abstract/category.h"
|
||||||
|
@ -12,7 +13,7 @@
|
||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
|
|
||||||
RootItem::RootItem(RootItem* parent_item)
|
RootItem::RootItem(RootItem* parent_item)
|
||||||
: QObject(nullptr), m_kind(RootItemKind::Root), m_id(NO_PARENT_CATEGORY), m_customId(QL1S("")),
|
: QObject(nullptr), m_kind(RootItem::Kind::Root), m_id(NO_PARENT_CATEGORY), m_customId(QL1S("")),
|
||||||
m_title(QString()), m_description(QString()), m_keepOnTop(false), m_parentItem(parent_item) {}
|
m_title(QString()), m_description(QString()), m_keepOnTop(false), m_parentItem(parent_item) {}
|
||||||
|
|
||||||
RootItem::RootItem(const RootItem& other) : RootItem(nullptr) {
|
RootItem::RootItem(const RootItem& other) : RootItem(nullptr) {
|
||||||
|
@ -36,7 +37,7 @@ QString RootItem::hashCode() const {
|
||||||
|
|
||||||
return
|
return
|
||||||
QString::number(acc_id) + QL1S("-") +
|
QString::number(acc_id) + QL1S("-") +
|
||||||
QString::number(kind()) + QL1S("-") +
|
QString::number(int(kind())) + QL1S("-") +
|
||||||
QString::number(id());
|
QString::number(id());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,7 +45,7 @@ QString RootItem::additionalTooltip() const {
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<QAction*> RootItem::contextMenu() {
|
QList<QAction*> RootItem::contextMenuFeedsList() {
|
||||||
return QList<QAction*>();
|
return QList<QAction*>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,7 +89,7 @@ bool RootItem::cleanMessages(bool clear_only_read) {
|
||||||
bool result = true;
|
bool result = true;
|
||||||
|
|
||||||
for (RootItem* child : m_childItems) {
|
for (RootItem* child : m_childItems) {
|
||||||
if (child->kind() != RootItemKind::Bin) {
|
if (child->kind() != RootItem::Kind::Bin) {
|
||||||
result &= child->cleanMessages(clear_only_read);
|
result &= child->cleanMessages(clear_only_read);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -173,10 +174,10 @@ QVariant RootItem::data(int column, int role) const {
|
||||||
QIcon ico = icon();
|
QIcon ico = icon();
|
||||||
|
|
||||||
if (ico.isNull()) {
|
if (ico.isNull()) {
|
||||||
if (kind() == RootItemKind::Feed) {
|
if (kind() == RootItem::Kind::Feed) {
|
||||||
return qApp->icons()->fromTheme(QSL("application-rss+xml"));
|
return qApp->icons()->fromTheme(QSL("application-rss+xml"));
|
||||||
}
|
}
|
||||||
else if (kind() == RootItemKind::Category) {
|
else if (kind() == RootItem::Kind::Category) {
|
||||||
return qApp->icons()->fromTheme(QSL("folder"));
|
return qApp->icons()->fromTheme(QSL("folder"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -210,27 +211,15 @@ bool RootItem::performDragDropChange(RootItem* target_item) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int RootItem::countOfUnreadMessages() const {
|
int RootItem::countOfUnreadMessages() const {
|
||||||
int total_count = 0;
|
return boolinq::from(m_childItems).sum([](RootItem* it) {
|
||||||
|
return it->kind() == RootItem::Kind::Important ? 0 : it->countOfUnreadMessages();
|
||||||
for (RootItem* child_item : m_childItems) {
|
});
|
||||||
if (child_item->kind() != RootItemKind::Kind::Important) {
|
|
||||||
total_count += child_item->countOfUnreadMessages();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return total_count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int RootItem::countOfAllMessages() const {
|
int RootItem::countOfAllMessages() const {
|
||||||
int total_count = 0;
|
return boolinq::from(m_childItems).sum([](RootItem* it) {
|
||||||
|
return it->kind() == RootItem::Kind::Important ? 0 : it->countOfAllMessages();
|
||||||
for (RootItem* child_item : m_childItems) {
|
});
|
||||||
if (child_item->kind() != RootItemKind::Kind::Important) {
|
|
||||||
total_count += child_item->countOfAllMessages();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return total_count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RootItem::isChildOf(const RootItem* root) const {
|
bool RootItem::isChildOf(const RootItem* root) const {
|
||||||
|
@ -240,7 +229,7 @@ bool RootItem::isChildOf(const RootItem* root) const {
|
||||||
|
|
||||||
const RootItem* this_item = this;
|
const RootItem* this_item = this;
|
||||||
|
|
||||||
while (this_item->kind() != RootItemKind::Root) {
|
while (this_item->kind() != RootItem::Kind::Root) {
|
||||||
if (root->childItems().contains(const_cast<RootItem* const>(this_item))) {
|
if (root->childItems().contains(const_cast<RootItem* const>(this_item))) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -278,7 +267,7 @@ QList<RootItem*> RootItem::getSubTree() const {
|
||||||
return children;
|
return children;
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<RootItem*> RootItem::getSubTree(RootItemKind::Kind kind_of_item) const {
|
QList<RootItem*> RootItem::getSubTree(RootItem::Kind kind_of_item) const {
|
||||||
QList<RootItem*> children;
|
QList<RootItem*> children;
|
||||||
QList<RootItem*> traversable_items;
|
QList<RootItem*> traversable_items;
|
||||||
|
|
||||||
|
@ -288,7 +277,7 @@ QList<RootItem*> RootItem::getSubTree(RootItemKind::Kind kind_of_item) const {
|
||||||
while (!traversable_items.isEmpty()) {
|
while (!traversable_items.isEmpty()) {
|
||||||
RootItem* active_item = traversable_items.takeFirst();
|
RootItem* active_item = traversable_items.takeFirst();
|
||||||
|
|
||||||
if ((active_item->kind() & kind_of_item) > 0) {
|
if (int(active_item->kind() & kind_of_item) > 0) {
|
||||||
children.append(active_item);
|
children.append(active_item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -308,7 +297,7 @@ QList<Category*> RootItem::getSubTreeCategories() const {
|
||||||
while (!traversable_items.isEmpty()) {
|
while (!traversable_items.isEmpty()) {
|
||||||
RootItem* active_item = traversable_items.takeFirst();
|
RootItem* active_item = traversable_items.takeFirst();
|
||||||
|
|
||||||
if (active_item->kind() == RootItemKind::Category) {
|
if (active_item->kind() == RootItem::Kind::Category) {
|
||||||
children.append(active_item->toCategory());
|
children.append(active_item->toCategory());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -328,7 +317,7 @@ QHash<int, Category*> RootItem::getHashedSubTreeCategories() const {
|
||||||
while (!traversable_items.isEmpty()) {
|
while (!traversable_items.isEmpty()) {
|
||||||
RootItem* active_item = traversable_items.takeFirst();
|
RootItem* active_item = traversable_items.takeFirst();
|
||||||
|
|
||||||
if (active_item->kind() == RootItemKind::Category && !children.contains(active_item->id())) {
|
if (active_item->kind() == RootItem::Kind::Category && !children.contains(active_item->id())) {
|
||||||
children.insert(active_item->id(), active_item->toCategory());
|
children.insert(active_item->id(), active_item->toCategory());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -348,7 +337,7 @@ QHash<QString, Feed*> RootItem::getHashedSubTreeFeeds() const {
|
||||||
while (!traversable_items.isEmpty()) {
|
while (!traversable_items.isEmpty()) {
|
||||||
RootItem* active_item = traversable_items.takeFirst();
|
RootItem* active_item = traversable_items.takeFirst();
|
||||||
|
|
||||||
if (active_item->kind() == RootItemKind::Feed && !children.contains(active_item->customId())) {
|
if (active_item->kind() == RootItem::Kind::Feed && !children.contains(active_item->customId())) {
|
||||||
children.insert(active_item->customId(), active_item->toFeed());
|
children.insert(active_item->customId(), active_item->toFeed());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -368,7 +357,7 @@ QList<Feed*> RootItem::getSubTreeFeeds() const {
|
||||||
while (!traversable_items.isEmpty()) {
|
while (!traversable_items.isEmpty()) {
|
||||||
RootItem* active_item = traversable_items.takeFirst();
|
RootItem* active_item = traversable_items.takeFirst();
|
||||||
|
|
||||||
if (active_item->kind() == RootItemKind::Feed) {
|
if (active_item->kind() == RootItem::Kind::Feed) {
|
||||||
children.append(active_item->toFeed());
|
children.append(active_item->toFeed());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -381,8 +370,8 @@ QList<Feed*> RootItem::getSubTreeFeeds() const {
|
||||||
ServiceRoot* RootItem::getParentServiceRoot() const {
|
ServiceRoot* RootItem::getParentServiceRoot() const {
|
||||||
const RootItem* working_parent = this;
|
const RootItem* working_parent = this;
|
||||||
|
|
||||||
while (working_parent->kind() != RootItemKind::Root) {
|
while (working_parent->kind() != RootItem::Kind::Root) {
|
||||||
if (working_parent->kind() == RootItemKind::ServiceRoot) {
|
if (working_parent->kind() == RootItem::Kind::ServiceRoot) {
|
||||||
return working_parent->toServiceRoot();
|
return working_parent->toServiceRoot();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -393,11 +382,11 @@ ServiceRoot* RootItem::getParentServiceRoot() const {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
RootItemKind::Kind RootItem::kind() const {
|
RootItem::Kind RootItem::kind() const {
|
||||||
return m_kind;
|
return m_kind;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RootItem::setKind(RootItemKind::Kind kind) {
|
void RootItem::setKind(RootItem::Kind kind) {
|
||||||
m_kind = kind;
|
m_kind = kind;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -518,3 +507,11 @@ QDataStream& operator<<(QDataStream& out, const RootItem::Importance& myObj) {
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RootItem::Kind operator|(RootItem::Kind a, RootItem::Kind b) {
|
||||||
|
return static_cast<RootItem::Kind>(static_cast<int>(a) | static_cast<int>(b));
|
||||||
|
}
|
||||||
|
|
||||||
|
RootItem::Kind operator&(RootItem::Kind a, RootItem::Kind b) {
|
||||||
|
return static_cast<RootItem::Kind>(static_cast<int>(a) & static_cast<int>(b));
|
||||||
|
}
|
||||||
|
|
|
@ -14,24 +14,6 @@ class Feed;
|
||||||
class ServiceRoot;
|
class ServiceRoot;
|
||||||
class QAction;
|
class QAction;
|
||||||
|
|
||||||
namespace RootItemKind {
|
|
||||||
// Describes the kind of the item.
|
|
||||||
enum Kind {
|
|
||||||
Root = 1,
|
|
||||||
Bin = 2,
|
|
||||||
Feed = 4,
|
|
||||||
Category = 8,
|
|
||||||
ServiceRoot = 16,
|
|
||||||
Labels = 32,
|
|
||||||
Important = 64
|
|
||||||
};
|
|
||||||
|
|
||||||
inline Kind operator|(Kind a, Kind b) {
|
|
||||||
return static_cast<Kind>(static_cast<int>(a) | static_cast<int>(b));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Represents ROOT item of FeedsModel.
|
// Represents ROOT item of FeedsModel.
|
||||||
// NOTE: This class is derived to add functionality for
|
// NOTE: This class is derived to add functionality for
|
||||||
// all other non-root items of FeedsModel.
|
// all other non-root items of FeedsModel.
|
||||||
|
@ -39,18 +21,29 @@ class RSSGUARD_DLLSPEC RootItem : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum ReadStatus {
|
enum class ReadStatus {
|
||||||
Unread = 0,
|
Unread = 0,
|
||||||
Read = 1
|
Read = 1
|
||||||
};
|
};
|
||||||
|
|
||||||
// Holds statuses for messages
|
// Holds statuses for messages
|
||||||
// to be switched importance (starred).
|
// to be switched importance (starred).
|
||||||
enum Importance {
|
enum class Importance {
|
||||||
NotImportant = 0,
|
NotImportant = 0,
|
||||||
Important = 1
|
Important = 1
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Describes the kind of the item.
|
||||||
|
enum class Kind {
|
||||||
|
Root = 1,
|
||||||
|
Bin = 2,
|
||||||
|
Feed = 4,
|
||||||
|
Category = 8,
|
||||||
|
ServiceRoot = 16,
|
||||||
|
Labels = 32,
|
||||||
|
Important = 64
|
||||||
|
};
|
||||||
|
|
||||||
// Constructors and destructors.
|
// Constructors and destructors.
|
||||||
explicit RootItem(RootItem* parent_item = nullptr);
|
explicit RootItem(RootItem* parent_item = nullptr);
|
||||||
explicit RootItem(const RootItem& other);
|
explicit RootItem(const RootItem& other);
|
||||||
|
@ -63,7 +56,7 @@ class RSSGUARD_DLLSPEC RootItem : public QObject {
|
||||||
// Returns list of specific actions which can be done with the item.
|
// Returns list of specific actions which can be done with the item.
|
||||||
// Do not include general actions here like actions: Mark as read, Update, ...
|
// 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.
|
// NOTE: Ownership of returned actions is not switched to caller, free them when needed.
|
||||||
virtual QList<QAction*> contextMenu();
|
virtual QList<QAction*> contextMenuFeedsList();
|
||||||
|
|
||||||
// Can properties of this item be edited?
|
// Can properties of this item be edited?
|
||||||
virtual bool canBeEdited() const;
|
virtual bool canBeEdited() const;
|
||||||
|
@ -159,7 +152,7 @@ class RSSGUARD_DLLSPEC RootItem : public QObject {
|
||||||
// Returns flat list of all items from subtree where this item is a root.
|
// Returns flat list of all items from subtree where this item is a root.
|
||||||
// Returned list includes this item too.
|
// Returned list includes this item too.
|
||||||
QList<RootItem*> getSubTree() const;
|
QList<RootItem*> getSubTree() const;
|
||||||
QList<RootItem*> getSubTree(RootItemKind::Kind kind_of_item) const;
|
QList<RootItem*> getSubTree(RootItem::Kind kind_of_item) const;
|
||||||
QList<Category*> getSubTreeCategories() const;
|
QList<Category*> getSubTreeCategories() const;
|
||||||
|
|
||||||
// Returns list of categories complemented by their own integer primary ID.
|
// Returns list of categories complemented by their own integer primary ID.
|
||||||
|
@ -172,8 +165,8 @@ class RSSGUARD_DLLSPEC RootItem : public QObject {
|
||||||
// Returns the service root node which is direct or indirect parent of current item.
|
// Returns the service root node which is direct or indirect parent of current item.
|
||||||
ServiceRoot* getParentServiceRoot() const;
|
ServiceRoot* getParentServiceRoot() const;
|
||||||
|
|
||||||
RootItemKind::Kind kind() const;
|
RootItem::Kind kind() const;
|
||||||
void setKind(RootItemKind::Kind kind);
|
void setKind(RootItem::Kind kind);
|
||||||
|
|
||||||
// Each item can have icon.
|
// Each item can have icon.
|
||||||
QIcon icon() const;
|
QIcon icon() const;
|
||||||
|
@ -208,7 +201,7 @@ class RSSGUARD_DLLSPEC RootItem : public QObject {
|
||||||
void setKeepOnTop(bool keep_on_top);
|
void setKeepOnTop(bool keep_on_top);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
RootItemKind::Kind m_kind;
|
RootItem::Kind m_kind;
|
||||||
int m_id;
|
int m_id;
|
||||||
QString m_customId;
|
QString m_customId;
|
||||||
QString m_title;
|
QString m_title;
|
||||||
|
@ -220,6 +213,9 @@ class RSSGUARD_DLLSPEC RootItem : public QObject {
|
||||||
RootItem* m_parentItem;
|
RootItem* m_parentItem;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
RootItem::Kind operator|(RootItem::Kind a, RootItem::Kind b);
|
||||||
|
RootItem::Kind operator&(RootItem::Kind a, RootItem::Kind b);
|
||||||
|
|
||||||
QDataStream& operator<<(QDataStream& out, const RootItem::Importance& myObj);
|
QDataStream& operator<<(QDataStream& out, const RootItem::Importance& myObj);
|
||||||
QDataStream& operator>>(QDataStream& in, RootItem::Importance& myObj);
|
QDataStream& operator>>(QDataStream& in, RootItem::Importance& myObj);
|
||||||
QDataStream& operator<<(QDataStream& out, const RootItem::ReadStatus& myObj);
|
QDataStream& operator<<(QDataStream& out, const RootItem::ReadStatus& myObj);
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
ServiceRoot::ServiceRoot(RootItem* parent)
|
ServiceRoot::ServiceRoot(RootItem* parent)
|
||||||
: RootItem(parent), m_recycleBin(new RecycleBin(this)), m_importantNode(new ImportantNode(this)), m_accountId(NO_PARENT_CATEGORY) {
|
: RootItem(parent), m_recycleBin(new RecycleBin(this)), m_importantNode(new ImportantNode(this)), m_accountId(NO_PARENT_CATEGORY) {
|
||||||
setKind(RootItemKind::ServiceRoot);
|
setKind(RootItem::Kind::ServiceRoot);
|
||||||
setCreationDate(QDateTime::currentDateTime());
|
setCreationDate(QDateTime::currentDateTime());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ bool ServiceRoot::markAsReadUnread(RootItem::ReadStatus status) {
|
||||||
if (DatabaseQueries::markAccountReadUnread(database, accountId(), status)) {
|
if (DatabaseQueries::markAccountReadUnread(database, accountId(), status)) {
|
||||||
updateCounts(false);
|
updateCounts(false);
|
||||||
itemChanged(getSubTree());
|
itemChanged(getSubTree());
|
||||||
requestReloadMessageList(status == RootItem::Read);
|
requestReloadMessageList(status == RootItem::ReadStatus::Read);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -68,12 +68,27 @@ bool ServiceRoot::downloadAttachmentOnMyOwn(const QUrl& url) const {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<QAction*> ServiceRoot::contextMenu() {
|
QList<QAction*> ServiceRoot::contextMenuFeedsList() {
|
||||||
return serviceMenu();
|
return serviceMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QList<QAction*> ServiceRoot::contextMenuMessagesList(const QList<Message>& messages) {
|
||||||
|
Q_UNUSED(messages)
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
QList<QAction*> ServiceRoot::serviceMenu() {
|
QList<QAction*> ServiceRoot::serviceMenu() {
|
||||||
return QList<QAction*>();
|
if (m_serviceMenu.isEmpty() && isSyncable()) {
|
||||||
|
m_actionSyncIn = new QAction(qApp->icons()->fromTheme(QSL("view-refresh")), tr("Sync in"), this);
|
||||||
|
connect(m_actionSyncIn, &QAction::triggered, this, &ServiceRoot::syncIn);
|
||||||
|
m_serviceMenu.append(m_actionSyncIn);
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_serviceMenu;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ServiceRoot::isSyncable() const {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServiceRoot::start(bool freshly_activated) {
|
void ServiceRoot::start(bool freshly_activated) {
|
||||||
|
@ -86,10 +101,10 @@ void ServiceRoot::updateCounts(bool including_total_count) {
|
||||||
QList<Feed*> feeds;
|
QList<Feed*> feeds;
|
||||||
|
|
||||||
for (RootItem* child : getSubTree()) {
|
for (RootItem* child : getSubTree()) {
|
||||||
if (child->kind() == RootItemKind::Feed) {
|
if (child->kind() == RootItem::Kind::Feed) {
|
||||||
feeds.append(child->toFeed());
|
feeds.append(child->toFeed());
|
||||||
}
|
}
|
||||||
else if (child->kind() != RootItemKind::Category && child->kind() != RootItemKind::ServiceRoot) {
|
else if (child->kind() != RootItem::Kind::Category && child->kind() != RootItem::Kind::ServiceRoot) {
|
||||||
child->updateCounts(including_total_count);
|
child->updateCounts(including_total_count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -139,7 +154,7 @@ void ServiceRoot::removeOldAccountFromDatabase(bool including_messages) {
|
||||||
|
|
||||||
void ServiceRoot::cleanAllItemsFromModel() {
|
void ServiceRoot::cleanAllItemsFromModel() {
|
||||||
for (RootItem* top_level_item : childItems()) {
|
for (RootItem* top_level_item : childItems()) {
|
||||||
if (top_level_item->kind() != RootItemKind::Bin && top_level_item->kind() != RootItemKind::Important) {
|
if (top_level_item->kind() != RootItem::Kind::Bin && top_level_item->kind() != RootItem::Kind::Important) {
|
||||||
requestItemRemoval(top_level_item);
|
requestItemRemoval(top_level_item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -264,7 +279,7 @@ QMap<QString, QVariantMap> ServiceRoot::storeCustomFeedsData() {
|
||||||
QVariantMap feed_custom_data;
|
QVariantMap feed_custom_data;
|
||||||
|
|
||||||
feed_custom_data.insert(QSL("auto_update_interval"), feed->autoUpdateInitialInterval());
|
feed_custom_data.insert(QSL("auto_update_interval"), feed->autoUpdateInitialInterval());
|
||||||
feed_custom_data.insert(QSL("auto_update_type"), feed->autoUpdateType());
|
feed_custom_data.insert(QSL("auto_update_type"), int(feed->autoUpdateType()));
|
||||||
feed_custom_data.insert(QSL("msg_filters"), QVariant::fromValue(feed->messageFilters()));
|
feed_custom_data.insert(QSL("msg_filters"), QVariant::fromValue(feed->messageFilters()));
|
||||||
custom_data.insert(feed->customId(), feed_custom_data);
|
custom_data.insert(feed->customId(), feed_custom_data);
|
||||||
}
|
}
|
||||||
|
@ -351,7 +366,7 @@ QStringList ServiceRoot::customIDSOfMessagesForItem(RootItem* item) {
|
||||||
QStringList list;
|
QStringList list;
|
||||||
|
|
||||||
switch (item->kind()) {
|
switch (item->kind()) {
|
||||||
case RootItemKind::Category: {
|
case RootItem::Kind::Category: {
|
||||||
for (RootItem* child : item->childItems()) {
|
for (RootItem* child : item->childItems()) {
|
||||||
list.append(customIDSOfMessagesForItem(child));
|
list.append(customIDSOfMessagesForItem(child));
|
||||||
}
|
}
|
||||||
|
@ -359,28 +374,28 @@ QStringList ServiceRoot::customIDSOfMessagesForItem(RootItem* item) {
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
case RootItemKind::ServiceRoot: {
|
case RootItem::Kind::ServiceRoot: {
|
||||||
QSqlDatabase database = qApp->database()->connection(metaObject()->className());
|
QSqlDatabase database = qApp->database()->connection(metaObject()->className());
|
||||||
|
|
||||||
list = DatabaseQueries::customIdsOfMessagesFromAccount(database, accountId());
|
list = DatabaseQueries::customIdsOfMessagesFromAccount(database, accountId());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case RootItemKind::Bin: {
|
case RootItem::Kind::Bin: {
|
||||||
QSqlDatabase database = qApp->database()->connection(metaObject()->className());
|
QSqlDatabase database = qApp->database()->connection(metaObject()->className());
|
||||||
|
|
||||||
list = DatabaseQueries::customIdsOfMessagesFromBin(database, accountId());
|
list = DatabaseQueries::customIdsOfMessagesFromBin(database, accountId());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case RootItemKind::Feed: {
|
case RootItem::Kind::Feed: {
|
||||||
QSqlDatabase database = qApp->database()->connection(metaObject()->className());
|
QSqlDatabase database = qApp->database()->connection(metaObject()->className());
|
||||||
|
|
||||||
list = DatabaseQueries::customIdsOfMessagesFromFeed(database, item->customId(), accountId());
|
list = DatabaseQueries::customIdsOfMessagesFromFeed(database, item->customId(), accountId());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case RootItemKind::Important: {
|
case RootItem::Kind::Important: {
|
||||||
QSqlDatabase database = qApp->database()->connection(metaObject()->className());
|
QSqlDatabase database = qApp->database()->connection(metaObject()->className());
|
||||||
|
|
||||||
list = DatabaseQueries::customIdsOfImportantMessages(database, accountId());
|
list = DatabaseQueries::customIdsOfImportantMessages(database, accountId());
|
||||||
|
@ -415,7 +430,7 @@ bool ServiceRoot::markFeedsReadUnread(QList<Feed*> items, RootItem::ReadStatus r
|
||||||
}
|
}
|
||||||
|
|
||||||
itemChanged(itemss);
|
itemChanged(itemss);
|
||||||
requestReloadMessageList(read == RootItem::Read);
|
requestReloadMessageList(read == RootItem::ReadStatus::Read);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -476,11 +491,11 @@ void ServiceRoot::setAccountId(int account_id) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ServiceRoot::loadMessagesForItem(RootItem* item, MessagesModel* model) {
|
bool ServiceRoot::loadMessagesForItem(RootItem* item, MessagesModel* model) {
|
||||||
if (item->kind() == RootItemKind::Bin) {
|
if (item->kind() == RootItem::Kind::Bin) {
|
||||||
model->setFilter(QString("Messages.is_deleted = 1 AND Messages.is_pdeleted = 0 AND Messages.account_id = %1")
|
model->setFilter(QString("Messages.is_deleted = 1 AND Messages.is_pdeleted = 0 AND Messages.account_id = %1")
|
||||||
.arg(QString::number(accountId())));
|
.arg(QString::number(accountId())));
|
||||||
}
|
}
|
||||||
else if (item->kind() == RootItemKind::Kind::Important) {
|
else if (item->kind() == RootItem::Kind::Important) {
|
||||||
model->setFilter(QString("Messages.is_important = 1 AND Messages.is_deleted = 0 AND Messages.is_pdeleted = 0 AND Messages.account_id = %1")
|
model->setFilter(QString("Messages.is_important = 1 AND Messages.is_deleted = 0 AND Messages.is_pdeleted = 0 AND Messages.account_id = %1")
|
||||||
.arg(QString::number(accountId())));
|
.arg(QString::number(accountId())));
|
||||||
}
|
}
|
||||||
|
@ -554,7 +569,7 @@ bool ServiceRoot::onBeforeSwitchMessageImportance(RootItem* selected_item, const
|
||||||
QList<Message> mark_unstarred_msgs;
|
QList<Message> mark_unstarred_msgs;
|
||||||
|
|
||||||
for (const ImportanceChange& pair : changes) {
|
for (const ImportanceChange& pair : changes) {
|
||||||
if (pair.second == RootItem::Important) {
|
if (pair.second == RootItem::Importance::Important) {
|
||||||
mark_starred_msgs.append(pair.first);
|
mark_starred_msgs.append(pair.first);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -563,11 +578,11 @@ bool ServiceRoot::onBeforeSwitchMessageImportance(RootItem* selected_item, const
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mark_starred_msgs.isEmpty()) {
|
if (!mark_starred_msgs.isEmpty()) {
|
||||||
cache->addMessageStatesToCache(mark_starred_msgs, RootItem::Important);
|
cache->addMessageStatesToCache(mark_starred_msgs, RootItem::Importance::Important);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mark_unstarred_msgs.isEmpty()) {
|
if (!mark_unstarred_msgs.isEmpty()) {
|
||||||
cache->addMessageStatesToCache(mark_unstarred_msgs, RootItem::NotImportant);
|
cache->addMessageStatesToCache(mark_unstarred_msgs, RootItem::Importance::NotImportant);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,14 +53,20 @@ class ServiceRoot : public RootItem {
|
||||||
// NOTE: Caller does NOT take ownership of created menu!
|
// NOTE: Caller does NOT take ownership of created menu!
|
||||||
virtual QList<QAction*> addItemMenu();
|
virtual QList<QAction*> addItemMenu();
|
||||||
|
|
||||||
// Returns actions to display as context menu.
|
// NOTE: Caller does NOT take ownership of created menu!
|
||||||
QList<QAction*> contextMenu();
|
virtual QList<QAction*> contextMenuFeedsList();
|
||||||
|
|
||||||
|
// NOTE: Caller does NOT take ownership of created menu!
|
||||||
|
virtual QList<QAction*> contextMenuMessagesList(const QList<Message>& messages);
|
||||||
|
|
||||||
// Returns list of specific actions to be shown in main window menu
|
// Returns list of specific actions to be shown in main window menu
|
||||||
// bar in sections "Services -> 'this service'".
|
// bar in sections "Services -> 'this service'".
|
||||||
// NOTE: Caller does NOT take ownership of created menu!
|
// NOTE: Caller does NOT take ownership of created menu!
|
||||||
virtual QList<QAction*> serviceMenu();
|
virtual QList<QAction*> serviceMenu();
|
||||||
|
|
||||||
|
// If plugin uses online synchronization, then returns true.
|
||||||
|
virtual bool isSyncable() const;
|
||||||
|
|
||||||
// Start/stop services.
|
// Start/stop services.
|
||||||
// Start method is called when feed model gets initialized OR after user adds new service.
|
// Start method is called when feed model gets initialized OR after user adds new service.
|
||||||
// Account should synchronously initialize its children (load them from DB is recommended
|
// Account should synchronously initialize its children (load them from DB is recommended
|
||||||
|
@ -204,10 +210,12 @@ class ServiceRoot : public RootItem {
|
||||||
virtual QMap<QString, QVariantMap> storeCustomFeedsData();
|
virtual QMap<QString, QVariantMap> storeCustomFeedsData();
|
||||||
virtual void restoreCustomFeedsData(const QMap<QString, QVariantMap>& data, const QHash<QString, Feed*>& feeds);
|
virtual void restoreCustomFeedsData(const QMap<QString, QVariantMap>& data, const QHash<QString, Feed*>& feeds);
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
RecycleBin* m_recycleBin;
|
RecycleBin* m_recycleBin;
|
||||||
ImportantNode* m_importantNode;
|
ImportantNode* m_importantNode;
|
||||||
int m_accountId;
|
int m_accountId;
|
||||||
|
QAction* m_actionSyncIn;
|
||||||
|
QList<QAction*> m_serviceMenu;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SERVICEROOT_H
|
#endif // SERVICEROOT_H
|
||||||
|
|
|
@ -18,7 +18,8 @@
|
||||||
|
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
|
|
||||||
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) {
|
if (network == nullptr) {
|
||||||
m_network = new GmailNetworkFactory(this);
|
m_network = new GmailNetworkFactory(this);
|
||||||
}
|
}
|
||||||
|
@ -36,6 +37,10 @@ void GmailServiceRoot::updateTitle() {
|
||||||
setTitle(m_network->username() + QSL(" (Gmail)"));
|
setTitle(m_network->username() + QSL(" (Gmail)"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GmailServiceRoot::replyToEmail() {
|
||||||
|
FormAddEditEmail(this, qApp->mainFormWidget()).execForReply(&m_replyToMessage);
|
||||||
|
}
|
||||||
|
|
||||||
RootItem* GmailServiceRoot::obtainNewTreeForSyncIn() const {
|
RootItem* GmailServiceRoot::obtainNewTreeForSyncIn() const {
|
||||||
auto* root = new RootItem();
|
auto* root = new RootItem();
|
||||||
GmailFeed* inbox = new GmailFeed(tr("Inbox"), QSL(GMAIL_SYSTEM_LABEL_INBOX), qApp->icons()->fromTheme(QSL("mail-inbox")), root);
|
GmailFeed* inbox = new GmailFeed(tr("Inbox"), QSL(GMAIL_SYSTEM_LABEL_INBOX), qApp->icons()->fromTheme(QSL("mail-inbox")), root);
|
||||||
|
@ -128,8 +133,26 @@ bool GmailServiceRoot::downloadAttachmentOnMyOwn(const QUrl& url) const {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QList<QAction*> GmailServiceRoot::contextMenuMessagesList(const QList<Message>& messages) {
|
||||||
|
if (messages.size() == 1) {
|
||||||
|
m_replyToMessage = messages.at(0);
|
||||||
|
|
||||||
|
if (m_actionReply == nullptr) {
|
||||||
|
m_actionReply = new QAction(qApp->icons()->fromTheme(QSL("mail-reply-sender")), tr("Reply to this message"), this);
|
||||||
|
connect(m_actionReply, &QAction::triggered, this, &GmailServiceRoot::replyToEmail);
|
||||||
|
}
|
||||||
|
|
||||||
|
return { m_actionReply };
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QList<QAction*> GmailServiceRoot::serviceMenu() {
|
QList<QAction*> GmailServiceRoot::serviceMenu() {
|
||||||
if (m_serviceMenu.isEmpty()) {
|
if (m_serviceMenu.isEmpty()) {
|
||||||
|
ServiceRoot::serviceMenu();
|
||||||
|
|
||||||
QAction* act_new_email = new QAction(qApp->icons()->fromTheme(QSL("mail-message-new")), tr("Write new e-mail message"), this);
|
QAction* act_new_email = new QAction(qApp->icons()->fromTheme(QSL("mail-message-new")), tr("Write new e-mail message"), this);
|
||||||
|
|
||||||
connect(act_new_email, &QAction::triggered, this, &GmailServiceRoot::writeNewEmail);
|
connect(act_new_email, &QAction::triggered, this, &GmailServiceRoot::writeNewEmail);
|
||||||
|
@ -139,6 +162,10 @@ QList<QAction*> GmailServiceRoot::serviceMenu() {
|
||||||
return m_serviceMenu;
|
return m_serviceMenu;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GmailServiceRoot::isSyncable() const {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool GmailServiceRoot::canBeEdited() const {
|
bool GmailServiceRoot::canBeEdited() const {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,9 @@ class GmailServiceRoot : public ServiceRoot, public CacheForServiceRoot {
|
||||||
void setNetwork(GmailNetworkFactory* network);
|
void setNetwork(GmailNetworkFactory* network);
|
||||||
GmailNetworkFactory* network() const;
|
GmailNetworkFactory* network() const;
|
||||||
|
|
||||||
|
QList<QAction*> contextMenuMessagesList(const QList<Message>& messages);
|
||||||
QList<QAction*> serviceMenu();
|
QList<QAction*> serviceMenu();
|
||||||
|
bool isSyncable() const;
|
||||||
bool canBeEdited() const;
|
bool canBeEdited() const;
|
||||||
bool editViaGui();
|
bool editViaGui();
|
||||||
bool canBeDeleted() const;
|
bool canBeDeleted() const;
|
||||||
|
@ -40,6 +42,9 @@ class GmailServiceRoot : public ServiceRoot, public CacheForServiceRoot {
|
||||||
public slots:
|
public slots:
|
||||||
void updateTitle();
|
void updateTitle();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void replyToEmail();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
RootItem* obtainNewTreeForSyncIn() const;
|
RootItem* obtainNewTreeForSyncIn() const;
|
||||||
|
|
||||||
|
@ -48,9 +53,9 @@ class GmailServiceRoot : public ServiceRoot, public CacheForServiceRoot {
|
||||||
void loadFromDatabase();
|
void loadFromDatabase();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QList<QAction*> m_serviceMenu;
|
|
||||||
GmailNetworkFactory* m_network;
|
GmailNetworkFactory* m_network;
|
||||||
|
QAction* m_actionReply;
|
||||||
|
Message m_replyToMessage;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline void GmailServiceRoot::setNetwork(GmailNetworkFactory* network) {
|
inline void GmailServiceRoot::setNetwork(GmailNetworkFactory* network) {
|
||||||
|
|
|
@ -61,5 +61,9 @@ void EmailRecipientControl::setPossibleRecipients(const QStringList& rec) {
|
||||||
|
|
||||||
QCompleter* cmpl = new QCompleter(rec, m_txtRecipient);
|
QCompleter* cmpl = new QCompleter(rec, m_txtRecipient);
|
||||||
|
|
||||||
|
cmpl->setFilterMode(Qt::MatchFlag::MatchContains);
|
||||||
|
cmpl->setCaseSensitivity(Qt::CaseSensitivity::CaseInsensitive);
|
||||||
|
cmpl->setCompletionMode(QCompleter::CompletionMode::UnfilteredPopupCompletion);
|
||||||
|
|
||||||
m_txtRecipient->setCompleter(cmpl);
|
m_txtRecipient->setCompleter(cmpl);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,12 +7,18 @@
|
||||||
#include "gui/guiutilities.h"
|
#include "gui/guiutilities.h"
|
||||||
#include "gui/messagebox.h"
|
#include "gui/messagebox.h"
|
||||||
#include "miscellaneous/application.h"
|
#include "miscellaneous/application.h"
|
||||||
|
#include "miscellaneous/databasequeries.h"
|
||||||
#include "miscellaneous/iconfactory.h"
|
#include "miscellaneous/iconfactory.h"
|
||||||
#include "services/gmail/gmailserviceroot.h"
|
#include "services/gmail/gmailserviceroot.h"
|
||||||
#include "services/gmail/gui/emailrecipientcontrol.h"
|
#include "services/gmail/gui/emailrecipientcontrol.h"
|
||||||
#include "services/gmail/network/gmailnetworkfactory.h"
|
#include "services/gmail/network/gmailnetworkfactory.h"
|
||||||
|
|
||||||
FormAddEditEmail::FormAddEditEmail(GmailServiceRoot* root, QWidget* parent) : QDialog(parent), m_root(root) {
|
#include <QtConcurrent/QtConcurrentRun>
|
||||||
|
|
||||||
|
#include <QCloseEvent>
|
||||||
|
|
||||||
|
FormAddEditEmail::FormAddEditEmail(GmailServiceRoot* root, QWidget* parent)
|
||||||
|
: QDialog(parent), m_root(root), m_originalMessage(nullptr), m_possibleRecipients({}) {
|
||||||
m_ui.setupUi(this);
|
m_ui.setupUi(this);
|
||||||
|
|
||||||
GuiUtilities::applyDialogProperties(*this, qApp->icons()->fromTheme(QSL("mail-message-new")));
|
GuiUtilities::applyDialogProperties(*this, qApp->icons()->fromTheme(QSL("mail-message-new")));
|
||||||
|
@ -32,6 +38,14 @@ FormAddEditEmail::FormAddEditEmail(GmailServiceRoot* root, QWidget* parent) : QD
|
||||||
&QPushButton::clicked,
|
&QPushButton::clicked,
|
||||||
this,
|
this,
|
||||||
&FormAddEditEmail::onOkClicked);
|
&FormAddEditEmail::onOkClicked);
|
||||||
|
|
||||||
|
QSqlDatabase db = qApp->database()->connection(metaObject()->className());
|
||||||
|
|
||||||
|
m_possibleRecipients = DatabaseQueries::getAllRecipients(db, m_root->accountId());
|
||||||
|
|
||||||
|
for (auto* rec: recipientControls()) {
|
||||||
|
rec->setPossibleRecipients(m_possibleRecipients);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FormAddEditEmail::execForAdd() {
|
void FormAddEditEmail::execForAdd() {
|
||||||
|
@ -39,6 +53,14 @@ void FormAddEditEmail::execForAdd() {
|
||||||
exec();
|
exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FormAddEditEmail::execForReply(Message* original_message) {
|
||||||
|
m_originalMessage = original_message;
|
||||||
|
|
||||||
|
addRecipientRow(m_originalMessage->m_author);
|
||||||
|
m_ui.m_txtSubject->setText(QSL("Re: %1").arg(m_originalMessage->m_title));
|
||||||
|
exec();
|
||||||
|
}
|
||||||
|
|
||||||
void FormAddEditEmail::removeRecipientRow() {
|
void FormAddEditEmail::removeRecipientRow() {
|
||||||
auto* sndr = static_cast<EmailRecipientControl*>(sender());
|
auto* sndr = static_cast<EmailRecipientControl*>(sender());
|
||||||
|
|
||||||
|
@ -103,15 +125,8 @@ void FormAddEditEmail::onOkClicked() {
|
||||||
msg.set_plain(m_ui.m_txtMessage->toPlainText().toStdString());
|
msg.set_plain(m_ui.m_txtMessage->toPlainText().toStdString());
|
||||||
msg.set_header("Content-Type", "text/plain; charset=utf-8");
|
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 {
|
try {
|
||||||
m_root->network()->sendEmail(msg);
|
m_root->network()->sendEmail(msg, m_originalMessage);
|
||||||
accept();
|
accept();
|
||||||
}
|
}
|
||||||
catch (const ApplicationException& ex) {
|
catch (const ApplicationException& ex) {
|
||||||
|
@ -127,13 +142,7 @@ void FormAddEditEmail::addRecipientRow(const QString& recipient) {
|
||||||
|
|
||||||
connect(mail_rec, &EmailRecipientControl::removalRequested, this, &FormAddEditEmail::removeRecipientRow);
|
connect(mail_rec, &EmailRecipientControl::removalRequested, this, &FormAddEditEmail::removeRecipientRow);
|
||||||
|
|
||||||
try {
|
mail_rec->setPossibleRecipients(m_possibleRecipients);
|
||||||
QStringList rec = m_root->network()->getAllRecipients();
|
|
||||||
|
|
||||||
mail_rec->setPossibleRecipients(rec);
|
|
||||||
}
|
|
||||||
catch (const ApplicationException& ex) {}
|
|
||||||
|
|
||||||
m_ui.m_layout->insertRow(m_ui.m_layout->count() - 5, mail_rec);
|
m_ui.m_layout->insertRow(m_ui.m_layout->count() - 5, mail_rec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ class FormAddEditEmail : public QDialog {
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void execForAdd();
|
void execForAdd();
|
||||||
|
void execForReply(Message* original_message);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void removeRecipientRow();
|
void removeRecipientRow();
|
||||||
|
@ -38,6 +39,7 @@ class FormAddEditEmail : public QDialog {
|
||||||
Ui::FormAddEditEmail m_ui;
|
Ui::FormAddEditEmail m_ui;
|
||||||
QList<EmailRecipientControl*> m_recipientControls;
|
QList<EmailRecipientControl*> m_recipientControls;
|
||||||
Message* m_originalMessage;
|
Message* m_originalMessage;
|
||||||
|
QStringList m_possibleRecipients;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // FORMADDEDITEMAIL_H
|
#endif // FORMADDEDITEMAIL_H
|
||||||
|
|
|
@ -52,11 +52,29 @@ void GmailNetworkFactory::setBatchSize(int batch_size) {
|
||||||
m_batchSize = 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();
|
QString bearer = m_oauth2->bearer().toLocal8Bit();
|
||||||
|
|
||||||
if (bearer.isEmpty()) {
|
if (bearer.isEmpty()) {
|
||||||
throw ApplicationException(tr("you aren't logged in"));
|
//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")).toStdString();
|
||||||
|
msg["In-Reply-To"] = metadata.value(QSL("Message-ID")).toStdString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QString rfc_email = QString::fromStdString(msg.to_string());
|
QString rfc_email = QString::fromStdString(msg.to_string());
|
||||||
|
@ -415,89 +433,45 @@ bool GmailNetworkFactory::fillFullMessage(Message& msg, const QJsonObject& json,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList GmailNetworkFactory::getAllRecipients() {
|
QMap<QString, QString> GmailNetworkFactory::getMessageMetadata(const QString& msg_id, const QStringList& metadata) {
|
||||||
QString bearer = m_oauth2->bearer().toLocal8Bit();
|
QString bearer = m_oauth2->bearer();
|
||||||
|
|
||||||
if (bearer.isEmpty()) {
|
if (bearer.isEmpty()) {
|
||||||
throw ApplicationException(tr("not logged-in"));
|
throw ApplicationException(tr("you are not logged in"));
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList recipients;
|
|
||||||
QList<QPair<QByteArray, QByteArray>> headers;
|
QList<QPair<QByteArray, QByteArray>> headers;
|
||||||
|
QByteArray output;
|
||||||
|
int timeout = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)).toInt();
|
||||||
|
|
||||||
headers.append(QPair<QByteArray, QByteArray>(QString(HTTP_HEADERS_AUTHORIZATION).toLocal8Bit(),
|
headers.append(QPair<QByteArray, QByteArray>(QString(HTTP_HEADERS_AUTHORIZATION).toLocal8Bit(),
|
||||||
m_oauth2->bearer().toLocal8Bit()));
|
bearer.toLocal8Bit()));
|
||||||
headers.append(QPair<QByteArray, QByteArray>(QString(HTTP_HEADERS_CONTENT_TYPE).toLocal8Bit(),
|
|
||||||
QString(GMAIL_CONTENT_TYPE_JSON).toLocal8Bit()));
|
|
||||||
|
|
||||||
int timeout = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)).toInt();
|
QString query = QString("%1/%2?format=metadata&metadataHeaders=%3").arg(GMAIL_API_MSGS_LIST,
|
||||||
QByteArray msg_list_data;
|
msg_id,
|
||||||
|
metadata.join(QSL("&metadataHeaders=")));
|
||||||
// TODO: Cyklicky!!
|
NetworkResult res = NetworkFactory::performNetworkOperation(query,
|
||||||
auto list_res = NetworkFactory::performNetworkOperation(GMAIL_API_MSGS_LIST,
|
|
||||||
timeout,
|
timeout,
|
||||||
QByteArray(),
|
QByteArray(),
|
||||||
msg_list_data,
|
output,
|
||||||
QNetworkAccessManager::Operation::GetOperation,
|
QNetworkAccessManager::Operation::GetOperation,
|
||||||
headers);
|
headers);
|
||||||
|
|
||||||
if (list_res.first != QNetworkReply::NetworkError::NoError) {
|
|
||||||
throw ApplicationException(tr("comm error when asking for recipients"));
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonDocument json_list = QJsonDocument::fromJson(msg_list_data);
|
|
||||||
QStringList message_ids;
|
|
||||||
|
|
||||||
for (const auto& msg_nod : json_list.object()["messages"].toArray()) {
|
|
||||||
message_ids.append(msg_nod.toObject()["id"].toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
auto* multi = new QHttpMultiPart();
|
|
||||||
|
|
||||||
multi->setContentType(QHttpMultiPart::ContentType::MixedType);
|
|
||||||
|
|
||||||
for (const QString& msg : message_ids) {
|
|
||||||
QHttpPart part;
|
|
||||||
|
|
||||||
part.setRawHeader(HTTP_HEADERS_CONTENT_TYPE, GMAIL_CONTENT_TYPE_HTTP);
|
|
||||||
QString full_msg_endpoint = QString("GET /gmail/v1/users/me/messages/%1?metadataHeaders=From&metadataHeaders=To&format=metadata\r\n").arg(msg);
|
|
||||||
|
|
||||||
part.setBody(full_msg_endpoint.toUtf8());
|
|
||||||
multi->append(part);
|
|
||||||
}
|
|
||||||
|
|
||||||
QList<HttpResponse> output;
|
|
||||||
|
|
||||||
headers.removeLast();
|
|
||||||
|
|
||||||
NetworkResult res = NetworkFactory::performNetworkOperation(GMAIL_API_BATCH,
|
|
||||||
timeout,
|
|
||||||
multi,
|
|
||||||
output,
|
|
||||||
QNetworkAccessManager::Operation::PostOperation,
|
|
||||||
headers);
|
|
||||||
|
|
||||||
if (res.first == QNetworkReply::NetworkError::NoError) {
|
if (res.first == QNetworkReply::NetworkError::NoError) {
|
||||||
// We parse each part of HTTP response (it contains HTTP headers and payload with msg full data).
|
QJsonDocument doc = QJsonDocument::fromJson(output);
|
||||||
for (const HttpResponse& part : output) {
|
QMap<QString, QString> result;
|
||||||
QJsonObject msg_doc = QJsonDocument::fromJson(part.body().toUtf8()).object();
|
auto headers = doc.object()["payload"].toObject()["headers"].toArray();
|
||||||
auto headers = msg_doc["payload"].toObject()["headers"].toArray();
|
|
||||||
|
|
||||||
if (headers.size() >= 2) {
|
for (const auto& header : headers) {
|
||||||
for (const auto& head : headers) {
|
QJsonObject obj_header = header.toObject();
|
||||||
auto val = head.toObject()["value"].toString();
|
|
||||||
|
|
||||||
if (!recipients.contains(val)) {
|
result.insert(obj_header["name"].toString(), obj_header["value"].toString());
|
||||||
recipients.append(val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return recipients;
|
return result;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throw ApplicationException(tr("comm error when asking for recipients"));
|
throw ApplicationException(tr("failed to get metadata"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,10 +36,7 @@ class GmailNetworkFactory : public QObject {
|
||||||
void setBatchSize(int batch_size);
|
void setBatchSize(int batch_size);
|
||||||
|
|
||||||
// Sends e-mail, returns its ID.
|
// 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();
|
|
||||||
|
|
||||||
Downloader* downloadAttachment(const QString& msg_id, const QString& attachment_id);
|
Downloader* downloadAttachment(const QString& msg_id, const QString& attachment_id);
|
||||||
|
|
||||||
|
@ -53,6 +50,7 @@ class GmailNetworkFactory : public QObject {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool fillFullMessage(Message& msg, const QJsonObject& json, const QString& feed_id);
|
bool fillFullMessage(Message& msg, const QJsonObject& json, const QString& feed_id);
|
||||||
|
QMap<QString, QString> getMessageMetadata(const QString& msg_id, const QStringList& metadata);
|
||||||
bool obtainAndDecodeFullMessages(const QList<Message>& lite_messages, const QString& feed_id, QList<Message>& full_messages);
|
bool obtainAndDecodeFullMessages(const QList<Message>& lite_messages, const QString& feed_id, QList<Message>& full_messages);
|
||||||
QList<Message> decodeLiteMessages(const QString& messages_json_data, const QString& stream_id, QString& next_page_token);
|
QList<Message> decodeLiteMessages(const QString& messages_json_data, const QString& stream_id, QString& next_page_token);
|
||||||
|
|
||||||
|
|
|
@ -82,6 +82,10 @@ void InoreaderServiceRoot::saveAccountDataToDatabase() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool InoreaderServiceRoot::isSyncable() const {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool InoreaderServiceRoot::canBeEdited() const {
|
bool InoreaderServiceRoot::canBeEdited() const {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -119,17 +123,6 @@ void InoreaderServiceRoot::stop() {
|
||||||
saveCacheToFile(accountId());
|
saveCacheToFile(accountId());
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<QAction*> InoreaderServiceRoot::serviceMenu() {
|
|
||||||
if (m_serviceMenu.isEmpty()) {
|
|
||||||
QAction* act_sync_in = new QAction(qApp->icons()->fromTheme(QSL("view-refresh")), tr("Sync in"), this);
|
|
||||||
|
|
||||||
connect(act_sync_in, &QAction::triggered, this, &InoreaderServiceRoot::syncIn);
|
|
||||||
m_serviceMenu.append(act_sync_in);
|
|
||||||
}
|
|
||||||
|
|
||||||
return m_serviceMenu;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString InoreaderServiceRoot::code() const {
|
QString InoreaderServiceRoot::code() const {
|
||||||
return InoreaderEntryPoint().code();
|
return InoreaderEntryPoint().code();
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ class InoreaderServiceRoot : public ServiceRoot, public CacheForServiceRoot {
|
||||||
void setNetwork(InoreaderNetworkFactory* network);
|
void setNetwork(InoreaderNetworkFactory* network);
|
||||||
InoreaderNetworkFactory* network() const;
|
InoreaderNetworkFactory* network() const;
|
||||||
|
|
||||||
|
bool isSyncable() const;
|
||||||
bool canBeEdited() const;
|
bool canBeEdited() const;
|
||||||
bool editViaGui();
|
bool editViaGui();
|
||||||
bool canBeDeleted() const;
|
bool canBeDeleted() const;
|
||||||
|
@ -43,10 +44,8 @@ class InoreaderServiceRoot : public ServiceRoot, public CacheForServiceRoot {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void loadFromDatabase();
|
void loadFromDatabase();
|
||||||
QList<QAction*> serviceMenu();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QList<QAction*> m_serviceMenu;
|
|
||||||
InoreaderNetworkFactory* m_network;
|
InoreaderNetworkFactory* m_network;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -107,7 +107,7 @@ void FormEditOwnCloudAccount::performTest() {
|
||||||
if (!SystemFactory::isVersionEqualOrNewer(result.version(), OWNCLOUD_MIN_VERSION)) {
|
if (!SystemFactory::isVersionEqualOrNewer(result.version(), OWNCLOUD_MIN_VERSION)) {
|
||||||
m_ui->m_lblTestResult->setStatus(WidgetWithStatus::StatusType::Error,
|
m_ui->m_lblTestResult->setStatus(WidgetWithStatus::StatusType::Error,
|
||||||
tr(
|
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(),
|
result.version(),
|
||||||
OWNCLOUD_MIN_VERSION),
|
OWNCLOUD_MIN_VERSION),
|
||||||
tr("Selected Nextcloud News server is running unsupported version."));
|
tr("Selected Nextcloud News server is running unsupported version."));
|
||||||
|
|
|
@ -52,7 +52,7 @@ void FormOwnCloudFeedDetails::apply() {
|
||||||
else {
|
else {
|
||||||
const RootItem* parent = static_cast<RootItem*>(m_ui->m_cmbParentCategory->itemData(
|
const RootItem* parent = static_cast<RootItem*>(m_ui->m_cmbParentCategory->itemData(
|
||||||
m_ui->m_cmbParentCategory->currentIndex()).value<void*>());
|
m_ui->m_cmbParentCategory->currentIndex()).value<void*>());
|
||||||
const int category_id = parent->kind() == RootItemKind::ServiceRoot ? 0 : parent->customId().toInt();
|
const int category_id = parent->kind() == RootItem::Kind::ServiceRoot ? 0 : parent->customId().toInt();
|
||||||
const bool response = qobject_cast<OwnCloudServiceRoot*>(m_serviceRoot)->network()->createFeed(m_ui->m_txtUrl->lineEdit()->text(),
|
const bool response = qobject_cast<OwnCloudServiceRoot*>(m_serviceRoot)->network()->createFeed(m_ui->m_txtUrl->lineEdit()->text(),
|
||||||
category_id);
|
category_id);
|
||||||
|
|
||||||
|
|
|
@ -120,6 +120,8 @@ OwnCloudStatusResponse OwnCloudNetworkFactory::status() {
|
||||||
headers);
|
headers);
|
||||||
OwnCloudStatusResponse status_response(QString::fromUtf8(result_raw));
|
OwnCloudStatusResponse status_response(QString::fromUtf8(result_raw));
|
||||||
|
|
||||||
|
qDebugNN << "Raw status data is:" << result_raw;
|
||||||
|
|
||||||
if (network_reply.first != QNetworkReply::NoError) {
|
if (network_reply.first != QNetworkReply::NoError) {
|
||||||
qWarning("Nextcloud: Obtaining status info failed with error %d.", network_reply.first);
|
qWarning("Nextcloud: Obtaining status info failed with error %d.", network_reply.first);
|
||||||
}
|
}
|
||||||
|
@ -329,7 +331,7 @@ void OwnCloudNetworkFactory::markMessagesRead(RootItem::ReadStatus status, const
|
||||||
QJsonArray ids;
|
QJsonArray ids;
|
||||||
QString final_url;
|
QString final_url;
|
||||||
|
|
||||||
if (status == RootItem::Read) {
|
if (status == RootItem::ReadStatus::Read) {
|
||||||
final_url = m_fixedUrl + OWNCLOUD_API_PATH + "items/read/multiple";
|
final_url = m_fixedUrl + OWNCLOUD_API_PATH + "items/read/multiple";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -375,7 +377,7 @@ void OwnCloudNetworkFactory::markMessagesStarred(RootItem::Importance importance
|
||||||
QJsonArray ids;
|
QJsonArray ids;
|
||||||
QString final_url;
|
QString final_url;
|
||||||
|
|
||||||
if (importance == RootItem::Important) {
|
if (importance == RootItem::Importance::Important) {
|
||||||
final_url = m_fixedUrl + OWNCLOUD_API_PATH + "items/star/multiple";
|
final_url = m_fixedUrl + OWNCLOUD_API_PATH + "items/star/multiple";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -70,8 +70,8 @@ OwnCloudServiceRoot* OwnCloudFeed::serviceRoot() const {
|
||||||
QList<Message> OwnCloudFeed::obtainNewMessages(bool* error_during_obtaining) {
|
QList<Message> OwnCloudFeed::obtainNewMessages(bool* error_during_obtaining) {
|
||||||
OwnCloudGetMessagesResponse messages = serviceRoot()->network()->getMessages(customNumericId());
|
OwnCloudGetMessagesResponse messages = serviceRoot()->network()->getMessages(customNumericId());
|
||||||
|
|
||||||
if (serviceRoot()->network()->lastError() != QNetworkReply::NoError) {
|
if (serviceRoot()->network()->lastError() != QNetworkReply::NetworkError::NoError) {
|
||||||
setStatus(Feed::NetworkError);
|
setStatus(Feed::Status::NetworkError);
|
||||||
*error_during_obtaining = true;
|
*error_during_obtaining = true;
|
||||||
serviceRoot()->itemChanged(QList<RootItem*>() << this);
|
serviceRoot()->itemChanged(QList<RootItem*>() << this);
|
||||||
return QList<Message>();
|
return QList<Message>();
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
#include "services/owncloud/owncloudserviceentrypoint.h"
|
#include "services/owncloud/owncloudserviceentrypoint.h"
|
||||||
|
|
||||||
OwnCloudServiceRoot::OwnCloudServiceRoot(RootItem* parent)
|
OwnCloudServiceRoot::OwnCloudServiceRoot(RootItem* parent)
|
||||||
: ServiceRoot(parent), m_actionSyncIn(nullptr), m_network(new OwnCloudNetworkFactory()) {
|
: ServiceRoot(parent), m_network(new OwnCloudNetworkFactory()) {
|
||||||
setIcon(OwnCloudServiceEntryPoint().icon());
|
setIcon(OwnCloudServiceEntryPoint().icon());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,6 +25,10 @@ OwnCloudServiceRoot::~OwnCloudServiceRoot() {
|
||||||
delete m_network;
|
delete m_network;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool OwnCloudServiceRoot::isSyncable() const {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool OwnCloudServiceRoot::canBeEdited() const {
|
bool OwnCloudServiceRoot::canBeEdited() const {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -59,16 +63,6 @@ bool OwnCloudServiceRoot::supportsCategoryAdding() const {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<QAction*> OwnCloudServiceRoot::serviceMenu() {
|
|
||||||
if (m_serviceMenu.isEmpty()) {
|
|
||||||
m_actionSyncIn = new QAction(qApp->icons()->fromTheme(QSL("view-refresh")), tr("Sync in"), this);
|
|
||||||
connect(m_actionSyncIn, &QAction::triggered, this, &OwnCloudServiceRoot::syncIn);
|
|
||||||
m_serviceMenu.append(m_actionSyncIn);
|
|
||||||
}
|
|
||||||
|
|
||||||
return m_serviceMenu;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OwnCloudServiceRoot::start(bool freshly_activated) {
|
void OwnCloudServiceRoot::start(bool freshly_activated) {
|
||||||
Q_UNUSED(freshly_activated)
|
Q_UNUSED(freshly_activated)
|
||||||
loadFromDatabase();
|
loadFromDatabase();
|
||||||
|
|
|
@ -18,13 +18,13 @@ class OwnCloudServiceRoot : public ServiceRoot, public CacheForServiceRoot {
|
||||||
explicit OwnCloudServiceRoot(RootItem* parent = nullptr);
|
explicit OwnCloudServiceRoot(RootItem* parent = nullptr);
|
||||||
virtual ~OwnCloudServiceRoot();
|
virtual ~OwnCloudServiceRoot();
|
||||||
|
|
||||||
|
bool isSyncable() const;
|
||||||
bool canBeEdited() const;
|
bool canBeEdited() const;
|
||||||
bool canBeDeleted() const;
|
bool canBeDeleted() const;
|
||||||
bool editViaGui();
|
bool editViaGui();
|
||||||
bool deleteViaGui();
|
bool deleteViaGui();
|
||||||
bool supportsFeedAdding() const;
|
bool supportsFeedAdding() const;
|
||||||
bool supportsCategoryAdding() const;
|
bool supportsCategoryAdding() const;
|
||||||
QList<QAction*> serviceMenu();
|
|
||||||
|
|
||||||
void start(bool freshly_activated);
|
void start(bool freshly_activated);
|
||||||
void stop();
|
void stop();
|
||||||
|
@ -42,12 +42,8 @@ class OwnCloudServiceRoot : public ServiceRoot, public CacheForServiceRoot {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
RootItem* obtainNewTreeForSyncIn() const;
|
RootItem* obtainNewTreeForSyncIn() const;
|
||||||
|
|
||||||
void loadFromDatabase();
|
void loadFromDatabase();
|
||||||
|
|
||||||
QAction* m_actionSyncIn;
|
|
||||||
|
|
||||||
QList<QAction*> m_serviceMenu;
|
|
||||||
OwnCloudNetworkFactory* m_network;
|
OwnCloudNetworkFactory* m_network;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -70,10 +70,10 @@ int FormStandardCategoryDetails::addEditCategory(StandardCategory* input_categor
|
||||||
|
|
||||||
// Load parent from suggested item.
|
// Load parent from suggested item.
|
||||||
if (parent_to_select != nullptr) {
|
if (parent_to_select != nullptr) {
|
||||||
if (parent_to_select->kind() == RootItemKind::Category) {
|
if (parent_to_select->kind() == RootItem::Kind::Category) {
|
||||||
m_ui->m_cmbParentCategory->setCurrentIndex(m_ui->m_cmbParentCategory->findData(QVariant::fromValue((void*) parent_to_select)));
|
m_ui->m_cmbParentCategory->setCurrentIndex(m_ui->m_cmbParentCategory->findData(QVariant::fromValue((void*) parent_to_select)));
|
||||||
}
|
}
|
||||||
else if (parent_to_select->kind() == RootItemKind::Feed) {
|
else if (parent_to_select->kind() == RootItem::Kind::Feed) {
|
||||||
int target_item = m_ui->m_cmbParentCategory->findData(QVariant::fromValue((void*) parent_to_select->parent()));
|
int target_item = m_ui->m_cmbParentCategory->findData(QVariant::fromValue((void*) parent_to_select->parent()));
|
||||||
|
|
||||||
if (target_item >= 0) {
|
if (target_item >= 0) {
|
||||||
|
|
|
@ -143,14 +143,14 @@ void FormStandardImportExport::selectExportFile() {
|
||||||
|
|
||||||
if (!selected_file.isEmpty()) {
|
if (!selected_file.isEmpty()) {
|
||||||
if (selected_filter == filter_opml20) {
|
if (selected_filter == filter_opml20) {
|
||||||
m_conversionType = OPML20;
|
m_conversionType = ConversionType::OPML20;
|
||||||
|
|
||||||
if (!selected_file.endsWith(QL1S(".opml"))) {
|
if (!selected_file.endsWith(QL1S(".opml"))) {
|
||||||
selected_file += QL1S(".opml");
|
selected_file += QL1S(".opml");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (selected_filter == filter_txt_url_per_line) {
|
else if (selected_filter == filter_txt_url_per_line) {
|
||||||
m_conversionType = TXTUrlPerLine;
|
m_conversionType = ConversionType::TxtUrlPerLine;
|
||||||
|
|
||||||
if (!selected_file.endsWith(QL1S(".txt"))) {
|
if (!selected_file.endsWith(QL1S(".txt"))) {
|
||||||
selected_file += QL1S(".txt");
|
selected_file += QL1S(".txt");
|
||||||
|
@ -178,10 +178,10 @@ void FormStandardImportExport::selectImportFile() {
|
||||||
|
|
||||||
if (!selected_file.isEmpty()) {
|
if (!selected_file.isEmpty()) {
|
||||||
if (selected_filter == filter_opml20) {
|
if (selected_filter == filter_opml20) {
|
||||||
m_conversionType = OPML20;
|
m_conversionType = ConversionType::OPML20;
|
||||||
}
|
}
|
||||||
else if (selected_filter == filter_txt_url_per_line) {
|
else if (selected_filter == filter_txt_url_per_line) {
|
||||||
m_conversionType = TXTUrlPerLine;
|
m_conversionType = ConversionType::TxtUrlPerLine;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_ui->m_lblSelectFile->setStatus(WidgetWithStatus::StatusType::Ok, QDir::toNativeSeparators(selected_file), tr("File is selected."));
|
m_ui->m_lblSelectFile->setStatus(WidgetWithStatus::StatusType::Ok, QDir::toNativeSeparators(selected_file), tr("File is selected."));
|
||||||
|
@ -213,11 +213,11 @@ void FormStandardImportExport::parseImportFile(const QString& file_name, bool fe
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (m_conversionType) {
|
switch (m_conversionType) {
|
||||||
case OPML20:
|
case ConversionType::OPML20:
|
||||||
m_model->importAsOPML20(input_data, fetch_metadata_online);
|
m_model->importAsOPML20(input_data, fetch_metadata_online);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TXTUrlPerLine:
|
case ConversionType::TxtUrlPerLine:
|
||||||
m_model->importAsTxtURLPerLine(input_data, fetch_metadata_online);
|
m_model->importAsTxtURLPerLine(input_data, fetch_metadata_online);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -246,11 +246,11 @@ void FormStandardImportExport::exportFeeds() {
|
||||||
bool result_export = false;
|
bool result_export = false;
|
||||||
|
|
||||||
switch (m_conversionType) {
|
switch (m_conversionType) {
|
||||||
case OPML20:
|
case ConversionType::OPML20:
|
||||||
result_export = m_model->exportToOMPL20(result_data);
|
result_export = m_model->exportToOMPL20(result_data);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TXTUrlPerLine:
|
case ConversionType::TxtUrlPerLine:
|
||||||
result_export = m_model->exportToTxtURLPerLine(result_data);
|
result_export = m_model->exportToTxtURLPerLine(result_data);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -19,9 +19,9 @@ class FormStandardImportExport : public QDialog {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum ConversionType {
|
enum class ConversionType {
|
||||||
OPML20 = 0,
|
OPML20 = 0,
|
||||||
TXTUrlPerLine = 1
|
TxtUrlPerLine = 1
|
||||||
};
|
};
|
||||||
|
|
||||||
// Constructors.
|
// Constructors.
|
||||||
|
|
|
@ -73,10 +73,10 @@ bool StandardCategory::removeItself() {
|
||||||
// Remove all child items (feeds and categories)
|
// Remove all child items (feeds and categories)
|
||||||
// from the database.
|
// from the database.
|
||||||
for (RootItem* child : childItems()) {
|
for (RootItem* child : childItems()) {
|
||||||
if (child->kind() == RootItemKind::Category) {
|
if (child->kind() == RootItem::Kind::Category) {
|
||||||
children_removed &= dynamic_cast<StandardCategory*>(child)->removeItself();
|
children_removed &= dynamic_cast<StandardCategory*>(child)->removeItself();
|
||||||
}
|
}
|
||||||
else if (child->kind() == RootItemKind::Feed) {
|
else if (child->kind() == RootItem::Kind::Feed) {
|
||||||
children_removed &= dynamic_cast<StandardFeed*>(child)->removeItself();
|
children_removed &= dynamic_cast<StandardFeed*>(child)->removeItself();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ StandardFeed::StandardFeed(RootItem* parent_item)
|
||||||
m_username = QString();
|
m_username = QString();
|
||||||
m_password = QString();
|
m_password = QString();
|
||||||
m_networkError = QNetworkReply::NoError;
|
m_networkError = QNetworkReply::NoError;
|
||||||
m_type = Rss0X;
|
m_type = Type::Rss0X;
|
||||||
m_encoding = QString();
|
m_encoding = QString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ StandardFeed::~StandardFeed() {
|
||||||
qDebug("Destroying Feed instance.");
|
qDebug("Destroying Feed instance.");
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<QAction*> StandardFeed::contextMenu() {
|
QList<QAction*> StandardFeed::contextMenuFeedsList() {
|
||||||
return serviceRoot()->getContextMenuForFeed(this);
|
return serviceRoot()->getContextMenuForFeed(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,6 +77,7 @@ StandardServiceRoot* StandardFeed::serviceRoot() const {
|
||||||
|
|
||||||
bool StandardFeed::editViaGui() {
|
bool StandardFeed::editViaGui() {
|
||||||
QScopedPointer<FormStandardFeedDetails> form_pointer(new FormStandardFeedDetails(serviceRoot(), qApp->mainFormWidget()));
|
QScopedPointer<FormStandardFeedDetails> form_pointer(new FormStandardFeedDetails(serviceRoot(), qApp->mainFormWidget()));
|
||||||
|
|
||||||
form_pointer.data()->addEditFeed(this, nullptr);
|
form_pointer.data()->addEditFeed(this, nullptr);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -93,16 +94,16 @@ bool StandardFeed::deleteViaGui() {
|
||||||
|
|
||||||
QString StandardFeed::typeToString(StandardFeed::Type type) {
|
QString StandardFeed::typeToString(StandardFeed::Type type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case Atom10:
|
case Type::Atom10:
|
||||||
return QSL("ATOM 1.0");
|
return QSL("ATOM 1.0");
|
||||||
|
|
||||||
case Rdf:
|
case Type::Rdf:
|
||||||
return QSL("RDF (RSS 1.0)");
|
return QSL("RDF (RSS 1.0)");
|
||||||
|
|
||||||
case Rss0X:
|
case Type::Rss0X:
|
||||||
return QSL("RSS 0.91/0.92/0.93");
|
return QSL("RSS 0.91/0.92/0.93");
|
||||||
|
|
||||||
case Rss2X:
|
case Type::Rss2X:
|
||||||
default:
|
default:
|
||||||
return QSL("RSS 2.0/2.0.1");
|
return QSL("RSS 2.0/2.0.1");
|
||||||
}
|
}
|
||||||
|
@ -111,7 +112,7 @@ QString StandardFeed::typeToString(StandardFeed::Type type) {
|
||||||
void StandardFeed::fetchMetadataForItself() {
|
void StandardFeed::fetchMetadataForItself() {
|
||||||
QPair<StandardFeed*, QNetworkReply::NetworkError> metadata = guessFeed(url(), username(), password());
|
QPair<StandardFeed*, QNetworkReply::NetworkError> metadata = guessFeed(url(), username(), password());
|
||||||
|
|
||||||
if (metadata.first != nullptr && metadata.second == QNetworkReply::NoError) {
|
if (metadata.first != nullptr && metadata.second == QNetworkReply::NetworkError::NoError) {
|
||||||
// Some properties are not updated when new metadata are fetched.
|
// Some properties are not updated when new metadata are fetched.
|
||||||
metadata.first->setParent(parent());
|
metadata.first->setParent(parent());
|
||||||
metadata.first->setUrl(url());
|
metadata.first->setUrl(url());
|
||||||
|
@ -138,10 +139,11 @@ QPair<StandardFeed*, QNetworkReply::NetworkError> StandardFeed::guessFeed(const
|
||||||
const QString& username,
|
const QString& username,
|
||||||
const QString& password) {
|
const QString& password) {
|
||||||
QPair<StandardFeed*, QNetworkReply::NetworkError> result;
|
QPair<StandardFeed*, QNetworkReply::NetworkError> result;
|
||||||
|
|
||||||
result.first = nullptr;
|
result.first = nullptr;
|
||||||
QByteArray feed_contents;
|
QByteArray feed_contents;
|
||||||
|
|
||||||
QList<QPair<QByteArray, QByteArray>> headers;
|
QList<QPair<QByteArray, QByteArray>> headers;
|
||||||
|
|
||||||
headers << NetworkFactory::generateBasicAuthHeader(username, password);
|
headers << NetworkFactory::generateBasicAuthHeader(username, password);
|
||||||
|
|
||||||
NetworkResult network_result = NetworkFactory::performNetworkOperation(url,
|
NetworkResult network_result = NetworkFactory::performNetworkOperation(url,
|
||||||
|
@ -208,15 +210,15 @@ QPair<StandardFeed*, QNetworkReply::NetworkError> StandardFeed::guessFeed(const
|
||||||
|
|
||||||
QDomElement root_element = xml_document.documentElement();
|
QDomElement root_element = xml_document.documentElement();
|
||||||
QString root_tag_name = root_element.tagName();
|
QString root_tag_name = root_element.tagName();
|
||||||
|
|
||||||
QList<QString> icon_possible_locations;
|
QList<QString> icon_possible_locations;
|
||||||
|
|
||||||
icon_possible_locations.append(url);
|
icon_possible_locations.append(url);
|
||||||
|
|
||||||
if (root_tag_name == QL1S("rdf:RDF")) {
|
if (root_tag_name == QL1S("rdf:RDF")) {
|
||||||
// We found RDF feed.
|
// We found RDF feed.
|
||||||
QDomElement channel_element = root_element.namedItem(QSL("channel")).toElement();
|
QDomElement channel_element = root_element.namedItem(QSL("channel")).toElement();
|
||||||
|
|
||||||
result.first->setType(Rdf);
|
result.first->setType(Type::Rdf);
|
||||||
result.first->setTitle(channel_element.namedItem(QSL("title")).toElement().text());
|
result.first->setTitle(channel_element.namedItem(QSL("title")).toElement().text());
|
||||||
result.first->setDescription(channel_element.namedItem(QSL("description")).toElement().text());
|
result.first->setDescription(channel_element.namedItem(QSL("description")).toElement().text());
|
||||||
QString source_link = channel_element.namedItem(QSL("link")).toElement().text();
|
QString source_link = channel_element.namedItem(QSL("link")).toElement().text();
|
||||||
|
@ -230,10 +232,10 @@ QPair<StandardFeed*, QNetworkReply::NetworkError> StandardFeed::guessFeed(const
|
||||||
QString rss_type = root_element.attribute("version", "2.0");
|
QString rss_type = root_element.attribute("version", "2.0");
|
||||||
|
|
||||||
if (rss_type == QL1S("0.91") || rss_type == QL1S("0.92") || rss_type == QL1S("0.93")) {
|
if (rss_type == QL1S("0.91") || rss_type == QL1S("0.92") || rss_type == QL1S("0.93")) {
|
||||||
result.first->setType(Rss0X);
|
result.first->setType(Type::Rss0X);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
result.first->setType(Rss2X);
|
result.first->setType(Type::Rss2X);
|
||||||
}
|
}
|
||||||
|
|
||||||
QDomElement channel_element = root_element.namedItem(QSL("channel")).toElement();
|
QDomElement channel_element = root_element.namedItem(QSL("channel")).toElement();
|
||||||
|
@ -248,7 +250,7 @@ QPair<StandardFeed*, QNetworkReply::NetworkError> StandardFeed::guessFeed(const
|
||||||
}
|
}
|
||||||
else if (root_tag_name == QL1S("feed")) {
|
else if (root_tag_name == QL1S("feed")) {
|
||||||
// We found ATOM feed.
|
// We found ATOM feed.
|
||||||
result.first->setType(Atom10);
|
result.first->setType(Type::Atom10);
|
||||||
result.first->setTitle(root_element.namedItem(QSL("title")).toElement().text());
|
result.first->setTitle(root_element.namedItem(QSL("title")).toElement().text());
|
||||||
result.first->setDescription(root_element.namedItem(QSL("subtitle")).toElement().text());
|
result.first->setDescription(root_element.namedItem(QSL("subtitle")).toElement().text());
|
||||||
QString source_link = root_element.namedItem(QSL("link")).toElement().text();
|
QString source_link = root_element.namedItem(QSL("link")).toElement().text();
|
||||||
|
@ -335,6 +337,7 @@ bool StandardFeed::editItself(StandardFeed* new_feed_data) {
|
||||||
new_feed_data->autoUpdateType(), new_feed_data->autoUpdateInitialInterval(),
|
new_feed_data->autoUpdateType(), new_feed_data->autoUpdateInitialInterval(),
|
||||||
new_feed_data->type())) {
|
new_feed_data->type())) {
|
||||||
// Persistent storage update failed, no way to continue now.
|
// Persistent storage update failed, no way to continue now.
|
||||||
|
qWarning("Self-editing of standard feed failed.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -399,8 +402,8 @@ void StandardFeed::setEncoding(const QString& encoding) {
|
||||||
QList<Message> StandardFeed::obtainNewMessages(bool* error_during_obtaining) {
|
QList<Message> StandardFeed::obtainNewMessages(bool* error_during_obtaining) {
|
||||||
QByteArray feed_contents;
|
QByteArray feed_contents;
|
||||||
int download_timeout = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)).toInt();
|
int download_timeout = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)).toInt();
|
||||||
|
|
||||||
QList<QPair<QByteArray, QByteArray>> headers;
|
QList<QPair<QByteArray, QByteArray>> headers;
|
||||||
|
|
||||||
headers << NetworkFactory::generateBasicAuthHeader(username(), password());
|
headers << NetworkFactory::generateBasicAuthHeader(username(), password());
|
||||||
|
|
||||||
m_networkError = NetworkFactory::performNetworkOperation(url(),
|
m_networkError = NetworkFactory::performNetworkOperation(url(),
|
||||||
|
@ -412,7 +415,7 @@ QList<Message> StandardFeed::obtainNewMessages(bool* error_during_obtaining) {
|
||||||
|
|
||||||
if (m_networkError != QNetworkReply::NoError) {
|
if (m_networkError != QNetworkReply::NoError) {
|
||||||
qWarning("Error during fetching of new messages for feed '%s' (id %d).", qPrintable(url()), id());
|
qWarning("Error during fetching of new messages for feed '%s' (id %d).", qPrintable(url()), id());
|
||||||
setStatus(NetworkError);
|
setStatus(Status::NetworkError);
|
||||||
*error_during_obtaining = true;
|
*error_during_obtaining = true;
|
||||||
return QList<Message>();
|
return QList<Message>();
|
||||||
}
|
}
|
||||||
|
@ -438,16 +441,16 @@ QList<Message> StandardFeed::obtainNewMessages(bool* error_during_obtaining) {
|
||||||
QList<Message> messages;
|
QList<Message> messages;
|
||||||
|
|
||||||
switch (type()) {
|
switch (type()) {
|
||||||
case StandardFeed::Rss0X:
|
case StandardFeed::Type::Rss0X:
|
||||||
case StandardFeed::Rss2X:
|
case StandardFeed::Type::Rss2X:
|
||||||
messages = RssParser(formatted_feed_contents).messages();
|
messages = RssParser(formatted_feed_contents).messages();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case StandardFeed::Rdf:
|
case StandardFeed::Type::Rdf:
|
||||||
messages = RdfParser().parseXmlData(formatted_feed_contents);
|
messages = RdfParser().parseXmlData(formatted_feed_contents);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case StandardFeed::Atom10:
|
case StandardFeed::Type::Atom10:
|
||||||
messages = AtomParser(formatted_feed_contents).messages();
|
messages = AtomParser(formatted_feed_contents).messages();
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -20,7 +20,7 @@ class StandardFeed : public Feed {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum Type {
|
enum class Type {
|
||||||
Rss0X = 0,
|
Rss0X = 0,
|
||||||
Rss2X = 1,
|
Rss2X = 1,
|
||||||
Rdf = 2, // Sometimes denoted as RSS 1.0.
|
Rdf = 2, // Sometimes denoted as RSS 1.0.
|
||||||
|
@ -35,7 +35,7 @@ class StandardFeed : public Feed {
|
||||||
|
|
||||||
StandardServiceRoot* serviceRoot() const;
|
StandardServiceRoot* serviceRoot() const;
|
||||||
|
|
||||||
QList<QAction*> contextMenu();
|
QList<QAction*> contextMenuFeedsList();
|
||||||
|
|
||||||
QString additionalTooltip() const;
|
QString additionalTooltip() const;
|
||||||
|
|
||||||
|
|
|
@ -70,7 +70,7 @@ bool FeedsImportExportModel::exportToOMPL20(QByteArray& result) {
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (child_item->kind()) {
|
switch (child_item->kind()) {
|
||||||
case RootItemKind::Category: {
|
case RootItem::Kind::Category: {
|
||||||
QDomElement outline_category = opml_document.createElement(QSL("outline"));
|
QDomElement outline_category = opml_document.createElement(QSL("outline"));
|
||||||
|
|
||||||
outline_category.setAttribute(QSL("text"), child_item->title());
|
outline_category.setAttribute(QSL("text"), child_item->title());
|
||||||
|
@ -82,7 +82,7 @@ bool FeedsImportExportModel::exportToOMPL20(QByteArray& result) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case RootItemKind::Feed: {
|
case RootItem::Kind::Feed: {
|
||||||
auto* child_feed = dynamic_cast<StandardFeed*>(child_item);
|
auto* child_feed = dynamic_cast<StandardFeed*>(child_item);
|
||||||
QDomElement outline_feed = opml_document.createElement("outline");
|
QDomElement outline_feed = opml_document.createElement("outline");
|
||||||
|
|
||||||
|
@ -95,16 +95,16 @@ bool FeedsImportExportModel::exportToOMPL20(QByteArray& result) {
|
||||||
outline_feed.setAttribute(QSL("rssguard:icon"), QString(qApp->icons()->toByteArray(child_feed->icon())));
|
outline_feed.setAttribute(QSL("rssguard:icon"), QString(qApp->icons()->toByteArray(child_feed->icon())));
|
||||||
|
|
||||||
switch (child_feed->type()) {
|
switch (child_feed->type()) {
|
||||||
case StandardFeed::Rss0X:
|
case StandardFeed::Type::Rss0X:
|
||||||
case StandardFeed::Rss2X:
|
case StandardFeed::Type::Rss2X:
|
||||||
outline_feed.setAttribute(QSL("version"), QSL("RSS"));
|
outline_feed.setAttribute(QSL("version"), QSL("RSS"));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case StandardFeed::Rdf:
|
case StandardFeed::Type::Rdf:
|
||||||
outline_feed.setAttribute(QSL("version"), QSL("RSS1"));
|
outline_feed.setAttribute(QSL("version"), QSL("RSS1"));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case StandardFeed::Atom10:
|
case StandardFeed::Type::Atom10:
|
||||||
outline_feed.setAttribute(QSL("version"), QSL("ATOM"));
|
outline_feed.setAttribute(QSL("version"), QSL("ATOM"));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -200,13 +200,13 @@ void FeedsImportExportModel::importAsOPML20(const QByteArray& data, bool fetch_m
|
||||||
new_feed->setIcon(feed_icon);
|
new_feed->setIcon(feed_icon);
|
||||||
|
|
||||||
if (feed_type == QL1S("RSS1")) {
|
if (feed_type == QL1S("RSS1")) {
|
||||||
new_feed->setType(StandardFeed::Rdf);
|
new_feed->setType(StandardFeed::Type::Rdf);
|
||||||
}
|
}
|
||||||
else if (feed_type == QL1S("ATOM")) {
|
else if (feed_type == QL1S("ATOM")) {
|
||||||
new_feed->setType(StandardFeed::Atom10);
|
new_feed->setType(StandardFeed::Type::Atom10);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
new_feed->setType(StandardFeed::Rss2X);
|
new_feed->setType(StandardFeed::Type::Rss2X);
|
||||||
}
|
}
|
||||||
|
|
||||||
active_model_item->appendChild(new_feed);
|
active_model_item->appendChild(new_feed);
|
||||||
|
|
|
@ -27,22 +27,20 @@
|
||||||
#include <QStack>
|
#include <QStack>
|
||||||
|
|
||||||
StandardServiceRoot::StandardServiceRoot(RootItem* parent)
|
StandardServiceRoot::StandardServiceRoot(RootItem* parent)
|
||||||
: ServiceRoot(parent),
|
: ServiceRoot(parent) {
|
||||||
m_actionExportFeeds(nullptr), m_actionImportFeeds(nullptr), m_actionFeedFetchMetadata(nullptr) {
|
|
||||||
setTitle(qApp->system()->loggedInUser() + QSL(" (RSS/RDF/ATOM)"));
|
setTitle(qApp->system()->loggedInUser() + QSL(" (RSS/RDF/ATOM)"));
|
||||||
setIcon(StandardServiceEntryPoint().icon());
|
setIcon(StandardServiceEntryPoint().icon());
|
||||||
setDescription(tr("This is obligatory service account for standard RSS/RDF/ATOM feeds."));
|
setDescription(tr("This is obligatory service account for standard RSS/RDF/ATOM feeds."));
|
||||||
}
|
}
|
||||||
|
|
||||||
StandardServiceRoot::~StandardServiceRoot() {
|
StandardServiceRoot::~StandardServiceRoot() {
|
||||||
qDeleteAll(m_serviceMenu);
|
|
||||||
qDeleteAll(m_feedContextMenu);
|
qDeleteAll(m_feedContextMenu);
|
||||||
}
|
}
|
||||||
|
|
||||||
void StandardServiceRoot::start(bool freshly_activated) {
|
void StandardServiceRoot::start(bool freshly_activated) {
|
||||||
loadFromDatabase();
|
loadFromDatabase();
|
||||||
|
|
||||||
if (freshly_activated && getSubTree(RootItemKind::Feed).isEmpty()) {
|
if (freshly_activated && getSubTree(RootItem::Kind::Feed).isEmpty()) {
|
||||||
// In other words, if there are no feeds or categories added.
|
// In other words, if there are no feeds or categories added.
|
||||||
if (MessageBox::show(qApp->mainFormWidget(), QMessageBox::Question, QObject::tr("Load initial set of feeds"),
|
if (MessageBox::show(qApp->mainFormWidget(), QMessageBox::Question, QObject::tr("Load initial set of feeds"),
|
||||||
tr("This new account does not include any feeds. You can now add default set of feeds."),
|
tr("This new account does not include any feeds. You can now add default set of feeds."),
|
||||||
|
@ -176,13 +174,19 @@ void StandardServiceRoot::checkArgumentForFeedAdding(const QString& argument) {
|
||||||
QList<QAction*> StandardServiceRoot::getContextMenuForFeed(StandardFeed* feed) {
|
QList<QAction*> StandardServiceRoot::getContextMenuForFeed(StandardFeed* feed) {
|
||||||
if (m_feedContextMenu.isEmpty()) {
|
if (m_feedContextMenu.isEmpty()) {
|
||||||
// Initialize.
|
// Initialize.
|
||||||
m_actionFeedFetchMetadata = new QAction(qApp->icons()->fromTheme(QSL("emblem-downloads")), tr("Fetch metadata"), nullptr);
|
auto* action_metadata = new QAction(qApp->icons()->fromTheme(QSL("emblem-downloads")),
|
||||||
m_feedContextMenu.append(m_actionFeedFetchMetadata);
|
tr("Fetch metadata"),
|
||||||
|
this);
|
||||||
|
|
||||||
|
m_feedContextMenu.append(action_metadata);
|
||||||
|
|
||||||
|
connect(action_metadata, &QAction::triggered, this, [this]() {
|
||||||
|
m_feedForMetadata->fetchMetadataForItself();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make connections.
|
m_feedForMetadata = feed;
|
||||||
disconnect(m_actionFeedFetchMetadata, &QAction::triggered, nullptr, nullptr);
|
|
||||||
connect(m_actionFeedFetchMetadata, &QAction::triggered, feed, &StandardFeed::fetchMetadataForItself);
|
|
||||||
return m_feedContextMenu;
|
return m_feedContextMenu;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,7 +211,7 @@ bool StandardServiceRoot::mergeImportExportModel(FeedsImportExportModel* model,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (source_item->kind() == RootItemKind::Category) {
|
if (source_item->kind() == RootItem::Kind::Category) {
|
||||||
auto* source_category = dynamic_cast<StandardCategory*>(source_item);
|
auto* source_category = dynamic_cast<StandardCategory*>(source_item);
|
||||||
auto* new_category = new StandardCategory(*source_category);
|
auto* new_category = new StandardCategory(*source_category);
|
||||||
QString new_category_title = new_category->title();
|
QString new_category_title = new_category->title();
|
||||||
|
@ -231,7 +235,7 @@ bool StandardServiceRoot::mergeImportExportModel(FeedsImportExportModel* model,
|
||||||
RootItem* existing_category = nullptr;
|
RootItem* existing_category = nullptr;
|
||||||
|
|
||||||
for (RootItem* child : target_parent->childItems()) {
|
for (RootItem* child : target_parent->childItems()) {
|
||||||
if (child->kind() == RootItemKind::Category && child->title() == new_category_title) {
|
if (child->kind() == RootItem::Kind::Category && child->title() == new_category_title) {
|
||||||
existing_category = child;
|
existing_category = child;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -245,7 +249,7 @@ bool StandardServiceRoot::mergeImportExportModel(FeedsImportExportModel* model,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (source_item->kind() == RootItemKind::Feed) {
|
else if (source_item->kind() == RootItem::Kind::Feed) {
|
||||||
auto* source_feed = dynamic_cast<StandardFeed*>(source_item);
|
auto* source_feed = dynamic_cast<StandardFeed*>(source_item);
|
||||||
auto* new_feed = new StandardFeed(*source_feed);
|
auto* new_feed = new StandardFeed(*source_feed);
|
||||||
|
|
||||||
|
@ -306,12 +310,16 @@ void StandardServiceRoot::exportFeeds() {
|
||||||
|
|
||||||
QList<QAction*> StandardServiceRoot::serviceMenu() {
|
QList<QAction*> StandardServiceRoot::serviceMenu() {
|
||||||
if (m_serviceMenu.isEmpty()) {
|
if (m_serviceMenu.isEmpty()) {
|
||||||
m_actionExportFeeds = new QAction(qApp->icons()->fromTheme("document-export"), tr("Export feeds"), this);
|
ServiceRoot::serviceMenu();
|
||||||
m_actionImportFeeds = new QAction(qApp->icons()->fromTheme("document-import"), tr("Import feeds"), this);
|
|
||||||
connect(m_actionExportFeeds, &QAction::triggered, this, &StandardServiceRoot::exportFeeds);
|
auto* action_export_feeds = new QAction(qApp->icons()->fromTheme("document-export"), tr("Export feeds"), this);
|
||||||
connect(m_actionImportFeeds, &QAction::triggered, this, &StandardServiceRoot::importFeeds);
|
auto* action_import_feeds = new QAction(qApp->icons()->fromTheme("document-import"), tr("Import feeds"), this);
|
||||||
m_serviceMenu.append(m_actionExportFeeds);
|
|
||||||
m_serviceMenu.append(m_actionImportFeeds);
|
connect(action_export_feeds, &QAction::triggered, this, &StandardServiceRoot::exportFeeds);
|
||||||
|
connect(action_import_feeds, &QAction::triggered, this, &StandardServiceRoot::importFeeds);
|
||||||
|
|
||||||
|
m_serviceMenu.append(action_export_feeds);
|
||||||
|
m_serviceMenu.append(action_import_feeds);
|
||||||
}
|
}
|
||||||
|
|
||||||
return m_serviceMenu;
|
return m_serviceMenu;
|
||||||
|
|
|
@ -5,11 +5,12 @@
|
||||||
|
|
||||||
#include "services/abstract/serviceroot.h"
|
#include "services/abstract/serviceroot.h"
|
||||||
|
|
||||||
|
#include "services/standard/standardfeed.h"
|
||||||
|
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
#include <QPair>
|
#include <QPair>
|
||||||
|
|
||||||
class StandardCategory;
|
class StandardCategory;
|
||||||
class StandardFeed;
|
|
||||||
class FeedsImportExportModel;
|
class FeedsImportExportModel;
|
||||||
class QMenu;
|
class QMenu;
|
||||||
|
|
||||||
|
@ -58,12 +59,8 @@ class StandardServiceRoot : public ServiceRoot {
|
||||||
QString processFeedUrl(const QString& feed_url);
|
QString processFeedUrl(const QString& feed_url);
|
||||||
void checkArgumentsForFeedAdding();
|
void checkArgumentsForFeedAdding();
|
||||||
|
|
||||||
QAction* m_actionExportFeeds;
|
QPointer<StandardFeed> m_feedForMetadata = {};
|
||||||
QAction* m_actionImportFeeds;
|
QList<QAction*> m_feedContextMenu = {};
|
||||||
|
|
||||||
QList<QAction*> m_serviceMenu;
|
|
||||||
QList<QAction*> m_feedContextMenu;
|
|
||||||
QAction* m_actionFeedFetchMetadata;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // STANDARDSERVICEROOT_H
|
#endif // STANDARDSERVICEROOT_H
|
||||||
|
|
|
@ -37,7 +37,7 @@ void FormTtRssFeedDetails::apply() {
|
||||||
RootItem* parent = static_cast<RootItem*>(m_ui->m_cmbParentCategory->itemData(
|
RootItem* parent = static_cast<RootItem*>(m_ui->m_cmbParentCategory->itemData(
|
||||||
m_ui->m_cmbParentCategory->currentIndex()).value<void*>());
|
m_ui->m_cmbParentCategory->currentIndex()).value<void*>());
|
||||||
auto* root = qobject_cast<TtRssServiceRoot*>(parent->getParentServiceRoot());
|
auto* root = qobject_cast<TtRssServiceRoot*>(parent->getParentServiceRoot());
|
||||||
const int category_id = parent->kind() == RootItemKind::ServiceRoot ?
|
const int category_id = parent->kind() == RootItem::Kind::ServiceRoot ?
|
||||||
0 :
|
0 :
|
||||||
parent->customId().toInt();
|
parent->customId().toInt();
|
||||||
const TtRssSubscribeToFeedResponse response = root->network()->subscribeToFeed(m_ui->m_txtUrl->lineEdit()->text(),
|
const TtRssSubscribeToFeedResponse response = root->network()->subscribeToFeed(m_ui->m_txtUrl->lineEdit()->text(),
|
||||||
|
|
|
@ -86,12 +86,12 @@ class TtRssUnsubscribeFeedResponse : public TtRssResponse {
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace UpdateArticle {
|
namespace UpdateArticle {
|
||||||
enum Mode {
|
enum class Mode {
|
||||||
SetToFalse = 0,
|
SetToFalse = 0,
|
||||||
SetToTrue = 1,
|
SetToTrue = 1,
|
||||||
Togggle = 2
|
Togggle = 2
|
||||||
};
|
};
|
||||||
enum OperatingField {
|
enum class OperatingField {
|
||||||
Starred = 0,
|
Starred = 0,
|
||||||
Published = 1,
|
Published = 1,
|
||||||
Unread = 2
|
Unread = 2
|
||||||
|
|
|
@ -79,7 +79,7 @@ QList<Message> TtRssFeed::obtainNewMessages(bool* error_during_obtaining) {
|
||||||
serviceRoot()->network()->downloadOnlyUnreadMessages());
|
serviceRoot()->network()->downloadOnlyUnreadMessages());
|
||||||
|
|
||||||
if (serviceRoot()->network()->lastError() != QNetworkReply::NoError) {
|
if (serviceRoot()->network()->lastError() != QNetworkReply::NoError) {
|
||||||
setStatus(Feed::NetworkError);
|
setStatus(Feed::Status::NetworkError);
|
||||||
*error_during_obtaining = true;
|
*error_during_obtaining = true;
|
||||||
serviceRoot()->itemChanged(QList<RootItem*>() << this);
|
serviceRoot()->itemChanged(QList<RootItem*>() << this);
|
||||||
return QList<Message>();
|
return QList<Message>();
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
#include <QSqlTableModel>
|
#include <QSqlTableModel>
|
||||||
|
|
||||||
TtRssServiceRoot::TtRssServiceRoot(RootItem* parent)
|
TtRssServiceRoot::TtRssServiceRoot(RootItem* parent)
|
||||||
: ServiceRoot(parent), m_actionSyncIn(nullptr), m_network(new TtRssNetworkFactory()) {
|
: ServiceRoot(parent), m_network(new TtRssNetworkFactory()) {
|
||||||
setIcon(TtRssServiceEntryPoint().icon());
|
setIcon(TtRssServiceEntryPoint().icon());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,6 +52,10 @@ QString TtRssServiceRoot::code() const {
|
||||||
return TtRssServiceEntryPoint().code();
|
return TtRssServiceEntryPoint().code();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool TtRssServiceRoot::isSyncable() const {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool TtRssServiceRoot::editViaGui() {
|
bool TtRssServiceRoot::editViaGui() {
|
||||||
QScopedPointer<FormEditTtRssAccount> form_pointer(new FormEditTtRssAccount(qApp->mainFormWidget()));
|
QScopedPointer<FormEditTtRssAccount> form_pointer(new FormEditTtRssAccount(qApp->mainFormWidget()));
|
||||||
|
|
||||||
|
@ -123,8 +127,10 @@ void TtRssServiceRoot::saveAllCachedData(bool async) {
|
||||||
|
|
||||||
if (!ids.isEmpty()) {
|
if (!ids.isEmpty()) {
|
||||||
network()->updateArticles(ids,
|
network()->updateArticles(ids,
|
||||||
UpdateArticle::Unread,
|
UpdateArticle::OperatingField::Unread,
|
||||||
key == RootItem::Unread ? UpdateArticle::SetToTrue : UpdateArticle::SetToFalse,
|
key == RootItem::ReadStatus::Unread
|
||||||
|
? UpdateArticle::Mode::SetToTrue
|
||||||
|
: UpdateArticle::Mode::SetToFalse,
|
||||||
async);
|
async);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -141,23 +147,15 @@ void TtRssServiceRoot::saveAllCachedData(bool async) {
|
||||||
QStringList ids = customIDsOfMessages(messages);
|
QStringList ids = customIDsOfMessages(messages);
|
||||||
|
|
||||||
network()->updateArticles(ids,
|
network()->updateArticles(ids,
|
||||||
UpdateArticle::Starred,
|
UpdateArticle::OperatingField::Starred,
|
||||||
key == RootItem::Important ? UpdateArticle::SetToTrue : UpdateArticle::SetToFalse,
|
key == RootItem::Importance::Important
|
||||||
|
? UpdateArticle::Mode::SetToTrue
|
||||||
|
: UpdateArticle::Mode::SetToFalse,
|
||||||
async);
|
async);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<QAction*> TtRssServiceRoot::serviceMenu() {
|
|
||||||
if (m_serviceMenu.isEmpty()) {
|
|
||||||
m_actionSyncIn = new QAction(qApp->icons()->fromTheme(QSL("view-refresh")), tr("Sync in"), this);
|
|
||||||
connect(m_actionSyncIn, &QAction::triggered, this, &TtRssServiceRoot::syncIn);
|
|
||||||
m_serviceMenu.append(m_actionSyncIn);
|
|
||||||
}
|
|
||||||
|
|
||||||
return m_serviceMenu;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString TtRssServiceRoot::additionalTooltip() const {
|
QString TtRssServiceRoot::additionalTooltip() const {
|
||||||
return tr("Username: %1\nServer: %2\n"
|
return tr("Username: %1\nServer: %2\n"
|
||||||
"Last error: %3\nLast login on: %4").arg(m_network->username(),
|
"Last error: %3\nLast login on: %4").arg(m_network->username(),
|
||||||
|
|
|
@ -22,13 +22,14 @@ class TtRssServiceRoot : public ServiceRoot, public CacheForServiceRoot {
|
||||||
void start(bool freshly_activated);
|
void start(bool freshly_activated);
|
||||||
void stop();
|
void stop();
|
||||||
QString code() const;
|
QString code() const;
|
||||||
|
|
||||||
|
bool isSyncable() const;
|
||||||
bool canBeEdited() const;
|
bool canBeEdited() const;
|
||||||
bool canBeDeleted() const;
|
bool canBeDeleted() const;
|
||||||
bool editViaGui();
|
bool editViaGui();
|
||||||
bool deleteViaGui();
|
bool deleteViaGui();
|
||||||
bool supportsFeedAdding() const;
|
bool supportsFeedAdding() const;
|
||||||
bool supportsCategoryAdding() const;
|
bool supportsCategoryAdding() const;
|
||||||
QList<QAction*> serviceMenu();
|
|
||||||
|
|
||||||
QString additionalTooltip() const;
|
QString additionalTooltip() const;
|
||||||
|
|
||||||
|
@ -46,12 +47,8 @@ class TtRssServiceRoot : public ServiceRoot, public CacheForServiceRoot {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
RootItem* obtainNewTreeForSyncIn() const;
|
RootItem* obtainNewTreeForSyncIn() const;
|
||||||
|
|
||||||
void loadFromDatabase();
|
void loadFromDatabase();
|
||||||
|
|
||||||
QAction* m_actionSyncIn;
|
|
||||||
|
|
||||||
QList<QAction*> m_serviceMenu;
|
|
||||||
TtRssNetworkFactory* m_network;
|
TtRssNetworkFactory* m_network;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue