00001
00002
00003 #include <wibble/string.h>
00004
00005 #include <ept/token.h>
00006 #include <ept/core/desktopfile.h>
00007 #include <ept/core/source.h>
00008
00009 #include <set>
00010 #include <vector>
00011 #include <fstream>
00012 #include <sstream>
00013 #include <iterator>
00014 #include <functional>
00015
00016 #include <dirent.h>
00017
00018 #ifndef EPT_CORE_DESKTOP_H
00019 #define EPT_CORE_DESKTOP_H
00020
00021 namespace ept {
00022 namespace core {
00023 namespace desktop {
00024
00025 typedef enum { Name, Group, ShortDescription, Package, Icon } PropertyId;
00026
00027 template< PropertyId > struct PropertyType {};
00028 template<> struct PropertyType< Name > { typedef std::string T; };
00029 template<> struct PropertyType< Group > { typedef std::string T; };
00030 template<> struct PropertyType< ShortDescription > { typedef std::string T; };
00031 template<> struct PropertyType< Package > { typedef ept::Token T; };
00032 template<> struct PropertyType< Icon > { typedef std::string T; };
00033
00034 typedef std::set< std::string > Categories;
00035
00036 struct Category {
00037 std::string name;
00038 operator std::string() const { return name; }
00039 };
00040
00041 inline std::istream &operator >>( std::istream &i, Category &cat ) {
00042 char c;
00043 cat.name = "";
00044 while ( i.peek() != EOF ) {
00045 c = i.get();
00046 if ( c == ';' ) return i;
00047 cat.name += c;
00048 }
00049 return i;
00050 }
00051
00052 struct Entry : wibble::mixin::Comparable< Entry > {
00053 Entry() {}
00054 Entry( std::string n, std::string g,
00055 std::string p, std::string d , std::string i )
00056 : m_name( n ),
00057 m_package( p ),
00058 m_description( d ),
00059 m_icon( i )
00060 { setCategories( g ); }
00061
00062 void load( std::string file ) {
00063 m_id = file;
00064 std::ifstream i( file.c_str() );
00065 if ( !i.is_open() )
00066 return;
00067 desktop::File e;
00068 i >> e;
00069 i.close();
00070 desktop::File::Group &g = e.group( "Desktop Entry" );
00071 m_name = g.entry( "Name" ).value;
00072 m_description = g.entry( "Comment" ).value;
00073 if ( m_description == "" )
00074 m_description = g.entry( "GenericName" ).value;
00075 m_package = g.entry( "X-AppInstall-Package" ).value;
00076
00077 m_icon = g.entry( "Icon" ).value;
00078 setCategories( g.entry( "Categories" ).value );
00079 }
00080
00081 void setCategories( std::string s ) {
00082 std::istringstream i( s );
00083 m_categories.clear();
00084 std::remove_copy_if(
00085 std::istream_iterator< Category >( i ),
00086 std::istream_iterator< Category >(),
00087 std::inserter( m_categories, m_categories.begin() ),
00088 std::bind1st( std::equal_to< std::string >(), "" ) );
00089 }
00090
00091 Categories categories() const { return m_categories; }
00092 bool inCategory( std::string c ) const {
00093 return m_categories.find( c ) != m_categories.end();
00094 }
00095 std::string id() const { return m_id; }
00096 std::string name() const { return m_name; }
00097 std::string package() const { return m_package; }
00098 std::string description() const { return m_description; }
00099 std::string icon() const { return m_icon; }
00100 bool operator< ( const Entry &o ) const {
00101 if ( m_name < o.m_name ) return true;
00102 if ( m_name == o.m_name )
00103 if ( m_package < o.m_package ) return true;
00104 return false;
00105 }
00106 protected:
00107 std::string m_name, m_package, m_description, m_icon, m_id;
00108 bool m_supported, m_free;
00109 Categories m_categories;
00110 };
00111
00112 struct InternalList {
00113 std::string dir;
00114 std::string current;
00115 off_t offset;
00116
00117 InternalList() : dir( "" ), offset( -2 ) {}
00118 InternalList( std::string d ) : dir( d ), offset( -1 )
00119 {
00120 firstFile();
00121 }
00122
00123 Entry head() const {
00124 Entry r;
00125 r.load( current );
00126 return r;
00127 }
00128
00129 bool empty() const {
00130 return (offset == -2);
00131 }
00132
00133 void firstFile() {
00134 offset = -1;
00135 nextFile();
00136 }
00137
00138 InternalList tail() const {
00139 InternalList r = *this;
00140 r.nextFile();
00141 return r;
00142 }
00143
00144 void nextFile() {
00145 DIR *d = opendir( dir.c_str() );
00146 if ( !d ) {
00147 offset = -2;
00148 closedir( d );
00149 return;
00150 }
00151
00152 if ( offset != -1 )
00153 seekdir( d, offset );
00154
00155 dirent *ent = 0;
00156 while ( ( ent = readdir( d ) ) != 0 ) {
00157 std::string name( ent->d_name );
00158 if ( name == "." || name == ".." )
00159 continue;
00160 if ( !wibble::str::endsWith( name, ".desktop" ) )
00161 continue;
00162 current = dir + "/" + name;
00163 offset = telldir( d );
00164 closedir( d );
00165 return;
00166 }
00167 closedir( d );
00168 offset = -2;
00169 }
00170 };
00171
00172 struct Setup {
00173 typedef ept::Token Token;
00174 typedef Entry Internal;
00175 typedef desktop::PropertyId PropertyId;
00176 typedef desktop::InternalList InternalList;
00177 };
00178
00179 struct GroupPolicy {
00180 virtual std::string group( const Entry &e )
00181 {
00182 return wibble::str::fmt( e.categories() );
00183 }
00184 };
00185
00186 struct Source : core::Source< Source, Setup, PropertyType >
00187 {
00188 std::string m_dir;
00189
00190 GroupPolicy m_defaultPolicy;
00191 GroupPolicy *m_policy;
00192
00193 Source( std::string dir ) : m_dir( dir ),
00194 m_policy( &m_defaultPolicy ) {}
00195
00196 InternalList listInternal() {
00197 return InternalList( m_dir );
00198 }
00199
00200 Token getToken( Entry i ) {
00201 Token t;
00202 t._id = std::string( "desktop:" ) + i.id();
00203 return t;
00204 }
00205
00206 Entry lookupToken( Token t ) {
00207 Entry e;
00208 e.load( t.desktop() );
00209 return e;
00210 }
00211
00212 void setGroupPolicy( GroupPolicy *p ) {
00213 m_policy = p;
00214 }
00215
00216 template< PropertyId p >
00217 typename PropertyType< p >::T getInternal( Entry );
00218
00219 struct IsInGroup {
00220 std::string g;
00221 IsInGroup( std::string _g = "" ) : g( _g ) {}
00222 bool operator()( Token, std::string gr ) const {
00223 return gr == g;
00224 }
00225 };
00226
00227 PropertyFilter< Group, IsInGroup >::T group( std::string id )
00228 {
00229 return propertyFilter< Group >( IsInGroup( id ) );
00230 }
00231
00232 static std::string projectGroup( ComposedList< Name > t ) {
00233 return t.get< Group >();
00234 }
00235
00236 list::Unique< list::Sorted<
00237 list::Map< ComposedList< Name >,
00238 __typeof( std::ptr_fun( &projectGroup ) ) > > >
00239 groupList() {
00240 return list::unique(
00241 list::sort( list::map( list< Name >(),
00242 std::ptr_fun( &projectGroup ) ) ) );
00243 }
00244 };
00245
00246 template<> inline std::string Source::getInternal< Name >( Entry e ) {
00247 return e.name();
00248 }
00249
00250 template<> inline std::string Source::getInternal< Icon >( Entry e ) {
00251 return e.icon();
00252 }
00253
00254 template<> inline ept::Token Source::getInternal< Package >( Entry e ) {
00255 ept::Token t;
00256 t._id = e.package();
00257 return t;
00258 }
00259
00260 template<> inline std::string Source::getInternal< Group >( Entry e ) {
00261 return m_policy->group( e );
00262 }
00263
00264 template<> inline std::string Source::getInternal< ShortDescription >( Entry e ) {
00265 return e.description();
00266 }
00267
00268 }
00269 }
00270 }
00271
00272 #endif