LeechCraft  0.6.70-15082-g543737046d
Modular cross-platform feature rich live environment.
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>
16 #include <util/threads/futures.h>
17 #include "xdg.h"
18 #include "item.h"
19 
20 namespace 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 
31  bool ItemsFinder::IsReady () const
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 
215  void ItemsFinder::Update ()
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 }
LC::Util::XDG::Item_ptr
std::shared_ptr< Item > Item_ptr
Definition: item.h:30
LC::Util::XDG::ItemsFinder::ItemsFinder
ItemsFinder(const ICoreProxy_ptr &, const QList< Type > &types, QObject *parent=nullptr)
Constructs the items finder for the given types.
Definition: itemsfinder.cpp:28
LC::Util::XDG::ItemsFinder::GetItems
Cat2Items_t GetItems() const
Returns the categorized list of XDG items.
Definition: itemsfinder.cpp:42
QList< Type >
Items_
QMultiMap< QDateTime, QString > Items_
Definition: networkdiskcachegc.cpp:49
LC::Util::swap
void swap(FDGuard &g1, FDGuard &g2)
Definition: fdguard.cpp:58
LC::Util::XDG::Item::FromDesktopFile
static Item_ptr FromDesktopFile(const QString &file)
Loads the XDG .desktop item from file.
Definition: item.cpp:203
LC::Util::Stlize
auto Stlize(Assoc &&assoc) noexcept
Converts an Qt's associative sequence assoc to an STL-like iteratable range.
Definition: qtutil.h:49
futures.h
xdg.h
itemsfinder.h
Removed_
std::decay_t< T > Removed_
Definition: itemsfinder.cpp:147
LC::Util::Sorted
decltype(auto) Sorted(Cont &&cont)
Definition: prelude.h:218
LC::Util::XDG
Definition: desktopparser.cpp:15
LC::Util::XDG::ItemsFinder::FindItem
Item_ptr FindItem(const QString &permanentID) const
Finds an XDG item for the given permanent ID.
Definition: itemsfinder.cpp:47
LC::Util::XDG::ItemsFinder::Update
void Update()
Definition: itemsfinder.cpp:221
ICoreProxy_ptr
std::shared_ptr< ICoreProxy > ICoreProxy_ptr
Definition: icoreproxy.h:181
qtutil.h
LC::Util::XDG::ToPaths
QStringList ToPaths(const QList< Type > &types)
Returns a set of typical directories with desktop files of the given types.
Definition: itemtypes.cpp:66
Added_
std::decay_t< T > Added_
Definition: itemsfinder.cpp:146
LC::Util::XDG::ItemsFinder::itemsListChanged
void itemsListChanged()
Notifies when the list of items changes in any way.
prelude.h
LC::Util::XDG::Cat2Items_t
QHash< QString, QList< Item_ptr > > Cat2Items_t
Definition: itemsfinder.h:28
Intersection_
std::decay_t< T > Intersection_
Definition: itemsfinder.cpp:148
LC::Util::ConcatMap
auto ConcatMap(Cont &&c, F &&f)
Definition: prelude.h:190
LC::Util::XDG::ItemsFinder::IsReady
bool IsReady() const
Checks whether this items finder is ready.
Definition: itemsfinder.cpp:37
item.h