LeechCraft 0.6.70-16373-g319c272718
Modular cross-platform feature rich live environment.
Loading...
Searching...
No Matches
itemsfinder.cpp
Go to the documentation of this file.
1/**********************************************************************
2 * LeechCraft - modular cross-platform feature rich internet client.
3 * Copyright (C) 2006-2014 Georg Rudoy
4 *
5 * Distributed under the Boost Software License, Version 1.0.
6 * (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt)
7 **********************************************************************/
8
9#include "itemsfinder.h"
10#include <QDir>
11#include <QTimer>
12#include <QtDebug>
13#include <QtConcurrentRun>
14#include <util/sll/prelude.h>
15#include <util/sll/qtutil.h>
17#include "xdg.h"
18#include "item.h"
19
20namespace LC::Util::XDG
21{
23 const QList<Type>& types, QObject *parent)
24 : QObject { parent }
25 , Proxy_ { proxy }
26 , Types_ { types }
27 {
28 QTimer::singleShot (1000, this, &ItemsFinder::Update);
29 }
30
32 {
33 return IsReady_;
34 }
35
37 {
38 return Items_;
39 }
40
41 Item_ptr ItemsFinder::FindItem (const QString& id) const
42 {
43 for (const auto& list : Items_)
44 {
45 const auto pos = std::find_if (list.begin (), list.end (),
46 [&id] (const Item_ptr& item) { return item->GetPermanentID () == id; });
47 if (pos != list.end ())
48 return *pos;
49 }
50
51 return {};
52 }
53
54 namespace
55 {
56 using Cat2ID2Item_t = QHash<QString, QHash<QString, Item_ptr>>;
57
58 Cat2ID2Item_t ItemsList2Map (const Cat2Items_t& items)
59 {
60 Cat2ID2Item_t result;
61
62 for (const auto& pair : Util::Stlize (items))
63 {
64 auto& map = result [pair.first];
65 for (const auto& item : pair.second)
66 map [item->GetPermanentID ()] = item;
67 }
68
69 return result;
70 }
71
72 Cat2Items_t ItemsMap2List (const Cat2ID2Item_t& items)
73 {
74 Cat2Items_t result;
75
76 for (const auto& pair : Util::Stlize (items))
77 std::copy (pair.second.begin (), pair.second.end (),
78 std::back_inserter (result [pair.first]));
79
80 return result;
81 }
82
83 QStringList ScanDir (const QString& path)
84 {
85 const auto& infos = QDir (path).entryInfoList ({ QStringLiteral ("*.desktop") },
86 QDir::Files | QDir::AllDirs | QDir::NoDotAndDotDot);
87
88 return Util::ConcatMap (infos,
89 [] (const QFileInfo& info)
90 {
91 return info.isDir () ?
92 ScanDir (info.absoluteFilePath ()) :
93 QStringList { info.absoluteFilePath () };
94 });
95 }
96
97 Cat2ID2Item_t FindAndParse (const QList<Type>& types)
98 {
99 Cat2ID2Item_t result;
100
101 QStringList paths;
102 for (const auto& dir : ToPaths (types))
103 paths << ScanDir (dir);
104
105 for (const auto& path : paths)
106 {
107 Item_ptr item;
108 try
109 {
110 item = Item::FromDesktopFile (path);
111 }
112 catch (const std::exception& e)
113 {
114 qWarning () << Q_FUNC_INFO
115 << "error parsing"
116 << path
117 << e.what ();
118 continue;
119 }
120
121 if (!item->IsValid ())
122 {
123 qWarning () << Q_FUNC_INFO
124 << "invalid item"
125 << path;
126 continue;
127 }
128
129 for (const auto& cat : item->GetCategories ())
130 if (!cat.startsWith ("X-"_ql))
131 result [cat] [item->GetPermanentID ()] = item;
132 }
133
134 return result;
135 }
136
137 template<typename T>
138 struct DiffResult
139 {
140 std::decay_t<T> Added_;
141 std::decay_t<T> Removed_;
142 std::decay_t<T> Intersection_;
143
144 DiffResult (T&& oldCont, T&& newCont)
145 {
146 std::set_difference (oldCont.begin (), oldCont.end (),
147 newCont.begin (), newCont.end (),
148 std::back_inserter (Removed_));
149 std::set_difference (newCont.begin (), newCont.end (),
150 oldCont.begin (), oldCont.end (),
151 std::back_inserter (Added_));
152
153 std::set_intersection (oldCont.begin (), oldCont.end (),
154 newCont.begin (), newCont.end (),
155 std::back_inserter (Intersection_));
156 }
157
158 bool HasChanges () const
159 {
160 return !Removed_.isEmpty () || !Added_.isEmpty ();
161 }
162 };
163
164 template<typename Container>
165 DiffResult<Container> CalcDiff (Container&& oldCont, Container&& newCont)
166 {
167 return { std::forward<Container> (oldCont), std::forward<Container> (newCont) };
168 }
169
170 std::optional<Cat2Items_t> Merge (const Cat2Items_t& existing, Cat2ID2Item_t result)
171 {
172 auto ourItems = ItemsList2Map (existing);
173
174 using std::swap;
175
176 const auto& diffCats = CalcDiff (Util::Sorted (existing.keys ()),
177 Util::Sorted (result.keys ()));
178
179 for (const auto& removed : diffCats.Removed_)
180 ourItems.remove (removed);
181 for (const auto& added : diffCats.Added_)
182 swap (ourItems [added], result [added]);
183
184 bool changed = diffCats.HasChanges ();
185
186 for (const auto& cat : diffCats.Intersection_)
187 {
188 auto& ourList = ourItems [cat];
189 auto& newList = result [cat];
190 const auto& diffItems = CalcDiff (Util::Sorted (ourList.keys ()),
191 Util::Sorted (newList.keys ()));
192
193 changed = changed || diffItems.HasChanges ();
194
195 for (const auto& removed : diffItems.Removed_)
196 ourList.remove (removed);
197 for (const auto& added : diffItems.Added_)
198 swap (ourList [added], newList [added]);
199
200 for (const auto& existing : diffItems.Intersection_)
201 if (*ourList [existing] != *newList [existing])
202 {
203 swap (ourList [existing], newList [existing]);
204 changed = true;
205 }
206 }
207
208 if (!changed)
209 return {};
210
211 return ItemsMap2List (ourItems);
212 }
213 }
214
216 {
217 if (IsScanning_)
218 return;
219
220 IsScanning_ = true;
221
222 Util::Sequence (this, QtConcurrent::run (FindAndParse, Types_)) >>
223 [this] (const Cat2ID2Item_t& result)
224 {
225 return QtConcurrent::run (Merge, Items_, result);
226 } >>
227 [this] (const std::optional<Cat2Items_t>& result)
228 {
229 IsScanning_ = false;
230 IsReady_ = true;
231
232 if (result)
233 {
234 Items_ = *result;
235 emit itemsListChanged ();
236 }
237 };
238 }
239}
static Item_ptr FromDesktopFile(const QString &file)
Loads the XDG .desktop item from file.
Definition item.cpp:197
bool IsReady() const
Checks whether this items finder is ready.
ItemsFinder(const ICoreProxy_ptr &, const QList< Type > &types, QObject *parent=nullptr)
Constructs the items finder for the given types.
Item_ptr FindItem(const QString &permanentID) const
Finds an XDG item for the given permanent ID.
void itemsListChanged()
Notifies when the list of items changes in any way.
Cat2Items_t GetItems() const
Returns the categorized list of XDG items.
QList< QNetworkCookie > Added_
QList< QNetworkCookie > Removed_
std::shared_ptr< ICoreProxy > ICoreProxy_ptr
Definition icoreproxy.h:181
std::decay_t< T > Intersection_
QHash< QString, QList< Item_ptr > > Cat2Items_t
Definition itemsfinder.h:22
std::shared_ptr< Item > Item_ptr
Definition item.h:24
QStringList ToPaths(const QList< Type > &types)
Returns a set of typical directories with desktop files of the given types.
Definition itemtypes.cpp:60
auto Stlize(Assoc &&assoc) noexcept
Converts an Qt's associative sequence assoc to an STL-like iteratable range.
Definition qtutil.h:48
auto ConcatMap(Cont &&c, F &&f)
Definition prelude.h:168
decltype(auto) Sorted(Cont &&cont)
Definition prelude.h:196
void swap(FDGuard &g1, FDGuard &g2)
Definition fdguard.cpp:51