Write support

In addition to reading the meta-data for a file, it is also possible to change it and save it back into the file. Not all KFile plugins need to support this - sometimes it wouldn't even be meaningful. However it can be very useful, and you should consider providing write support if practicable.

To implement write support, you have to do two things - mark the items as changeable, and provide a write function. In some circumstances, you may also have to provide a validator function for the new or modified data, to ensure that the meta-data remains valid. We'll take on each of these tasks in turn.

In our MNG KFile plugin, there really isn't anything that would be meaningful to change. So in this part of the tutorial, I'm going to change the theme, and make up my own format (called tutetext), using a combination of text and numbers, with the input and output handled by the QDataStream class. You can download a suitable example as example.tutetext.

MIME type association

Remember that we need a MIME type association so that the KDE Trader mechanism knows which KFile plugin is required for a particular file. In the case of the tutetext document, we're always going to use the same file (which will be have suffix .tutetext), and instead of using a magic number association, we'll just define a .desktop association.

The .desktop association looks like this:

Example 11. x-tutetext.desktop example

	       1	[Desktop Entry]
     2	Encoding=UTF-8
     3	Comment=TuteText Document
     4	Type=MimeType
     5	MimeType=text/x-tutetext
     6	Patterns=*.tutetext
       
	

This is a very simple .desktop entry, and typically there would be many more entries for things such as tranlated names, icons and other properties. However the important parts are lines 4, 5 and 6. Line 4 marks this as a MIME type linkage, while line 5 defines the MIME type (text probably isn't appropriate, but is close enough for this example). Line 6 specifies the files that will be associated with the mimetype, which will be any filename that ends with .tutetext.

I built this in kdelibs/mimetypes/text, but as long as it gets installed in the right place for the KDE Trader to find it, the original location doesn't really matter.

kfile_tutetext.desktop

As for the MNG KFile plugin, we need a .desktop, as shown below:

Example 12. kfile_tutetext.desktop example

	       1	[Desktop Entry]
     2	Encoding=UTF-8
     3	Type=Service
     4	Name=TuteText Info
     5	ServiceTypes=KFilePlugin
     6	X-KDE-Library=kfile_tutetext
     7	MimeType=text/x-tutetext
       
	

This is fairly similar to the .desktop we saw for the MNG KFile plugin, although the names have changed to match the different MIME type (in line 7), and the different library we want to have loaded (in line 6). The name (line 4) also changed to avoid any confusion.

Implementation of write support

The header file (kfile_tutetext.h) has to be updated to include the write method, as shown below:

Example 13. kfile_tutetext.h example

	       1	/***************************************************************************
     2	 *   Copyright (C) 2004 by Brad Hards                                      *
     3	 *   bhards@bigpond.net.au                                                 *
     4	 *                                                                         *
     5	 *   This program is free software; you can redistribute it and/or modify  *
     6	 *   it under the terms of the GNU General Public License as published by  *
     7	 *   the Free Software Foundation; either version 2 of the License, or     *
     8	 *   (at your option) any later version.                                   *
     9	 *                                                                         *
    10	 *   This program is distributed in the hope that it will be useful,       *
    11	 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
    12	 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
    13	 *   GNU General Public License for more details.                          *
    14	 *                                                                         *
    15	 *   You should have received a copy of the GNU General Public License     *
    16	 *   along with this program; if not, write to the                         *
    17	 *   Free Software Foundation, Inc.,                                       *
    18	 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
    19	 ***************************************************************************/
       
    20	#ifndef __KFILE_TUTETEXT_H__
    21	#define __KFILE_TUTETEXT_H__
       
    22	/**
    23	 * Note: For further information look into <$KDEDIR/include/kfilemetainfo.h>
    24	 */
    25	#include <kfilemetainfo.h>
       
    26	class QStringList;
       
    27	class tuteTextPlugin: public KFilePlugin
    28	{
    29	    Q_OBJECT
    30	    
    31	public:
    32	    tuteTextPlugin( QObject *parent, const char *name, const QStringList& args );
    33	    
    34	    virtual bool readInfo( KFileMetaInfo& info, uint what);
    35	    virtual bool writeInfo( const KFileMetaInfo& info ) const;
    36	};
       
    37	#endif // __KFILE_TUTETEXT_H__
       
	

This pretty much as we've seen before, although the name of the plugin has changed, and the write method in line 35 is new. Quickly stepping through it, lines 1 to 19 provide a standard copyright. Lines 20, 21 and 37 provide the normal idempotent construction for headers (preventing warnings if the header is accidentally included twice). Lines 22 to 25 provide the required class to derive from, and line 26 provides a forward reference for one of the arguments required in the constructor. Lines 27 to 36 provide the class declaration, including the required Q_OBJECT macro definition.

We now have a constructor, read method and write method, as shown below:

Example 14. kfile_tutetext.cpp example

	       1	/***************************************************************************
     2	 *   Copyright (C) 2004 by Brad Hards                                      *
     3	 *   bhards@bigpond.net.au                                                 *
     4	 *                                                                         *
     5	 *   This program is free software; you can redistribute it and/or modify  *
     6	 *   it under the terms of the GNU General Public License as published by  *
     7	 *   the Free Software Foundation; either version 2 of the License, or     *
     8	 *   (at your option) any later version.                                   *
     9	 *                                                                         *
    10	 *   This program is distributed in the hope that it will be useful,       *
    11	 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
    12	 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
    13	 *   GNU General Public License for more details.                          *
    14	 *                                                                         *
    15	 *   You should have received a copy of the GNU General Public License     *
    16	 *   along with this program; if not, write to the                         *
    17	 *   Free Software Foundation, Inc.,                                       *
    18	 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
    19	 ***************************************************************************/
       
    20	#include <config.h>
    21	#include <qfile.h>
    22	#include <kdebug.h>
    23	#include "kfile_tutetext.h"
       
    24	#include <kgenericfactory.h>
       
    25	typedef KGenericFactory<tuteTextPlugin> tuteTextFactory;
       
    26	K_EXPORT_COMPONENT_FACTORY(kfile_tutetext, tuteTextFactory( "kfile_tutetext" ))
       
    27	tuteTextPlugin::tuteTextPlugin(QObject *parent, const char *name,
    28				       const QStringList &args)
    29	    : KFilePlugin(parent, name, args)
    30	{
    31	    KFileMimeTypeInfo* info = addMimeTypeInfo( "text/x-tutetext" );
       
    32	    KFileMimeTypeInfo::GroupInfo* technicalGroup = 0L;
    33	    technicalGroup = addGroupInfo(info, "tuteTextTechnical", i18n("Technical"));
       
    34	    KFileMimeTypeInfo::ItemInfo* item;
       
    35	    // our new items in the group
    36	    item = addItemInfo(technicalGroup, "An integer", i18n("An integer"), QVariant::Int);
    37	    setAttributes( item,
    38			   KFileMimeTypeInfo::Modifiable |
    39			   KFileMimeTypeInfo::Addable );
    40	    item = addItemInfo(technicalGroup, "A String", i18n("A String"), QVariant::String);
    41	    setAttributes( item,
    42			   KFileMimeTypeInfo::Modifiable |
    43			   KFileMimeTypeInfo::Addable );
       
    44	    item = addItemInfo(technicalGroup, "Another integer", i18n("Another integer"), QVariant::Int);
    45	    setAttributes( item,
    46			   KFileMimeTypeInfo::Modifiable |
    47			   KFileMimeTypeInfo::Addable );
    48	}
       
    49	bool tuteTextPlugin::readInfo( KFileMetaInfo& info, uint /*what*/)
    50	{
    51	    QFile file( info.path().latin1() );
    52	    file.open( IO_ReadOnly );
    53	    QDataStream stream( &file );
       
    54	    // Read the data
    55	    Q_INT32 firstInt, secondInt;
    56	    QString myString;
       
    57	    stream >> firstInt;
    58	    stream >> myString;
    59	    stream >> secondInt;
       
    60	    KFileMetaInfoGroup technicalGroup = appendGroup( info, "tuteTextTechnical" );
    61	    appendItem( technicalGroup, "An integer", firstInt );
    62	    appendItem( technicalGroup, "A String", myString );
    63	    appendItem( technicalGroup, "Another integer", secondInt );
    64	    file.close();
       
    65	    return true;
    66	}
       
    67	bool tuteTextPlugin::writeInfo( const KFileMetaInfo& info ) const
    68	{
    69	    QFile file( info.path().latin1() );
    70	    file.open( IO_WriteOnly );
    71	    QDataStream stream( &file );
       
    72	    stream << info["tuteTextTechnical"].value("An integer").toInt();
    73	    stream << info["tuteTextTechnical"].value("A String").toString();
    74	    stream << info["tuteTextTechnical"].value("Another integer").toInt();
       
    75	    file.close();
       
    76	    return true;
    77	}
       
    78	#include "kfile_tutetext.moc"
       
	

Lines 1 to 26 are fairly standard - all I've done is changed it to reflect the updated names.

Lines 27 to 48 are the constructor, and it is broadly similar to the constructor for the MNG example. In this case, we only have one group, consisting of three items (two integers and a string). The setAttributes call in lines 37 to 39 (and repeated in lines 41-43 and 45-47) is an important change, because it marks the items as able to be modified or added. Note that not all of the items have to be able to be updated, so you can do whatever makes sense for your particular file format.

Lines 49 to 66 provide the readInfo method, which is heavily based on the QDataStream class. A production quality KFile plugin would obviously have extensive error checking, however I've omitted it in this case to make it easier to read.

Lines 67 to 77 provide the writeInfo method, which is also heavily based on the QDataStream class, and again omits any error checking. Lines 69 to 71 provide an open data stream on the required file, which is passed in as info.path(). Lines 72 to 74 dump the variables back out, to update the file. Lines 75 and 76 then clean up and return.

Makefile.am

To complete the build, you'll obviously need a suitable Makefile.am, as shown below:

Example 15. Makefile.am example for tutetext

	       1	## Makefile.am for folder file meta info plugin
       
     2	INCLUDES         = $(all_includes)
       
     3	# these are the headers for your project
     4	noinst_HEADERS   = kfile_tutetext.h
       
     5	kde_module_LTLIBRARIES = kfile_tutetext.la
       
     6	kfile_tutetext_la_SOURCES = kfile_tutetext.cpp
     7	kfile_tutetext_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
     8	kfile_tutetext_la_LIBADD = $(LIB_KIO)
       
     9	# let automoc handle all of the meta source files (moc)
    10	METASOURCES = AUTO
       
    11	services_DATA = kfile_tutetext.desktop
    12	servicesdir = $(kde_servicesdir)
       
    13	messages:
    14		$(XGETTEXT) *.cpp -o $(podir)/kfile_tutetext.pot
	

This is very similar to the previous examples, so I won't work through this one in detail. The only real changes are in the names, and in the absence of any format specific library, since Qt is always linked in.