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.
tqt3/tools/assistant/docuparser.cpp

398 lines
9.6 KiB

/**********************************************************************
** Copyright (C) 2000-2008 Trolltech ASA. All rights reserved.
**
** This file is part of the TQt Assistant.
**
** This file may be used under the terms of the GNU General
** Public License versions 2.0 or 3.0 as published by the Free
** Software Foundation and appearing in the files LICENSE.GPL2
** and LICENSE.GPL3 included in the packaging of this file.
** Alternatively you may (at your option) use any later version
** of the GNU General Public License if such license has been
** publicly approved by Trolltech ASA (or its successors, if any)
** and the KDE Free TQt Foundation.
**
** Please review the following information to ensure GNU General
** Public Licensing requirements will be met:
** http://trolltech.com/products/qt/licenses/licensing/opensource/.
** If you are unsure which license is appropriate for your use, please
** review the following information:
** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
** or contact the sales department at sales@trolltech.com.
**
** Licensees holding valid TQt Commercial licenses may use this file in
** accordance with the TQt Commercial License Agreement provided with
** the Software.
**
** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
** herein.
**
**********************************************************************/
#include "docuparser.h"
#include "profile.h"
#include <ntqdir.h>
#include <ntqfile.h>
#include <ntqfileinfo.h>
#include <ntqregexp.h>
#include <ntqstring.h>
#include <ntqxml.h>
TQDataStream &operator>>( TQDataStream &s, ContentItem &ci )
{
s >> ci.title;
s >> ci.reference;
s >> ci.depth;
return s;
}
TQDataStream &operator<<( TQDataStream &s, const ContentItem &ci )
{
s << ci.title;
s << ci.reference;
s << ci.depth;
return s;
}
const TQString DocuParser::DocumentKey = "/TQt Assistant/" + TQString(TQT_VERSION_STR) + "/";
DocuParser *DocuParser::createParser( const TQString &fileName )
{
TQFile file( fileName );
if( !file.open( IO_ReadOnly ) ) {
return 0;
}
TQString str;
int read = 0;
int maxlen = 1024;
int majVer = 0, minVer = 0, serVer = 0;
static TQRegExp re( "assistantconfig +version=\"(\\d)\\.(\\d)\\.(\\d)\"", FALSE );
Q_ASSERT( re.isValid() );
while( read != -1 ) {
read = file.readLine( str, maxlen );
if( re.search( str ) >= 0 ) {
majVer = re.cap( 1 ).toInt();
minVer = re.cap( 2 ).toInt();
serVer = re.cap( 3 ).toInt();
}
}
if( majVer == 3 && minVer >= 2 )
return new DocuParser320;
return new DocuParser310;
}
bool DocuParser::parse( TQFile *file )
{
TQXmlInputSource source( file );
TQXmlSimpleReader reader;
reader.setContentHandler( this );
reader.setErrorHandler( this );
setFileName( TQFileInfo( *file ).absFilePath() );
return reader.parse( source );
}
TQString DocuParser::errorProtocol() const
{
return errorProt;
}
TQValueList<ContentItem> DocuParser::getContentItems()
{
return contentList;
}
TQPtrList<IndexItem> DocuParser::getIndexItems()
{
return indexList;
}
TQString DocuParser::absolutify( const TQString &name ) const
{
TQFileInfo orgPath( name );
if( orgPath.isRelative() )
return TQFileInfo( fname ).dirPath() + TQDir::separator() + name;
return name;
}
void DocuParser310::addTo( Profile *p )
{
p->addDCFTitle( fname, docTitle );
p->addDCFIcon( docTitle, iconName );
p->addDCFIndexPage( docTitle, conURL );
}
bool DocuParser310::startDocument()
{
state = StateInit;
errorProt = "";
contentRef = "";
indexRef = "";
depth = 0;
contentList.clear();
indexList.clear();
return TRUE;
}
bool DocuParser310::startElement( const TQString &, const TQString &,
const TQString &qname,
const TQXmlAttributes &attr )
{
if (qname == "DCF" && state == StateInit) {
state = StateContent;
contentRef = absolutify( attr.value( "ref" ) );
conURL = contentRef;
docTitle = attr.value( "title" );
iconName = absolutify( attr.value( "icon" ) );
contentList.append( ContentItem( docTitle, contentRef, depth ) );
} else if (qname == "section" && (state == StateContent || state == StateSect)) {
state = StateSect;
contentRef = absolutify( attr.value( "ref" ) );
title = attr.value( "title" );
depth++;
contentList.append( ContentItem( title, contentRef, depth ) );
} else if (qname == "keyword" && state == StateSect) {
state = StateKeyword;
indexRef = absolutify( attr.value( "ref" ) );
} else
return FALSE;
return TRUE;
}
bool DocuParser310::endElement( const TQString &nameSpace, const TQString &localName,
const TQString &qName )
{
switch( state ) {
case StateInit:
break;
case StateContent:
state = StateInit;
break;
case StateSect:
state = --depth ? StateSect : StateContent;
break;
case StateKeyword:
state = StateSect;
break;
}
return TRUE;
}
bool DocuParser310::characters( const TQString& ch )
{
TQString str = ch.simplifyWhiteSpace();
if ( str.isEmpty() )
return TRUE;
switch ( state ) {
case StateInit:
case StateContent:
case StateSect:
return FALSE;
break;
case StateKeyword:
indexList.append( new IndexItem( str, indexRef ) );
break;
default:
return FALSE;
}
return TRUE;
}
bool DocuParser310::fatalError( const TQXmlParseException& exception )
{
errorProt += TQString( "fatal parsing error: %1 in line %2, column %3\n" )
.arg( exception.message() )
.arg( exception.lineNumber() )
.arg( exception.columnNumber() );
return TQXmlDefaultHandler::fatalError( exception );
}
DocuParser320::DocuParser320()
: prof( new Profile )
{
}
void DocuParser320::addTo( Profile *p )
{
TQMap<TQString,TQString>::ConstIterator it;
for (it = prof->dcfTitles.begin(); it != prof->dcfTitles.end(); ++it)
p->dcfTitles[it.key()] = *it;
for (it = prof->icons.begin(); it != prof->icons.end(); ++it)
p->icons[it.key()] = *it;
for (it = prof->indexPages.begin(); it != prof->indexPages.end(); ++it)
p->indexPages[it.key()] = *it;
}
bool DocuParser320::startDocument()
{
state = StateInit;
errorProt = "";
contentRef = "";
indexRef = "";
depth = 0;
contentList.clear();
indexList.clear();
prof->addDCF( fname );
return TRUE;
}
bool DocuParser320::startElement( const TQString &, const TQString &,
const TQString &qname,
const TQXmlAttributes &attr )
{
TQString lower = qname.lower();
switch( state ) {
case StateInit:
if( lower == "assistantconfig" )
state = StateDocRoot;
break;
case StateDocRoot:
if( lower == "dcf" ) {
state = StateContent;
contentRef = absolutify( attr.value( "ref" ) );
conURL = contentRef;
docTitle = attr.value( "title" );
iconName = absolutify( attr.value( "icon" ) );
contentList.append( ContentItem( docTitle, contentRef, depth ) );
} else if( lower == "profile" ) {
state = StateProfile;
}
break;
case StateSect:
if ( lower == "keyword" && state == StateSect ) {
state = StateKeyword;
indexRef = absolutify( attr.value( "ref" ) );
break;
} // else if (lower == "section")
case StateContent:
if( lower == "section" ) {
state = StateSect;
contentRef = absolutify( attr.value( "ref" ) );
title = attr.value( "title" );
depth++;
contentList.append( ContentItem( title, contentRef, depth ) );
}
break;
case StateProfile:
if( lower == "property" ) {
state = StateProperty;
propertyName = attr.value( "name" );
}
break;
case StateProperty:
break;
}
return TRUE;
}
bool DocuParser320::endElement( const TQString &nameSpace,
const TQString &localName,
const TQString &qName )
{
switch( state ) {
case StateInit:
break;
case StateDocRoot:
state = StateInit;
break;
case StateProfile:
state = StateDocRoot;
break;
case StateProperty:
state = StateProfile;
if( propertyName.isEmpty() || propertyValue.isEmpty() )
return FALSE;
{
static const TQStringList lst = TQStringList() << "startpage" << "abouturl"
<< "applicationicon" << "assistantdocs";
if (lst.contains(propertyName))
propertyValue = absolutify( propertyValue );
}
prof->addProperty( propertyName, propertyValue );
break;
case StateContent:
if( !iconName.isEmpty() ) prof->addDCFIcon( docTitle, iconName );
if( contentRef.isEmpty() )
return FALSE;
prof->addDCFIndexPage( docTitle, conURL );
prof->addDCFTitle( fname, docTitle );
state = StateDocRoot;
break;
case StateSect:
state = --depth ? StateSect : StateContent;
break;
case StateKeyword:
state = StateSect;
break;
}
return TRUE;
}
bool DocuParser320::characters( const TQString& ch )
{
TQString str = ch.simplifyWhiteSpace();
if ( str.isEmpty() )
return TRUE;
switch ( state ) {
case StateInit:
case StateContent:
case StateSect:
return FALSE;
break;
case StateKeyword:
indexList.append( new IndexItem( str, indexRef ) );
break;
case StateProperty:
propertyValue = ch;
break;
default:
return FALSE;
}
return TRUE;
}
bool DocuParser320::fatalError( const TQXmlParseException& exception )
{
errorProt += TQString( "fatal parsing error: %1 in line %2, column %3\n" )
.arg( exception.message() )
.arg( exception.lineNumber() )
.arg( exception.columnNumber() );
return TQXmlDefaultHandler::fatalError( exception );
}