libept
|
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; // throw? 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 // m_group = g.entry( "Categories" ).value; 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 mutable Entry entry; 00116 off_t offset; 00117 mutable bool loaded; 00118 00119 InternalList() : dir( "" ), offset( -2 ), loaded( false ) {} 00120 InternalList( std::string d ) : dir( d ), offset( -1 ), loaded( false ) 00121 { 00122 firstFile(); 00123 } 00124 00125 Entry head() const { 00126 if (!loaded) 00127 entry.load( current ); 00128 loaded = true; 00129 return entry; 00130 } 00131 00132 bool empty() const { 00133 return (offset == -2); 00134 } 00135 00136 void firstFile() { 00137 offset = -1; 00138 nextFile(); 00139 } 00140 00141 InternalList tail() const { 00142 InternalList r = *this; 00143 r.nextFile(); 00144 return r; 00145 } 00146 00147 void nextFile() { 00148 loaded = false; 00149 DIR *d = opendir( dir.c_str() ); 00150 if ( !d ) { 00151 offset = -2; 00152 closedir( d ); 00153 return; 00154 } 00155 00156 if ( offset != -1 ) 00157 seekdir( d, offset ); 00158 00159 dirent *ent = 0; 00160 while ( ( ent = readdir( d ) ) != 0 ) { 00161 std::string name( ent->d_name ); 00162 if ( name == "." || name == ".." ) 00163 continue; 00164 if ( !wibble::str::endsWith( name, ".desktop" ) ) 00165 continue; 00166 current = dir + "/" + name; 00167 offset = telldir( d ); 00168 closedir( d ); 00169 return; 00170 } 00171 closedir( d ); 00172 offset = -2; 00173 } 00174 }; 00175 00176 struct Setup { 00177 typedef ept::Token Token; 00178 typedef Entry Internal; 00179 typedef desktop::PropertyId PropertyId; 00180 typedef desktop::InternalList InternalList; 00181 }; 00182 00183 struct GroupPolicy { 00184 virtual std::string group( const Entry &e ) 00185 { 00186 return wibble::str::fmt( e.categories() ); 00187 } 00188 virtual ~GroupPolicy() {} 00189 }; 00190 00191 struct Source : core::Source< Source, Setup, PropertyType > 00192 { 00193 std::string m_dir; 00194 00195 GroupPolicy m_defaultPolicy; 00196 GroupPolicy *m_policy; 00197 00198 Source( std::string dir ) : m_dir( dir ), 00199 m_policy( &m_defaultPolicy ) {} 00200 00201 InternalList listInternal() { 00202 return InternalList( m_dir ); 00203 } 00204 00205 Token getToken( Entry i ) { 00206 Token t; 00207 t._id = std::string( "desktop:" ) + i.id(); 00208 return t; 00209 } 00210 00211 Entry lookupToken( Token t ) { 00212 Entry e; 00213 e.load( t.desktop() ); 00214 return e; 00215 } 00216 00217 void setGroupPolicy( GroupPolicy *p ) { 00218 m_policy = p; 00219 } 00220 00221 template< PropertyId p > 00222 typename PropertyType< p >::T getInternal( Entry ); 00223 00224 struct IsInGroup { 00225 std::string g; 00226 IsInGroup( std::string _g = "" ) : g( _g ) {} 00227 bool operator()( Token, std::string gr ) const { 00228 return gr == g; 00229 } 00230 }; 00231 00232 PropertyFilter< Group, IsInGroup >::T group( std::string id ) 00233 { 00234 return propertyFilter< Group >( IsInGroup( id ) ); 00235 } 00236 00237 static std::string projectGroup( ComposedList< Name > t ) { 00238 return t.get< Group >(); 00239 } 00240 00241 list::Unique< list::Sorted< 00242 list::Map< ComposedList< Name >, 00243 __typeof( std::ptr_fun( &projectGroup ) ) > > > 00244 groupList() { 00245 return list::unique( 00246 list::sort( list::map( list< Name >(), 00247 std::ptr_fun( &projectGroup ) ) ) ); 00248 } 00249 }; 00250 00251 template<> inline std::string Source::getInternal< Name >( Entry e ) { 00252 return e.name(); 00253 } 00254 00255 template<> inline std::string Source::getInternal< Icon >( Entry e ) { 00256 return e.icon(); 00257 } 00258 00259 template<> inline ept::Token Source::getInternal< Package >( Entry e ) { 00260 ept::Token t; 00261 t._id = e.package(); 00262 return t; 00263 } 00264 00265 template<> inline std::string Source::getInternal< Group >( Entry e ) { 00266 return m_policy->group( e ); 00267 } 00268 00269 template<> inline std::string Source::getInternal< ShortDescription >( Entry e ) { 00270 return e.description(); 00271 } 00272 00273 } 00274 } 00275 } 00276 00277 #endif