libept
desktop.h
Go to the documentation of this file.
1 
2 
3 #include <wibble/string.h>
4 
5 #include <ept/token.h>
6 #include <ept/core/desktopfile.h>
7 #include <ept/core/source.h>
8 
9 #include <set>
10 #include <vector>
11 #include <fstream>
12 #include <sstream>
13 #include <iterator>
14 #include <functional>
15 
16 #include <dirent.h>
17 
18 #ifndef EPT_CORE_DESKTOP_H
19 #define EPT_CORE_DESKTOP_H
20 
21 namespace ept {
22 namespace core {
23 namespace desktop {
24 
26 
27 template< PropertyId > struct PropertyType {};
28 template<> struct PropertyType< Name > { typedef std::string T; };
29 template<> struct PropertyType< Group > { typedef std::string T; };
30 template<> struct PropertyType< ShortDescription > { typedef std::string T; };
31 template<> struct PropertyType< Package > { typedef ept::Token T; };
32 template<> struct PropertyType< Icon > { typedef std::string T; };
33 
34 typedef std::set< std::string > Categories;
35 
36 struct Category {
37  std::string name;
38  operator std::string() const { return name; }
39 };
40 
41 inline std::istream &operator >>( std::istream &i, Category &cat ) {
42  char c;
43  cat.name = "";
44  while ( i.peek() != EOF ) {
45  c = i.get();
46  if ( c == ';' ) return i;
47  cat.name += c;
48  }
49  return i;
50 }
51 
52 struct Entry : wibble::mixin::Comparable< Entry > {
53  Entry() {}
54  Entry( std::string n, std::string g,
55  std::string p, std::string d , std::string i )
56  : m_name( n ),
57  m_package( p ),
58  m_description( d ),
59  m_icon( i )
60  { setCategories( g ); }
61 
62  void load( std::string file ) {
63  m_id = file;
64  std::ifstream i( file.c_str() );
65  if ( !i.is_open() )
66  return; // throw?
67  desktop::File e;
68  i >> e;
69  i.close();
70  desktop::File::Group &g = e.group( "Desktop Entry" );
71  m_name = g.entry( "Name" ).value;
72  m_description = g.entry( "Comment" ).value;
73  if ( m_description == "" )
74  m_description = g.entry( "GenericName" ).value;
75  m_package = g.entry( "X-AppInstall-Package" ).value;
76  // m_group = g.entry( "Categories" ).value;
77  m_icon = g.entry( "Icon" ).value;
78  setCategories( g.entry( "Categories" ).value );
79  }
80 
81  void setCategories( std::string s ) {
82  std::istringstream i( s );
83  m_categories.clear();
84  std::remove_copy_if(
85  std::istream_iterator< Category >( i ),
86  std::istream_iterator< Category >(),
87  std::inserter( m_categories, m_categories.begin() ),
88  std::bind1st( std::equal_to< std::string >(), "" ) );
89  }
90 
91  Categories categories() const { return m_categories; }
92  bool inCategory( std::string c ) const {
93  return m_categories.find( c ) != m_categories.end();
94  }
95  std::string id() const { return m_id; }
96  std::string name() const { return m_name; }
97  std::string package() const { return m_package; }
98  std::string description() const { return m_description; }
99  std::string icon() const { return m_icon; }
100  bool operator< ( const Entry &o ) const {
101  if ( m_name < o.m_name ) return true;
102  if ( m_name == o.m_name )
103  if ( m_package < o.m_package ) return true;
104  return false;
105  }
106 protected:
110 };
111 
112 struct InternalList {
113  std::string dir;
114  std::string current;
115  mutable Entry entry;
116  off_t offset;
117  mutable bool loaded;
118 
119  InternalList() : dir( "" ), offset( -2 ), loaded( false ) {}
120  InternalList( std::string d ) : dir( d ), offset( -1 ), loaded( false )
121  {
122  firstFile();
123  }
124 
125  Entry head() const {
126  if (!loaded)
127  entry.load( current );
128  loaded = true;
129  return entry;
130  }
131 
132  bool empty() const {
133  return (offset == -2);
134  }
135 
136  void firstFile() {
137  offset = -1;
138  nextFile();
139  }
140 
141  InternalList tail() const {
142  InternalList r = *this;
143  r.nextFile();
144  return r;
145  }
146 
147  void nextFile() {
148  loaded = false;
149  DIR *d = opendir( dir.c_str() );
150  if ( !d ) {
151  offset = -2;
152  closedir( d );
153  return;
154  }
155 
156  if ( offset != -1 )
157  seekdir( d, offset );
158 
159  dirent *ent = 0;
160  while ( ( ent = readdir( d ) ) != 0 ) {
161  std::string name( ent->d_name );
162  if ( name == "." || name == ".." )
163  continue;
164  if ( !wibble::str::endsWith( name, ".desktop" ) )
165  continue;
166  current = dir + "/" + name;
167  offset = telldir( d );
168  closedir( d );
169  return;
170  }
171  closedir( d );
172  offset = -2;
173  }
174 };
175 
176 struct Setup {
177  typedef ept::Token Token;
178  typedef Entry Internal;
181 };
182 
183 struct GroupPolicy {
184  virtual std::string group( const Entry &e )
185  {
186  return wibble::str::fmt( e.categories() );
187  }
188  virtual ~GroupPolicy() {}
189 };
190 
191 struct Source : core::Source< Source, Setup, PropertyType >
192 {
193  std::string m_dir;
194 
197 
198  Source( std::string dir ) : m_dir( dir ),
200 
202  return InternalList( m_dir );
203  }
204 
206  Token t;
207  t._id = std::string( "desktop:" ) + i.id();
208  return t;
209  }
210 
212  Entry e;
213  e.load( t.desktop() );
214  return e;
215  }
216 
218  m_policy = p;
219  }
220 
221  template< PropertyId p >
223 
224  struct IsInGroup {
225  std::string g;
226  IsInGroup( std::string _g = "" ) : g( _g ) {}
227  bool operator()( Token, std::string gr ) const {
228  return gr == g;
229  }
230  };
231 
232  PropertyFilter< Group, IsInGroup >::T group( std::string id )
233  {
234  return propertyFilter< Group >( IsInGroup( id ) );
235  }
236 
237  static std::string projectGroup( ComposedList< Name > t ) {
238  return t.get< Group >();
239  }
240 
241  list::Unique< list::Sorted<
242  list::Map< ComposedList< Name >,
243  __typeof( std::ptr_fun( &projectGroup ) ) > > >
245  return list::unique(
246  list::sort( list::map( list< Name >(),
247  std::ptr_fun( &projectGroup ) ) ) );
248  }
249 };
250 
251 template<> inline std::string Source::getInternal< Name >( Entry e ) {
252  return e.name();
253 }
254 
255 template<> inline std::string Source::getInternal< Icon >( Entry e ) {
256  return e.icon();
257 }
258 
259 template<> inline ept::Token Source::getInternal< Package >( Entry e ) {
260  ept::Token t;
261  t._id = e.package();
262  return t;
263 }
264 
265 template<> inline std::string Source::getInternal< Group >( Entry e ) {
266  return m_policy->group( e );
267 }
268 
269 template<> inline std::string Source::getInternal< ShortDescription >( Entry e ) {
270  return e.description();
271 }
272 
273 }
274 }
275 }
276 
277 #endif