File indexing completed on 2025-02-16 04:59:36

0001 /*
0002  * SPDX-FileCopyrightText: 2014 Kevin Ottens <ervin@kde.org>
0003  * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0004  */
0005 
0006 
0007 
0008 #ifndef DOMAIN_QUERYRESULTPROVIDER_H
0009 #define DOMAIN_QUERYRESULTPROVIDER_H
0010 
0011 #include <algorithm>
0012 #include <functional>
0013 
0014 #include <QList>
0015 #include <QSharedPointer>
0016 
0017 #include "utils/mem_fn.h"
0018 
0019 namespace Domain {
0020 
0021 template<typename ItemType>
0022 class QueryResultProvider;
0023 
0024 template<typename InputType>
0025 class QueryResultInputImpl
0026 {
0027 public:
0028     typedef typename QueryResultProvider<InputType>::Ptr ProviderPtr;
0029     typedef QSharedPointer<QueryResultInputImpl<InputType> > Ptr;
0030     typedef QWeakPointer<QueryResultInputImpl<InputType>> WeakPtr;
0031     typedef std::function<void(InputType, int)> ChangeHandler;
0032     typedef QList<ChangeHandler> ChangeHandlerList;
0033 
0034     virtual ~QueryResultInputImpl() {}
0035 
0036 protected:
0037     explicit QueryResultInputImpl(const ProviderPtr &provider)
0038         : m_provider(provider)
0039     {
0040     }
0041 
0042     static void registerResult(const ProviderPtr &provider, const Ptr &result)
0043     {
0044         provider->m_results << result;
0045     }
0046 
0047     static ProviderPtr retrieveProvider(const Ptr &result)
0048     {
0049         return result->m_provider;
0050     }
0051 
0052     // cppcheck can't figure out the friend class
0053     // cppcheck-suppress unusedPrivateFunction
0054     ChangeHandlerList preInsertHandlers() const
0055     {
0056         return m_preInsertHandlers;
0057     }
0058 
0059     // cppcheck can't figure out the friend class
0060     // cppcheck-suppress unusedPrivateFunction
0061     ChangeHandlerList postInsertHandlers() const
0062     {
0063         return m_postInsertHandlers;
0064     }
0065 
0066     // cppcheck can't figure out the friend class
0067     // cppcheck-suppress unusedPrivateFunction
0068     ChangeHandlerList preRemoveHandlers() const
0069     {
0070         return m_preRemoveHandlers;
0071     }
0072 
0073     // cppcheck can't figure out the friend class
0074     // cppcheck-suppress unusedPrivateFunction
0075     ChangeHandlerList postRemoveHandlers() const
0076     {
0077         return m_postRemoveHandlers;
0078     }
0079 
0080     // cppcheck can't figure out the friend class
0081     // cppcheck-suppress unusedPrivateFunction
0082     ChangeHandlerList preReplaceHandlers() const
0083     {
0084         return m_preReplaceHandlers;
0085     }
0086 
0087     // cppcheck can't figure out the friend class
0088     // cppcheck-suppress unusedPrivateFunction
0089     ChangeHandlerList postReplaceHandlers() const
0090     {
0091         return m_postReplaceHandlers;
0092     }
0093 
0094     friend class QueryResultProvider<InputType>;
0095     ProviderPtr m_provider;
0096     ChangeHandlerList m_preInsertHandlers;
0097     ChangeHandlerList m_postInsertHandlers;
0098     ChangeHandlerList m_preRemoveHandlers;
0099     ChangeHandlerList m_postRemoveHandlers;
0100     ChangeHandlerList m_preReplaceHandlers;
0101     ChangeHandlerList m_postReplaceHandlers;
0102 };
0103 
0104 template<typename ItemType>
0105 class QueryResultProvider
0106 {
0107 public:
0108     typedef QSharedPointer<QueryResultProvider<ItemType>> Ptr;
0109     typedef QWeakPointer<QueryResultProvider<ItemType>> WeakPtr;
0110 
0111     typedef QSharedPointer<QueryResultInputImpl<ItemType> > ResultPtr;
0112     typedef QWeakPointer<QueryResultInputImpl<ItemType>> ResultWeakPtr;
0113     typedef std::function<void(ItemType, int)> ChangeHandler;
0114     typedef QList<ChangeHandler> ChangeHandlerList;
0115 
0116 
0117     QueryResultProvider()
0118     {
0119     }
0120 
0121     QList<ItemType> data() const
0122     {
0123         return m_list;
0124     }
0125 
0126     void append(const ItemType &item)
0127     {
0128         cleanupResults();
0129         callChangeHandlers(item, m_list.size(),
0130                            Utils::mem_fn(&QueryResultInputImpl<ItemType>::preInsertHandlers));
0131         m_list.append(item);
0132         callChangeHandlers(item, m_list.size()-1,
0133                            Utils::mem_fn(&QueryResultInputImpl<ItemType>::postInsertHandlers));
0134     }
0135 
0136     void prepend(const ItemType &item)
0137     {
0138         cleanupResults();
0139         callChangeHandlers(item, 0,
0140                            Utils::mem_fn(&QueryResultInputImpl<ItemType>::preInsertHandlers));
0141         m_list.prepend(item);
0142         callChangeHandlers(item, 0,
0143                            Utils::mem_fn(&QueryResultInputImpl<ItemType>::postInsertHandlers));
0144     }
0145 
0146     void insert(int index, const ItemType &item)
0147     {
0148         cleanupResults();
0149         callChangeHandlers(item, index,
0150                            Utils::mem_fn(&QueryResultInputImpl<ItemType>::preInsertHandlers));
0151         m_list.insert(index, item);
0152         callChangeHandlers(item, index,
0153                            Utils::mem_fn(&QueryResultInputImpl<ItemType>::postInsertHandlers));
0154     }
0155 
0156     ItemType takeFirst()
0157     {
0158         cleanupResults();
0159         const ItemType item = m_list.first();
0160         callChangeHandlers(item, 0,
0161                            Utils::mem_fn(&QueryResultInputImpl<ItemType>::preRemoveHandlers));
0162         m_list.removeFirst();
0163         callChangeHandlers(item, 0,
0164                            Utils::mem_fn(&QueryResultInputImpl<ItemType>::postRemoveHandlers));
0165         return item;
0166     }
0167 
0168     void removeFirst()
0169     {
0170         takeFirst();
0171     }
0172 
0173     ItemType takeLast()
0174     {
0175         cleanupResults();
0176         const ItemType item = m_list.last();
0177         callChangeHandlers(item, m_list.size()-1,
0178                            Utils::mem_fn(&QueryResultInputImpl<ItemType>::preRemoveHandlers));
0179         m_list.removeLast();
0180         callChangeHandlers(item, m_list.size(),
0181                            Utils::mem_fn(&QueryResultInputImpl<ItemType>::postRemoveHandlers));
0182         return item;
0183     }
0184 
0185     void removeLast()
0186     {
0187         takeLast();
0188     }
0189 
0190     ItemType takeAt(int index)
0191     {
0192         cleanupResults();
0193         const ItemType item = m_list.at(index);
0194         callChangeHandlers(item, index,
0195                            Utils::mem_fn(&QueryResultInputImpl<ItemType>::preRemoveHandlers));
0196         m_list.removeAt(index);
0197         callChangeHandlers(item, index,
0198                            Utils::mem_fn(&QueryResultInputImpl<ItemType>::postRemoveHandlers));
0199         return item;
0200     }
0201 
0202     void removeAt(int index)
0203     {
0204         takeAt(index);
0205     }
0206 
0207     void replace(int index, const ItemType &item)
0208     {
0209         cleanupResults();
0210         callChangeHandlers(m_list.at(index), index,
0211                            Utils::mem_fn(&QueryResultInputImpl<ItemType>::preReplaceHandlers));
0212         m_list.replace(index, item);
0213         callChangeHandlers(item, index,
0214                            Utils::mem_fn(&QueryResultInputImpl<ItemType>::postReplaceHandlers));
0215     }
0216 
0217     QueryResultProvider &operator<< (const ItemType &item)
0218     {
0219         append(item);
0220         return *this;
0221     }
0222 
0223 private:
0224     void cleanupResults()
0225     {
0226         m_results.erase(std::remove_if(m_results.begin(),
0227                                        m_results.end(),
0228                                        Utils::mem_fn(&QueryResultInputImpl<ItemType>::WeakPtr::isNull)),
0229                         m_results.end());
0230     }
0231 
0232     typedef std::function<ChangeHandlerList(ResultPtr)> ChangeHandlerGetter;
0233 
0234     void callChangeHandlers(const ItemType &item, int index, const ChangeHandlerGetter &handlerGetter)
0235     {
0236         for (auto weakResult : m_results)
0237         {
0238             auto result = weakResult.toStrongRef();
0239             if (!result) continue;
0240             for (auto handler : handlerGetter(result))
0241             {
0242                 handler(item, index);
0243             }
0244         }
0245     }
0246 
0247     friend class QueryResultInputImpl<ItemType>;
0248     QList<ItemType> m_list;
0249     QList<ResultWeakPtr> m_results;
0250 };
0251 
0252 }
0253 
0254 #endif // DOMAIN_QUERYRESULTPROVIDER_H