LeechCraft  0.6.70-13729-g7046a9d2a7
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  * Boost Software License - Version 1.0 - August 17th, 2003
6  *
7  * Permission is hereby granted, free of charge, to any person or organization
8  * obtaining a copy of the software and accompanying documentation covered by
9  * this license (the "Software") to use, reproduce, display, distribute,
10  * execute, and transmit the Software, and to prepare derivative works of the
11  * Software, and to permit third-parties to whom the Software is furnished to
12  * do so, all subject to the following:
13  *
14  * The copyright notices in the Software and this entire statement, including
15  * the above license grant, this restriction and the following disclaimer,
16  * must be included in all copies of the Software, in whole or in part, and
17  * all derivative works of the Software, unless such copies or derivative
18  * works are solely in the form of machine-executable object code generated by
19  * a source language processor.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
24  * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
25  * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
26  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27  * DEALINGS IN THE SOFTWARE.
28  **********************************************************************/
29 
30 #include "itemsfinder.h"
31 #include <QDir>
32 #include <QTimer>
33 #include <QtDebug>
34 #include <QtConcurrentRun>
35 #include <util/sll/prelude.h>
36 #include <util/sll/qtutil.h>
37 #include <util/threads/futures.h>
38 #include "xdg.h"
39 #include "item.h"
40 
41 namespace LC
42 {
43 namespace Util
44 {
45 namespace XDG
46 {
48  const QList<Type>& types, QObject *parent)
49  : QObject { parent }
50  , Proxy_ { proxy }
51  , Types_ { types }
52  {
53  QTimer::singleShot (1000, this, SLOT (update ()));
54  }
55 
56  bool ItemsFinder::IsReady () const
57  {
58  return IsReady_;
59  }
60 
62  {
63  return Items_;
64  }
65 
66  Item_ptr ItemsFinder::FindItem (const QString& id) const
67  {
68  for (const auto& list : Items_)
69  {
70  const auto pos = std::find_if (list.begin (), list.end (),
71  [&id] (const Item_ptr& item) { return item->GetPermanentID () == id; });
72  if (pos != list.end ())
73  return *pos;
74  }
75 
76  return {};
77  }
78 
79  namespace
80  {
81  using Cat2ID2Item_t = QHash<QString, QHash<QString, Item_ptr>>;
82 
83  Cat2ID2Item_t ItemsList2Map (const Cat2Items_t& items)
84  {
85  Cat2ID2Item_t result;
86 
87  for (const auto& pair : Util::Stlize (items))
88  {
89  auto& map = result [pair.first];
90  for (const auto& item : pair.second)
91  map [item->GetPermanentID ()] = item;
92  }
93 
94  return result;
95  }
96 
97  Cat2Items_t ItemsMap2List (const Cat2ID2Item_t& items)
98  {
99  Cat2Items_t result;
100 
101  for (const auto& pair : Util::Stlize (items))
102  std::copy (pair.second.begin (), pair.second.end (),
103  std::back_inserter (result [pair.first]));
104 
105  return result;
106  }
107 
108  QStringList ScanDir (const QString& path)
109  {
110  const auto& infos = QDir (path).entryInfoList ({ "*.desktop" },
111  QDir::Files | QDir::AllDirs | QDir::NoDotAndDotDot);
112 
113  return Util::ConcatMap (infos,
114  [] (const QFileInfo& info)
115  {
116  return info.isDir () ?
117  ScanDir (info.absoluteFilePath ()) :
118  QStringList { info.absoluteFilePath () };
119  });
120  }
121 
122  Cat2ID2Item_t FindAndParse (const QList<Type>& types)
123  {
124  Cat2ID2Item_t result;
125 
126  QStringList paths;
127  for (const auto& dir : ToPaths (types))
128  paths << ScanDir (dir);
129 
130  for (const auto& path : paths)
131  {
132  Item_ptr item;
133  try
134  {
135  item = Item::FromDesktopFile (path);
136  }
137  catch (const std::exception& e)
138  {
139  qWarning () << Q_FUNC_INFO
140  << "error parsing"
141  << path
142  << e.what ();
143  continue;
144  }
145 
146  if (!item->IsValid ())
147  {
148  qWarning () << Q_FUNC_INFO
149  << "invalid item"
150  << path;
151  continue;
152  }
153 
154  for (const auto& cat : item->GetCategories ())
155  if (!cat.startsWith ("X-"))
156  result [cat] [item->GetPermanentID ()] = item;
157  }
158 
159  return result;
160  }
161 
162  template<typename T>
163  struct DiffResult
164  {
165  std::decay_t<T> Added_;
166  std::decay_t<T> Removed_;
167  std::decay_t<T> Intersection_;
168 
169  DiffResult (T&& oldCont, T&& newCont)
170  {
171  std::set_difference (oldCont.begin (), oldCont.end (),
172  newCont.begin (), newCont.end (),
173  std::back_inserter (Removed_));
174  std::set_difference (newCont.begin (), newCont.end (),
175  oldCont.begin (), oldCont.end (),
176  std::back_inserter (Added_));
177 
178  std::set_intersection (oldCont.begin (), oldCont.end (),
179  newCont.begin (), newCont.end (),
180  std::back_inserter (Intersection_));
181  }
182 
183  bool HasChanges () const
184  {
185  return !Removed_.isEmpty () || !Added_.isEmpty ();
186  }
187  };
188 
189  template<typename Container>
190  DiffResult<Container> CalcDiff (Container&& oldCont, Container&& newCont)
191  {
192  return { std::forward<Container> (oldCont), std::forward<Container> (newCont) };
193  }
194 
195  boost::optional<Cat2Items_t> Merge (const Cat2Items_t& existing, Cat2ID2Item_t result)
196  {
197  auto ourItems = ItemsList2Map (existing);
198 
199  using std::swap;
200 
201  const auto& diffCats = CalcDiff (Util::Sorted (existing.keys ()),
202  Util::Sorted (result.keys ()));
203 
204  for (const auto& removed : diffCats.Removed_)
205  ourItems.remove (removed);
206  for (const auto& added : diffCats.Added_)
207  swap (ourItems [added], result [added]);
208 
209  bool changed = diffCats.HasChanges ();
210 
211  for (const auto& cat : diffCats.Intersection_)
212  {
213  auto& ourList = ourItems [cat];
214  auto& newList = result [cat];
215  const auto& diffItems = CalcDiff (Util::Sorted (ourList.keys ()),
216  Util::Sorted (newList.keys ()));
217 
218  changed = changed || diffItems.HasChanges ();
219 
220  for (const auto& removed : diffItems.Removed_)
221  ourList.remove (removed);
222  for (const auto& added : diffItems.Added_)
223  swap (ourList [added], newList [added]);
224 
225  for (const auto& existing : diffItems.Intersection_)
226  if (*ourList [existing] != *newList [existing])
227  {
228  swap (ourList [existing], newList [existing]);
229  changed = true;
230  }
231  }
232 
233  if (!changed)
234  return {};
235 
236  return ItemsMap2List (ourItems);
237  }
238  }
239 
241  {
242  if (IsScanning_)
243  return;
244 
245  IsScanning_ = true;
246 
247  Util::Sequence (this, QtConcurrent::run (FindAndParse, Types_)) >>
248  [this] (Cat2ID2Item_t result)
249  {
250  return QtConcurrent::run (Merge, Items_, result);
251  } >>
252  [this] (const boost::optional<Cat2Items_t>& result)
253  {
254  IsScanning_ = false;
255  IsReady_ = true;
256 
257  if (result)
258  {
259  Items_ = *result;
260  emit itemsListChanged ();
261  }
262  };
263  }
264 }
265 }
266 }
void itemsListChanged()
Notifies when the list of items changes in any way.
bool IsReady() const
Checks whether this items finder is ready.
Definition: itemsfinder.cpp:56
auto Stlize(Assoc &&assoc)
Converts an Qt&#39;s associative sequence assoc to an STL-like iteratable range.
Definition: qtutil.h:115
Item_ptr FindItem(const QString &permanentID) const
Finds an XDG item for the given permanent ID.
Definition: itemsfinder.cpp:66
void swap(FDGuard &g1, FDGuard &g2)
Definition: fdguard.cpp:74
void update()
Updates the list of items.
std::decay_t< T > Removed_
ItemsFinder(ICoreProxy_ptr, const QList< Type > &types, QObject *parent=nullptr)
Constructs the items finder for the given types.
Definition: itemsfinder.cpp:47
Cat2Items_t GetItems() const
Returns the categorized list of XDG items.
Definition: itemsfinder.cpp:61
decltype(auto) Sorted(Cont &&cont)
Definition: prelude.h:233
std::shared_ptr< ICoreProxy > ICoreProxy_ptr
Definition: icoreproxy.h:202
std::decay_t< T > Intersection_
std::decay_t< T > Added_
std::shared_ptr< Item > Item_ptr
Definition: item.h:49
QStringList ToPaths(const QList< Type > &types)
Returns a set of typical directories with desktop files of the given types.
Definition: itemtypes.cpp:85
QHash< QString, QList< Item_ptr > > Cat2Items_t
Definition: itemsfinder.h:47
Definition: constants.h:35
auto ConcatMap(Cont &&c, F &&f)
Definition: prelude.h:205
static Item_ptr FromDesktopFile(const QString &file)
Loads the XDG .desktop item from file.
Definition: item.cpp:221