You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
589 lines
18 KiB
589 lines
18 KiB
/* This file is part of the KDE project
|
|
* Copyright (C) 2003 Pierre Souchay <pierre@souchay.net>
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public
|
|
* License as published by the Free Software Foundation version 2.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; see the file COPYING. If not, write to
|
|
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
* Boston, MA 02110-1301, USA.
|
|
*
|
|
*/
|
|
|
|
/**
|
|
* CHANGES
|
|
* v1.7 to 1.9
|
|
* Added the editing duration analysis.
|
|
* v1.6 to 1.7
|
|
* Changed the incorrect meta:date to dc:date
|
|
* Now parse date instead of simply print the ISO date
|
|
* Fixes bug with keywords, now properly handled
|
|
* Changed the deprecated upload method to the new one.
|
|
* v1.5 to 1.6
|
|
* Correction for bug 68112: http://bugs.kde.org/show_bug.cgi?id=68112
|
|
* OOo 1.1 does not support garbages in zip files. We now recreate the zip
|
|
* file from scratch. It is slower, but we don't have the choice :(
|
|
* v1.1 to v1.2
|
|
* Added support for KFileMimeTypeInfo::Hints (Name, Author, Description)
|
|
* Added some Advanced Attributes and Statistics according to DTD of OOo
|
|
* No more duplicated strings of same contents to facilitate changes
|
|
*/
|
|
|
|
#include <config.h>
|
|
#include "kfile_ooo.h"
|
|
|
|
#include <klocale.h>
|
|
#include <kgenericfactory.h>
|
|
#include <KoStore.h>
|
|
#include <KoStoreDevice.h>
|
|
#include <kzip.h>
|
|
#include <ktempfile.h>
|
|
#include <tqptrstack.h>
|
|
|
|
#include <tqdom.h>
|
|
#include <tqfile.h>
|
|
#include <tqdatetime.h>
|
|
#include <tqvalidator.h>
|
|
#include <kdebug.h>
|
|
#include <kio/netaccess.h>
|
|
|
|
typedef KGenericFactory<KOfficePlugin> KOfficeFactory;
|
|
|
|
K_EXPORT_COMPONENT_FACTORY(kfile_ooo, KOfficeFactory( "kfile_ooo" ))
|
|
|
|
static const char * const mimetypes[] =
|
|
{ "application/vnd.sun.xml.calc", "application/vnd.sun.xml.calc.template",
|
|
"application/vnd.sun.xml.draw", "application/vnd.sun.xml.draw.template",
|
|
"application/vnd.sun.xml.impress","application/vnd.sun.xml.impress.template",
|
|
"application/vnd.sun.xml.writer", "application/vnd.sun.xml.writer.global",
|
|
"application/vnd.sun.xml.writer.math",
|
|
"application/vnd.sun.xml.writer.template",
|
|
"application/vnd.oasis.opendocument.chart",
|
|
"application/vnd.oasis.opendocument.formula",
|
|
"application/vnd.oasis.opendocument.graphics",
|
|
"application/vnd.oasis.opendocument.graphics-template",
|
|
"application/vnd.oasis.opendocument.presentation",
|
|
"application/vnd.oasis.opendocument.presentation-template",
|
|
"application/vnd.oasis.opendocument.spreadsheet",
|
|
"application/vnd.oasis.opendocument.spreadsheet-template",
|
|
"application/vnd.oasis.opendocument.text",
|
|
"application/vnd.oasis.opendocument.text-template",
|
|
0};
|
|
|
|
static const char * const Advanced[] =
|
|
{
|
|
"meta:printed-by" , I18N_NOOP("Printed By"),
|
|
"meta:print-date" , I18N_NOOP("Print Date"),
|
|
"dc:date" , I18N_NOOP("Date"),
|
|
"meta:creation-date" , I18N_NOOP("Creation Date"),
|
|
"meta:initial-creator", I18N_NOOP("Creator"),
|
|
"meta:generator" , I18N_NOOP("Generator"),
|
|
"meta:editing-cycles" , I18N_NOOP("Editing Cycles"),
|
|
"meta:editing-duration" , I18N_NOOP("Editing Duration"),
|
|
0};
|
|
|
|
static const char * dclanguage = "dc:language";
|
|
|
|
static const char * const Information[] =
|
|
{"dc:title" , I18N_NOOP("Title") ,
|
|
"dc:creator" , I18N_NOOP("Author") ,
|
|
"dc:description", I18N_NOOP("Description"),
|
|
"dc:subject" , I18N_NOOP("Subject") ,
|
|
dclanguage , I18N_NOOP("Language") ,
|
|
0};
|
|
|
|
static const char * const Statistics[] =
|
|
{"meta:draw-count" , I18N_NOOP("Draws"),
|
|
"meta:table-count" , I18N_NOOP("Tables"),
|
|
"meta:image-count" , I18N_NOOP("Images"),
|
|
"meta:object-count" , I18N_NOOP("Objects"),
|
|
"meta:ole-object-count", I18N_NOOP("OLE Objects"),
|
|
"meta:page-count" , I18N_NOOP("Pages"),
|
|
"meta:paragraph-count" , I18N_NOOP("Paragraphs"),
|
|
"meta:word-count" , I18N_NOOP("Words"),
|
|
"meta:cell-count" , I18N_NOOP("Cells"),
|
|
"meta:character-count" , I18N_NOOP("Characters"),
|
|
"meta:row-count" , I18N_NOOP("Rows"),
|
|
0};
|
|
|
|
static const char * metakeywords = "meta:keywords";
|
|
static const char * metakeyword = "meta:keyword" ;
|
|
static const char * DocumentInfo = "DocumentInfo" ;
|
|
static const char * UserDefined = "UserDefined" ;
|
|
static const char * DocAdvanced = "Advanced" ;
|
|
static const char * DocStatistics = "Statistics" ;
|
|
static const char * metadocstat = "meta:document-statistic";
|
|
static const char * metaname = "meta:name" ;
|
|
static const char * metauserdef = "meta:user-defined";
|
|
static const char * metafile = "meta.xml" ;
|
|
KOfficePlugin::KOfficePlugin(TQObject *parent, const char *name,
|
|
const TQStringList &args)
|
|
|
|
: KFilePlugin(parent, name, args)
|
|
{
|
|
int i = 0;
|
|
while (mimetypes[i])
|
|
makeMimeTypeInfo( mimetypes[i++] );
|
|
}
|
|
|
|
void KOfficePlugin::makeMimeTypeInfo(const TQString& mimeType)
|
|
{
|
|
KFileMimeTypeInfo* info = addMimeTypeInfo( mimeType );
|
|
|
|
userdefined = addGroupInfo(info, UserDefined, i18n("User Defined"));
|
|
addVariableInfo(userdefined, TQVariant::String,
|
|
KFileMimeTypeInfo::Addable |
|
|
KFileMimeTypeInfo::Removable |
|
|
KFileMimeTypeInfo::Modifiable);
|
|
|
|
KFileMimeTypeInfo::GroupInfo* group = 0L;
|
|
group = addGroupInfo(info, DocumentInfo, i18n("Document Information"));
|
|
KFileMimeTypeInfo::ItemInfo* item;
|
|
int i = 0;
|
|
for (i = 0; Information[i]; i+=2){
|
|
item = addItemInfo(group, Information[i], i18n(Information[i+1]),
|
|
TQVariant::String);
|
|
setAttributes(item, KFileMimeTypeInfo::Modifiable);
|
|
switch (i){
|
|
case 0:
|
|
setHint(item, KFileMimeTypeInfo::Name);
|
|
break;
|
|
case 1:
|
|
setHint(item, KFileMimeTypeInfo::Author);
|
|
break;
|
|
case 2:
|
|
setHint(item, KFileMimeTypeInfo::Description);
|
|
default:;
|
|
}
|
|
}
|
|
|
|
item = addItemInfo(group, metakeyword, i18n("Keywords"),
|
|
TQVariant::String);
|
|
setHint(item, KFileMimeTypeInfo::Description);
|
|
setAttributes(item, KFileMimeTypeInfo::Modifiable);
|
|
|
|
group = addGroupInfo(info, DocAdvanced, i18n("Document Advanced"));
|
|
for (i = 0; Advanced[i]; i+=2){
|
|
// I should add the isDate property instead of testing the index, but it works well, who cares ? :-)
|
|
TQVariant::Type typ = TQVariant::String;
|
|
if (i > 1 && i < 8)
|
|
typ = TQVariant::DateTime;
|
|
if (i == 14)
|
|
typ = TQVariant::String;
|
|
item = addItemInfo(group, Advanced[i], i18n(Advanced[i+1]), typ);
|
|
setHint(item, KFileMimeTypeInfo::Description);
|
|
}
|
|
|
|
group = addGroupInfo(info, DocStatistics, i18n("Document Statistics"));
|
|
for (i = 0; Statistics[i]; i+=2){
|
|
item = addItemInfo(group, Statistics[i], i18n(Statistics[i+1]),
|
|
TQVariant::Int);
|
|
setHint(item, KFileMimeTypeInfo::Length);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Gets a number in the string and update the position next character which
|
|
* is not a number
|
|
* @param str The string to check
|
|
* @param the position to start to, updated to the next character NAN
|
|
* @return the number parsed, 0 if number was not valid
|
|
*/
|
|
int getNumber(TQString &str, int * pos){
|
|
int k = *pos;
|
|
for (int len = str.length() ;
|
|
str.at(k).isNumber() && k < len ;
|
|
k++);
|
|
bool result = false;
|
|
int num = str.mid( *pos, k-(*pos)).toInt(&result);
|
|
*pos = k;
|
|
if (!result)
|
|
return 0;
|
|
return num;
|
|
}
|
|
|
|
void KOfficePlugin::getEditingTime(KFileMetaInfoGroup group1,
|
|
const char * labelid, TQString & txt){
|
|
TQString t;
|
|
int days = 0;
|
|
int hours = 0;
|
|
int minutes = 0;
|
|
int seconds = 0;
|
|
if (txt.at(0) != 'P'){
|
|
kdDebug(7034) << labelid << "=" << txt <<
|
|
" does not seems to be a valid duration" << endl;
|
|
return;
|
|
}
|
|
int pos = 1;
|
|
if (txt.at(pos).isNumber()){
|
|
days = getNumber(txt, &pos);
|
|
if (txt.at(pos++)!='D'){
|
|
days=0;
|
|
kdDebug(7034) << labelid <<
|
|
" First arg was not a day in " << txt << endl;
|
|
}
|
|
}
|
|
if (txt.at(pos)!= 'T'){
|
|
kdDebug(7034) << labelid << "=" << txt <<
|
|
" does not seems to contain time information" << endl;
|
|
return;
|
|
}
|
|
pos++;
|
|
int len = txt.length();
|
|
while (pos < len){
|
|
int res = getNumber(txt, &pos);
|
|
if (pos >= len)
|
|
return;
|
|
switch (txt.tqat(pos).latin1()) {
|
|
case 'H':
|
|
hours = res;
|
|
break;
|
|
case 'M':
|
|
minutes = res;
|
|
break;
|
|
case 'S':
|
|
seconds = res;
|
|
break;
|
|
default:
|
|
kdDebug(7034) << "Unknown unit at pos " << pos << " while parsing " <<
|
|
labelid << "="<< txt << endl;
|
|
}
|
|
pos++;
|
|
}
|
|
hours += days * 24;
|
|
appendItem(group1, labelid,
|
|
i18n("%1:%2.%3").tqarg(hours).tqarg(minutes, 2).tqarg(seconds,2 ));
|
|
}
|
|
|
|
void KOfficePlugin::getDateTime(KFileMetaInfoGroup group1,
|
|
const char * labelid, TQString & txt)
|
|
{
|
|
TQDateTime dt = TQDateTime::fromString( txt, Qt::ISODate);
|
|
appendItem( group1, labelid, dt);
|
|
}
|
|
|
|
bool KOfficePlugin::readInfo( KFileMetaInfo& info, uint /*what*/)
|
|
{
|
|
if ( info.path().isEmpty() ) // remote file
|
|
return false;
|
|
|
|
KFileMetaInfoGroup group = appendGroup(info, DocumentInfo);
|
|
TQDomDocument doc = getMetaDocument(info.path());
|
|
if (doc.isNull())
|
|
return false;
|
|
TQDomElement base = getBaseNode(doc).toElement();
|
|
if (base.isNull())
|
|
return false;
|
|
for (int i = 0; Information[i]; i+=2)
|
|
appendItem(group, Information[i],
|
|
stringFromNode(base, Information[i]));
|
|
// Special case for keyword
|
|
TQDomNodeList keywordList = base.elementsByTagName( metakeyword );
|
|
TQString allKeywords;
|
|
for (uint i = 0; i < keywordList.length(); i++){
|
|
TQDomNode node = keywordList.item(i);
|
|
if (node.isElement()){
|
|
if (i>0)
|
|
allKeywords += ", ";
|
|
allKeywords += node.toElement().text();
|
|
}
|
|
}
|
|
appendItem(group, metakeyword,
|
|
allKeywords);
|
|
|
|
KFileMetaInfoGroup group1 = appendGroup(info, DocAdvanced);
|
|
for (int i = 0; Advanced[i]; i+=2){
|
|
TQString txt = stringFromNode(base, Advanced[i]);
|
|
if (!txt.isEmpty()){
|
|
// A silly way to do it...
|
|
switch (i){
|
|
case 2:
|
|
case 4:
|
|
case 6:
|
|
getDateTime(group1, Advanced[i], txt);
|
|
break;
|
|
case 14:
|
|
getEditingTime(group1, Advanced[i], txt);
|
|
break;
|
|
default:
|
|
appendItem(group1, Advanced[i], txt);}
|
|
}
|
|
}
|
|
|
|
TQDomNode dstat = base.namedItem(metadocstat);
|
|
|
|
KFileMetaInfoGroup group2 = appendGroup(info, DocStatistics);
|
|
if (!dstat.isNull() && dstat.isElement()){
|
|
TQDomElement dinfo = dstat.toElement();
|
|
for (int i = 0; Statistics[i]; i+=2)
|
|
addAttributeInfo(dinfo, group2, Statistics[i] );
|
|
}
|
|
|
|
|
|
TQDomNodeList userList = base.elementsByTagName( metauserdef );
|
|
|
|
KFileMetaInfoGroup groupuser = appendGroup(info, UserDefined);
|
|
|
|
for (uint i = 0; i < userList.length(); i++){
|
|
TQDomNode node = userList.item(i);
|
|
if (node.isElement()){
|
|
appendItem(groupuser,
|
|
node.toElement().attribute(metaname,
|
|
TQString("User %1").tqarg(i)),
|
|
node.toElement().text());
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
TQString KOfficePlugin::stringFromNode(const TQDomNode &node, const TQString &name)
|
|
{
|
|
TQString value = node.namedItem(name).toElement().text();
|
|
return value.isEmpty() ? TQString() : value;
|
|
}
|
|
|
|
void KOfficePlugin::addAttributeInfo(const TQDomElement & elem, KFileMetaInfoGroup & group, const TQString &attributeName)
|
|
{
|
|
if (!elem.hasAttribute(attributeName)){
|
|
return;
|
|
}
|
|
TQString m_attribute = elem.attribute(attributeName, "0");
|
|
if (m_attribute == "0")
|
|
return;
|
|
appendItem(group, attributeName, m_attribute);
|
|
}
|
|
|
|
bool KOfficePlugin::writeTextNode(TQDomDocument & doc,
|
|
TQDomNode & parentNode,
|
|
const TQString &nodeName,
|
|
const TQString &value) const
|
|
{
|
|
if (parentNode.toElement().isNull()){
|
|
kdDebug(7034) << "Parent node is Null or not an Element, cannot write node "
|
|
<< nodeName << endl;
|
|
return false;
|
|
}
|
|
|
|
// If the node does not exist, we create it...
|
|
if (parentNode.namedItem(nodeName).isNull())
|
|
TQDomNode ex = parentNode.appendChild(doc.createElement(nodeName));
|
|
|
|
// Now, we are sure we have a node
|
|
TQDomElement nodeA = parentNode.namedItem(nodeName).toElement();
|
|
|
|
// Ooops... existing node were not of the good type...
|
|
if (nodeA.isNull()){
|
|
kdDebug(7034) << "Wrong type of node " << nodeName << ", should be Element"
|
|
<< endl;
|
|
return false;
|
|
}
|
|
|
|
TQDomText txtNode = doc.createTextNode(value);
|
|
|
|
// If the node has already Text Child, we replace it.
|
|
if (nodeA.firstChild().isNull())
|
|
nodeA.appendChild(txtNode);
|
|
else
|
|
nodeA.replaceChild( txtNode, nodeA.firstChild());
|
|
return true;
|
|
}
|
|
|
|
bool KOfficePlugin::writeInfo( const KFileMetaInfo& info) const
|
|
{
|
|
bool no_errors = true;
|
|
TQDomDocument doc = getMetaDocument(info.path());
|
|
TQDomElement base = getBaseNode(doc).toElement();
|
|
if (base.isNull())
|
|
return false;
|
|
for (int i = 0; Information[i]; i+=2)
|
|
no_errors = no_errors &&
|
|
writeTextNode(doc, base, Information[i],
|
|
info[DocumentInfo][Information[i]].value().toString());
|
|
// If we need a meta:keywords container, we create it.
|
|
if (base.namedItem(metakeywords).isNull())
|
|
base.appendChild(doc.createElement(metakeywords));
|
|
TQDomNode metaKeyNode = base.namedItem(metakeywords);
|
|
|
|
TQDomNodeList childs = doc.elementsByTagName(metakeyword);
|
|
for (int i = childs.length(); i >= 0; --i){
|
|
metaKeyNode.removeChild( childs.item(i) );
|
|
}
|
|
TQStringList keywordList = TQStringList::split(",", info[DocumentInfo][metakeyword].value().toString().stripWhiteSpace(), false);
|
|
for ( TQStringList::Iterator it = keywordList.begin(); it != keywordList.end(); ++it ) {
|
|
TQDomElement elem = doc.createElement(metakeyword);
|
|
metaKeyNode.appendChild(elem);
|
|
elem.appendChild(doc.createTextNode((*it).stripWhiteSpace()));
|
|
}
|
|
|
|
// Now, we store the user-defined data
|
|
TQDomNodeList theElements = base.elementsByTagName(metauserdef);
|
|
for (uint i = 0; i < theElements.length(); i++)
|
|
{
|
|
TQDomElement el = theElements.item(i).toElement();
|
|
if (el.isNull()){
|
|
kdDebug(7034) << metauserdef << " is not an Element" << endl;
|
|
no_errors = false;
|
|
}
|
|
|
|
TQString s = info[UserDefined][el.attribute(metaname)].value().toString();
|
|
if (s != el.text()){
|
|
TQDomText txt = doc.createTextNode(s);
|
|
if (!el.firstChild().isNull())
|
|
el.replaceChild(txt, el.firstChild());
|
|
else
|
|
el.appendChild(txt);
|
|
}
|
|
}
|
|
|
|
if (!no_errors){
|
|
kdDebug(7034) << "Errors were found while building " << metafile
|
|
<< " for file " << info.path() << endl;
|
|
// It is safer to avoid to manipulate meta.xml if errors, we abort.
|
|
return false;
|
|
}
|
|
writeMetaData(info.path(), doc);
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* This function recreate a zip in dest with all files from src
|
|
* except meta.xml
|
|
*/
|
|
bool copyZipToZip( const KZip * src, KZip * dest)
|
|
{
|
|
KArchiveDirectory * src_dir;
|
|
KArchiveFile * input_file;
|
|
TQPtrStack<KArchiveDirectory> src_dirStack ;
|
|
TQStringList dirEntries;
|
|
TQStringList curDirName;
|
|
TQStringList::Iterator it;
|
|
KArchiveEntry* curEntry;
|
|
TQString filename = TQString();
|
|
|
|
src_dirStack.push ( src->directory() );
|
|
|
|
do {
|
|
src_dir = src_dirStack.pop();
|
|
curDirName.append(src_dir->name());
|
|
dirEntries = src_dir->entries();
|
|
|
|
/* We now iterate over all entries and create entries in dest */
|
|
for ( it = dirEntries.begin(); it != dirEntries.end(); ++it ) {
|
|
if ( *it == metafile )
|
|
continue;
|
|
curEntry = src_dir->entry( *it );
|
|
|
|
if (curEntry->isFile()) {
|
|
input_file = dynamic_cast<KArchiveFile*>( curEntry );
|
|
TQByteArray b = input_file->data();
|
|
if (curDirName.isEmpty() || src_dir->name()=="/"){
|
|
filename = *it;
|
|
} else {
|
|
filename = curDirName.join("/") + "/" + *it;
|
|
}
|
|
dest->writeFile(filename , TQString(), TQString(), b.count(), b.data() );
|
|
} else
|
|
if (curEntry->isDirectory()) {
|
|
src_dirStack.push( dynamic_cast<KArchiveDirectory*>( curEntry ) );
|
|
}
|
|
else {
|
|
kdDebug(7034) << *it << " is a unknown type. Aborting." << endl;
|
|
return false;
|
|
}
|
|
}
|
|
curDirName.pop_back();
|
|
} while ( ! src_dirStack.isEmpty() );
|
|
return true;
|
|
}
|
|
|
|
bool KOfficePlugin::writeMetaData(const TQString & path,
|
|
const TQDomDocument &doc) const
|
|
{
|
|
KTempFile tmp_file;
|
|
tmp_file.setAutoDelete(true);
|
|
KZip * m_zip = new KZip(tmp_file.name());
|
|
KZip * current= new KZip(path);
|
|
/* To correct problem with OOo 1.1, we have to recreate the file from scratch */
|
|
if (!m_zip->open(IO_WriteOnly) || !current->open(IO_ReadOnly) )
|
|
return false;
|
|
TQCString text = doc.toCString();
|
|
m_zip->setCompression(KZip::DeflateCompression);
|
|
if (!copyZipToZip(current, m_zip))
|
|
return false;
|
|
m_zip->writeFile(metafile, TQString(), TQString(),text.length(),
|
|
text);
|
|
delete current;
|
|
delete m_zip;
|
|
// NULL as third parameter is not good, but I don't know the Window ID
|
|
// That is only to avoid the deprecated warning at compile time
|
|
if (!KIO::NetAccess::upload( tmp_file.name(), KURL(path), NULL)){
|
|
kdDebug(7034) << "Error while saving " << tmp_file.name() << " as " << path << endl;
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
TQIODevice* KOfficePlugin::getData(KArchive &m_zip, int fileMode) const
|
|
{
|
|
|
|
if ( !m_zip.open(fileMode) || !m_zip.directory())
|
|
return 0;
|
|
|
|
const KArchiveEntry* entry = m_zip.directory()->entry( metafile );
|
|
if (!entry || entry->isDirectory())
|
|
return 0;
|
|
|
|
const KZipFileEntry* f = static_cast<const KZipFileEntry *>(entry);
|
|
if (!f)
|
|
return 0;
|
|
return f->device();
|
|
}
|
|
|
|
TQDomDocument KOfficePlugin::getMetaDocument(const TQString &path) const
|
|
{
|
|
TQDomDocument doc;
|
|
KZip m_zip(path);
|
|
TQIODevice * io = getData(m_zip, IO_ReadOnly);
|
|
if (!io || !io->isReadable())
|
|
return doc;
|
|
TQString errorMsg;
|
|
int errorLine, errorColumn;
|
|
if ( !doc.setContent( io, &errorMsg, &errorLine, &errorColumn ) ){
|
|
kdDebug(7034) << "Error " << errorMsg.latin1()
|
|
<< "while getting XML content at line "
|
|
<< errorLine << ", column "<< errorColumn << endl;
|
|
delete io;
|
|
return doc;
|
|
}
|
|
delete io;
|
|
return doc;
|
|
}
|
|
|
|
TQDomNode KOfficePlugin::getBaseNode(const TQDomDocument &doc) const
|
|
{
|
|
return
|
|
doc.namedItem("office:document-meta").namedItem("office:meta");
|
|
}
|
|
|
|
TQValidator * KOfficePlugin::createValidator(const TQString &, /* mimetype */
|
|
const TQString & , /* group */
|
|
const TQString &key,
|
|
TQObject * parent,
|
|
const char * name ) const
|
|
{
|
|
if (key == dclanguage)
|
|
return new TQRegExpValidator(TQRegExp("[a-zA-Z-]{1,5}"),
|
|
parent, name);
|
|
return 0;
|
|
}
|
|
|
|
#include "kfile_ooo.moc"
|