00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include <iostream>
00020
00021 #include <qfile.h>
00022 #include <qptrlist.h>
00023
00024 #include <kaboutdata.h>
00025 #include <kapplication.h>
00026 #include <kcmdlineargs.h>
00027 #include <kfilemetainfo.h>
00028 #include <klocale.h>
00029 #include <kpropertiesdialog.h>
00030
00031 #include "fileprops.h"
00032
00033 #define KFILEVERSION "0.2"
00034 #define INDENT "\t"
00035
00036 using namespace std;
00037
00038 static QString beatifyValue( const QString& value )
00039 {
00040 if ( value.isNull() )
00041 return QString("(no value for key available)");
00042 else if ( value.isEmpty() )
00043 return QString("(empty)");
00044
00045 return value;
00046 }
00047
00048 FileProps::FileProps( const QString& path, const QStringList& suppliedGroups )
00049 : m_dirty( false )
00050 {
00051 m_info = new KFileMetaInfo(path, QString::null, KFileMetaInfo::Everything);
00052 m_userSuppliedGroups = !suppliedGroups.isEmpty();
00053 m_groupsToUse = m_userSuppliedGroups ? suppliedGroups : m_info->groups();
00054 }
00055
00056 FileProps::~FileProps()
00057 {
00058 sync();
00059 delete m_info;
00060 }
00061
00062 bool FileProps::sync()
00063 {
00064 if ( !m_dirty )
00065 return true;
00066
00067 return m_info->applyChanges();
00068 }
00069
00070 bool FileProps::isValid() const
00071 {
00072 return m_info->isValid();
00073 }
00074
00075 QStringList FileProps::supportedGroups() const
00076 {
00077 return m_info->supportedGroups();
00078 }
00079
00080 QStringList FileProps::availableGroups() const
00081 {
00082 return m_info->groups();
00083 }
00084
00085 QStringList FileProps::supportedKeys( const QString& group ) const
00086 {
00087 KFileMetaInfoGroup g = m_info->group( group );
00088 return g.supportedKeys();
00089 }
00090
00091 QStringList FileProps::availableKeys( const QString& group ) const
00092 {
00093 KFileMetaInfoGroup g = m_info->group( group );
00094 QStringList allKeys = g.keys();
00095 QStringList ret;
00096 QStringList::ConstIterator it = allKeys.begin();
00097 for ( ; it != allKeys.end(); ++it )
00098 {
00099 if ( g.item( *it ).isValid() )
00100 ret.append( *it );
00101 }
00102
00103 return ret;
00104 }
00105
00106 QStringList FileProps::preferredKeys( const QString& group ) const
00107 {
00108 KFileMetaInfoGroup g = m_info->group( group );
00109 return g.preferredKeys();
00110 }
00111
00112 QString FileProps::getValue( const QString& group,
00113 const QString& key ) const
00114 {
00115 KFileMetaInfoGroup g = m_info->group( group );
00116 return FileProps::createKeyValue( g, key );
00117 }
00118
00119 bool FileProps::setValue( const QString& group,
00120 const QString& key, const QString &value )
00121 {
00122 KFileMetaInfoGroup g = m_info->group( group );
00123 bool wasAdded = false;
00124 if ( !g.isValid() )
00125 {
00126 if ( m_info->addGroup( group ) )
00127 {
00128 wasAdded = true;
00129 g = m_info->group( group );
00130 }
00131 else
00132 return false;
00133 }
00134
00135 bool ok = g[key].setValue( value );
00136
00137 if ( !ok && wasAdded )
00138 (void) m_info->removeGroup( group );
00139
00140 m_dirty |= ok;
00141 return ok;
00142 }
00143
00144 QStringList FileProps::allValues( const QString& group ) const
00145 {
00146 KFileMetaInfoGroup g = m_info->group( group );
00147 return FileProps::createKeyValueList( g, g.keys() );
00148 }
00149
00150 QStringList FileProps::preferredValues( const QString& group ) const
00151 {
00152 KFileMetaInfoGroup g = m_info->group( group );
00153 return FileProps::createKeyValueList( g, g.preferredKeys() );
00154 }
00155
00156
00157
00158
00159 QString FileProps::createKeyValue( const KFileMetaInfoGroup& g,
00160 const QString& key )
00161 {
00162 static const int MAX_SPACE = 25;
00163 KFileMetaInfoItem item = g.item( key );
00164
00165 QString result("%1");
00166 result = result.arg( (item.isValid() ? item.translatedKey() : key) + ":",
00167 -MAX_SPACE );
00168 result.append( beatifyValue( item.string() ) );
00169
00170 QString group("%1");
00171 group = group.arg( g.translatedName() + ":", -MAX_SPACE );
00172 result.prepend( group );
00173
00174 return result;
00175 }
00176
00177
00178 QStringList FileProps::createKeyValueList( const KFileMetaInfoGroup& g,
00179 const QStringList& keys )
00180 {
00181 QStringList result;
00182 QStringList::ConstIterator it = keys.begin();
00183
00184 for ( ; it != keys.end(); ++it )
00185 result.append( FileProps::createKeyValue( g, *it ) );
00186
00187 return result;
00188 }
00189
00192
00193
00194
00195
00196
00197 static KCmdLineOptions options[] =
00198 {
00199 { "m", 0, 0 },
00200 { "nomimetype", I18N_NOOP("Do not print the mimetype of the given file(s)"), 0 },
00201
00202 { "ls", 0, 0 },
00203 { "listsupported <mimetype>",
00204 I18N_NOOP("List all supported metadata keys of the given file(s). "
00205 "If mimetype is not specified, the mimetype of the given "
00206 "files is used." ), "file" },
00207
00208 { "lp", 0, 0 },
00209 { "listpreferred <mimetype>",
00210 I18N_NOOP("List all preferred metadata keys of the given file(s). "
00211 "If mimetype is not specified, the mimetype of the given "
00212 "files is used." ), "file" },
00213
00214 { "la", 0, 0 },
00215 { "listavailable",
00216 I18N_NOOP("List all metadata keys which have a value in the given "
00217 "file(s)."), 0 },
00218
00219 { "sm", 0, 0 },
00220 { "supportedMimetypes",
00221 I18N_NOOP("Prints all mimetypes for which metadata support is "
00222 "available."), 0 },
00223
00224 { "q", 0, 0 },
00225 { "quiet",
00226 I18N_NOOP("Do not print a warning when more than one file was given "
00227 "and they do not all have the same mimetype."), 0 },
00228
00229 { "av", 0, 0 },
00230 { "allValues",
00231 I18N_NOOP("Prints all metadata values, available in the given "
00232 "file(s)."), 0 },
00233
00234 { "pv", 0, 0 },
00235 { "preferredValues",
00236 I18N_NOOP("Prints the preferred metadata values, available in the "
00237 "given file(s)."), 0 },
00238
00239 { "dialog",
00240 I18N_NOOP("Opens a KDE properties dialog to allow viewing and "
00241 "modifying of metadata of the given file(s)"), 0 },
00242
00243 { "getValue <key>",
00244 I18N_NOOP("Prints the value for 'key' of the given file(s). 'key' "
00245 "may also be a comma-separated list of keys"), 0 },
00246
00247 { "setValue <key=value>",
00248 I18N_NOOP("Attempts to set the value 'value' for the metadata key "
00249 "'key' for the given file(s)"), 0 },
00250
00251 { "!groups <arguments>", I18N_NOOP("The group to get values from or set values to"),
00252 0 },
00253
00254 { "+[files]",
00255 I18N_NOOP("The file (or a number of files) to operate on."), 0 },
00256 KCmdLineLastOption
00257 };
00258
00259
00260
00261
00262
00263
00264 static void printSupportedMimeTypes()
00265 {
00266 QStringList allMimeTypes = KFileMetaInfoProvider::self()->supportedMimeTypes();
00267 if ( allMimeTypes.isEmpty() )
00268 {
00269 cout <<
00270 i18n("No support for metadata extraction found.").local8Bit()
00271 << endl;
00272 return;
00273 }
00274
00275 cout << i18n("Supported MimeTypes:").local8Bit() << endl;
00276
00277 QStringList::ConstIterator it = allMimeTypes.begin();
00278 for ( ; it != allMimeTypes.end(); it++ )
00279 cout << (*it).local8Bit() << endl;
00280 }
00281
00282
00283 static KFileItemList * fileItemList( const KCmdLineArgs *args )
00284 {
00285 KFileItemList * items = new KFileItemList();
00286 items->setAutoDelete( true );
00287 for ( int i = 0; i < args->count(); i++ )
00288 items->append( new KFileItem( KFileItem::Unknown,
00289 KFileItem::Unknown,
00290 args->url( i ) ));
00291 return items;
00292 }
00293
00294 static void showPropertiesDialog( const KCmdLineArgs *args )
00295 {
00296 KFileItemList *items = fileItemList( args );
00297 new KPropertiesDialog( *items, 0L, "props dialog", true );
00298 delete items;
00299 }
00300
00301 static void printMimeTypes( const KCmdLineArgs *args )
00302 {
00303 for ( int i = 0; i < args->count(); i++ )
00304 {
00305 KURL url = args->url( i );
00306 KMimeType::Ptr mt = KMimeType::findByURL( url );
00307 cout << args->arg(i) << ": " << mt->comment().local8Bit() << " ("
00308 << mt->name().local8Bit() << ")" << endl;
00309 }
00310 }
00311
00312 static void printList( const QStringList& list )
00313 {
00314 QStringList::ConstIterator it = list.begin();
00315 for ( ; it != list.end(); ++it )
00316 cout << (*it).local8Bit() << endl;
00317 cout << endl;
00318 }
00319
00320 static void processMetaDataOptions( const QPtrList<FileProps> propList,
00321 KCmdLineArgs *args )
00322 {
00323
00324
00325
00326 QString line("-- -------------------------------------------------------");
00327 FileProps *props;
00328 QPtrListIterator<FileProps> it( propList );
00329 for ( ; (props = it.current()); ++it )
00330 {
00331 QString file = props->fileName() + " ";
00332 QString fileString = line.replace( 3, file.length(), file );
00333 cout << QFile::encodeName( fileString ) << endl;
00334
00335 if ( args->isSet( "listsupported" ) )
00336 {
00337 cout << "=Supported Keys=" << endl;
00338 printList( props->supportedKeys() );
00339 }
00340 if ( args->isSet( "listpreferred" ) )
00341 {
00342 cout << "=Preferred Keys=" << endl;
00343 printList( props->preferredKeys() );
00344 }
00345 if ( args->isSet( "listavailable" ) )
00346 {
00347 cout << "=Available Keys=" << endl;
00348 QStringList groups = props->availableGroups();
00349 QStringList::ConstIterator git = groups.begin();
00350 for ( ; git != groups.end(); ++git )
00351 {
00352 cout << "Group: " << (*git).local8Bit() << endl;
00353 printList( props->availableKeys( *git ) );
00354 }
00355 }
00356
00357
00358
00359
00360 if ( args->isSet( "getValue" ) )
00361 {
00362 cout << "=Value=" << endl;
00363 QString key = QString::fromLocal8Bit( args->getOption("getValue"));
00364 QStringList::ConstIterator git = props->groupsToUse().begin();
00365 for ( ; git != props->groupsToUse().end(); ++git )
00366 cout << props->getValue( *git, key ).local8Bit() << endl;
00367 }
00368
00369 if ( args->isSet( "setValue" ) )
00370 {
00371
00372 QString cmd = QString::fromLocal8Bit( args->getOption("setValue"));
00373 QString key = cmd.section( '=', 0, 0 );
00374 QString value = cmd.section( '=', 1 );
00375
00376
00377
00378 QStringList groups = props->userSuppliedGroups() ?
00379 props->groupsToUse() :
00380 props->supportedGroups();
00381
00382 QStringList::ConstIterator git = groups.begin();
00383 for ( ; git != groups.end(); ++git )
00384 props->setValue( *git, key, value );
00385 }
00386
00387 if ( args->isSet( "allValues" ) )
00388 {
00389 cout << "=All Values=" << endl;
00390 QStringList groups = props->availableGroups();
00391 QStringList::ConstIterator group = groups.begin();
00392 for ( ; group != groups.end(); ++group )
00393 printList( props->allValues( *group ) );
00394 }
00395 if ( args->isSet( "preferredValues" ) && !args->isSet("allValues") )
00396 {
00397 cout << "=Preferred Values=" << endl;
00398 QStringList groups = props->availableGroups();
00399 QStringList::ConstIterator group = groups.begin();
00400 for ( ; group != groups.end(); ++group )
00401 printList( props->preferredValues( *group ) );
00402 }
00403 }
00404
00405 }
00406
00407 int main( int argc, char **argv )
00408 {
00409 KAboutData about(
00410 "kfile", I18N_NOOP( "kfile" ), KFILEVERSION,
00411 I18N_NOOP("A commandline tool to read and modify metadata of files." ),
00412 KAboutData::License_LGPL, "(c) 2002, Carsten Pfeiffer",
00413 0 , "http://devel-home.kde.org/~pfeiffer/",
00414 "pfeiffer@kde.org" );
00415
00416 about.addAuthor( "Carsten Pfeiffer", 0, "pfeiffer@kde.org",
00417 "http://devel-home.kde.org/~pfeiffer/" );
00418
00419 KCmdLineArgs::init( argc, argv, &about );
00420
00421 KCmdLineArgs::addCmdLineOptions( options );
00422
00423 KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
00424 bool useGUI = args->isSet( "dialog" );
00425
00426 KApplication app( useGUI, useGUI );
00427
00428 QPtrList<FileProps> m_props;
00429 m_props.setAutoDelete( true );
00430
00431 bool quiet = args->isSet( "quiet" );
00432
00433 if ( args->isSet( "supportedMimetypes" ) )
00434 printSupportedMimeTypes();
00435
00436 int files = args->count();
00437 if ( files == 0 )
00438 KCmdLineArgs::usage( i18n("No files specified") );
00439
00440 if ( args->isSet( "dialog" ) )
00441 {
00442 showPropertiesDialog( args );
00443 return true;
00444 }
00445
00446 QStringList groupsToUse;
00447 QCStringList suppliedGroups = args->getOptionList( "groups" );
00448 QCStringList::ConstIterator it = suppliedGroups.begin();
00449 for ( ; it != suppliedGroups.end(); ++it )
00450 groupsToUse.append( QString::fromLocal8Bit( (*it) ) );
00451
00452 QString mimeType;
00453
00454 for ( int i = 0; i < files; i++ )
00455 {
00456 if ( args->isSet( "mimetype" ) )
00457 printMimeTypes( args );
00458
00459 FileProps *props = new FileProps( args->url(i).path(), groupsToUse );
00460 if ( props->isValid() )
00461 m_props.append( props );
00462 else
00463 {
00464 if ( !quiet )
00465 {
00466 cerr << args->arg(i) << ": " <<
00467 i18n("Cannot determine metadata").local8Bit() << endl;
00468 }
00469 delete props;
00470 }
00471 }
00472
00473
00474 processMetaDataOptions( m_props, args );
00475
00476 m_props.clear();
00477 cout.flush();
00478
00479 return 0;
00480 }