filters

wmlparser.cpp

00001 /* This file is part of the KDE project
00002    Copyright (C) 2002 Ariya Hidayat <ariyahidayat@yahoo.de>
00003 
00004    This library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Library General Public
00006    License as published by the Free Software Foundation; either
00007    version 2 of the License, or (at your option) any later version.
00008 
00009    This library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Library General Public License for more details.
00013 
00014    You should have received a copy of the GNU Library General Public License
00015    along with this library; see the file COPYING.LIB.  If not, write to
00016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017  * Boston, MA 02110-1301, USA.
00018 */
00019 
00020 #include <qstring.h>
00021 #include <qxml.h>
00022 #include <qfile.h>
00023 #include <qvaluestack.h>
00024 
00025 #include <wmlparser.h>
00026 
00027 class WMLParseState
00028 {
00029   public:
00030     unsigned tableRow, tableCol;
00031     WMLFormat currentFormat;
00032     WMLFormatList formatList;
00033     WMLLayout currentLayout;
00034     WMLParseState();
00035     WMLParseState( const WMLParseState& );
00036     WMLParseState& operator=( const WMLParseState& );
00037     void assign( const WMLParseState& );
00038 };
00039 
00040 WMLParseState::WMLParseState()
00041 {
00042   tableRow = tableCol = 0;
00043 }
00044 
00045 WMLParseState::WMLParseState( const WMLParseState& state )
00046 {
00047   assign( state );
00048 }
00049 
00050 WMLParseState& WMLParseState::operator=( const WMLParseState& state )
00051 {
00052   assign( state );
00053   return *this ;
00054 }
00055 
00056 void WMLParseState::assign( const WMLParseState& state )
00057 {
00058   tableRow = state.tableRow;
00059   tableCol = state.tableCol;
00060   currentFormat = state.currentFormat;
00061   formatList = state.formatList;
00062   currentLayout = state.currentLayout;
00063 }
00064 
00065 // ContentHandler for use with the reader
00066 class WMLHandler: public QXmlDefaultHandler
00067 {
00068   public:
00069 
00070     WMLHandler( WMLParser *parser ){ m_parser = parser; }
00071 
00072     bool startDocument();
00073     bool startElement( const QString&, const QString&, const QString& ,
00074                        const QXmlAttributes& );
00075     bool endElement( const QString&, const QString&, const QString& );
00076     bool characters( const QString& ch );
00077 
00078   private:
00079 
00080     WMLParser *m_parser;
00081 
00082     bool m_inBlock;
00083     QString m_text;
00084 
00085     bool m_inLink;
00086     QString m_link;
00087     QString m_href;
00088 
00089     WMLParseState m_state;
00090     QValueStack<WMLParseState> m_stateStack;
00091     
00092     bool flushParagraph();
00093     void pushState();
00094     void popState();
00095 };
00096 
00097 bool WMLHandler::startDocument()
00098 {
00099   m_text = "";
00100   m_inBlock = false;
00101 
00102   m_link = "";
00103   m_href = "";
00104   
00105   return true;
00106 }
00107 
00108 bool WMLHandler::startElement( const QString&, const QString&,
00109                                         const QString& qName,
00110                                         const QXmlAttributes& attr )
00111 {
00112   QString tag = qName.lower();
00113 
00114   if( tag == "wml" )
00115     return m_parser->doOpenDocument();
00116 
00117   if( tag == "card" ) 
00118   {
00119     m_state = WMLParseState();
00120     QString card_id = attr.value("id");
00121     QString card_title = attr.value("title");
00122     return m_parser->doOpenCard( card_id, card_title );
00123   }
00124 
00125   if( tag == "p" )
00126   {
00127     m_state.currentLayout = WMLLayout();
00128     m_inBlock = TRUE;
00129     if( m_state.currentFormat.bold || 
00130         m_state.currentFormat.italic ||
00131         m_state.currentFormat.underline ||
00132         (m_state.currentFormat.fontsize != WMLFormat::Normal) )
00133       m_state.formatList.append( m_state.currentFormat );
00134 
00135     QString align = attr.value("align").lower();
00136     if( align == "right" )
00137       m_state.currentLayout.align =  WMLLayout::Right;
00138     if( align == "center" )
00139       m_state.currentLayout.align =  WMLLayout::Center;
00140 
00141     return TRUE;
00142   }
00143 
00144   if(( tag == "b" ) || (tag == "strong") )
00145   {
00146     m_state.currentFormat.bold = TRUE;
00147     m_state.currentFormat.pos = m_text.length();
00148     m_state.formatList.append( m_state.currentFormat );
00149     return TRUE;
00150   }
00151  
00152   if(( tag == "i" ) || (tag == "em") )
00153   {  
00154     m_state.currentFormat.italic = TRUE;
00155     m_state.currentFormat.pos = m_text.length();  
00156     m_state.formatList.append( m_state.currentFormat );  
00157     return TRUE;  
00158   }  
00159 
00160   if( tag == "u" )
00161   {
00162     m_state.currentFormat.underline = TRUE;
00163     m_state.currentFormat.pos = m_text.length();
00164     m_state.formatList.append( m_state.currentFormat );
00165     return TRUE;
00166   }
00167 
00168   if( tag == "big" )
00169   {
00170     m_state.currentFormat.fontsize = WMLFormat::Big;
00171     m_state.currentFormat.pos = m_text.length();
00172     m_state.formatList.append( m_state.currentFormat );
00173     return TRUE;
00174   }
00175 
00176   if( tag == "small" ) 
00177   {
00178     m_state.currentFormat.fontsize = WMLFormat::Small;
00179     m_state.currentFormat.pos = m_text.length();
00180     m_state.formatList.append( m_state.currentFormat );
00181     return TRUE;
00182   }
00183 
00184   if( tag == "a" )
00185   {
00186     QString href = attr.value("href");
00187     if( !href.isEmpty() )
00188     {
00189       m_inBlock = false;
00190       m_inLink = true;
00191       m_state.currentFormat.link = "";
00192       m_state.currentFormat.href = href;
00193       m_state.currentFormat.pos = m_text.length();
00194       m_state.currentFormat.len = 1;
00195       m_text.append( "#" ); // inline char
00196       return true;
00197     }
00198   }
00199 
00200   // open new table
00201   if( tag == "table" )
00202   {
00203     pushState();
00204     return m_parser->doBeginTable();
00205   }
00206 
00207   // open table row
00208   if( tag == "tr" )
00209   {
00210     m_state.tableRow++;
00211     return TRUE;
00212   }
00213 
00214   // open table cell, keep in sync with <p> above
00215   if( tag == "td" )
00216   {
00217     m_state.tableCol++;
00218     m_state.currentLayout = WMLLayout();
00219     m_inBlock = TRUE;
00220     m_state.formatList.append( m_state.currentFormat );
00221     return m_parser->doTableCell( m_state.tableRow, m_state.tableCol );
00222   }
00223 
00224   // unhandled element
00225   return TRUE;
00226 }
00227 
00228 bool WMLHandler::endElement( const QString&, const QString&, 
00229   const QString& qName )
00230 {
00231   QString tag = qName.lower();
00232 
00233   if( tag == "wml" )
00234     return m_parser->doCloseDocument();
00235 
00236   if( tag == "card" )
00237   {
00238     // forget </p> before </card> ?
00239     m_inBlock = FALSE;
00240     if( !m_text.isEmpty() )
00241       flushParagraph();
00242     return m_parser->doCloseCard();
00243   }
00244 
00245   if( tag == "p" )
00246   {
00247     m_inBlock = FALSE;
00248     return flushParagraph();
00249   }
00250 
00251   if(( tag == "b" ) || (tag == "strong") )
00252   {
00253     m_state.currentFormat.bold = FALSE; 
00254     m_state.currentFormat.pos = m_text.length();
00255     m_state.formatList.append( m_state.currentFormat );
00256     return TRUE;
00257   }
00258 
00259   if(( tag == "i" ) || (tag == "em") )
00260   {
00261     m_state.currentFormat.italic = FALSE;
00262     m_state.currentFormat.pos = m_text.length();
00263     m_state.formatList.append( m_state.currentFormat );
00264     return TRUE;
00265   }
00266 
00267   if( tag == "u" )
00268   {
00269     m_state.currentFormat.underline = FALSE;  
00270     m_state.currentFormat.pos = m_text.length();
00271     m_state.formatList.append( m_state.currentFormat );
00272     return TRUE;
00273   }
00274 
00275   if( tag == "big" )
00276   {
00277     m_state.currentFormat.fontsize = WMLFormat::Normal;
00278     m_state.currentFormat.pos = m_text.length();
00279     m_state.formatList.append( m_state.currentFormat );
00280     return TRUE;
00281   }
00282 
00283   if( tag == "small" )
00284   {
00285     m_state.currentFormat.fontsize = WMLFormat::Normal;
00286     m_state.currentFormat.pos = m_text.length();
00287     m_state.formatList.append( m_state.currentFormat );
00288     return TRUE;
00289   }
00290 
00291   if( tag == "a" )
00292   {
00293     m_inBlock = true;
00294     m_inLink = false;
00295     m_state.formatList.append( m_state.currentFormat );
00296     return true;
00297   }
00298 
00299   // close table
00300   if( tag == "table" )
00301   {
00302     popState();
00303     return m_parser->doEndTable();
00304   }
00305 
00306   // close table row
00307   if( tag == "tr" )
00308     return TRUE; //skip
00309 
00310   // close table cell, like </p>
00311   if( tag == "td" )
00312   {
00313     m_inBlock = FALSE;
00314     return flushParagraph();
00315   }
00316 
00317   // unhandled
00318   return TRUE;
00319 }
00320 
00321 bool WMLHandler::characters( const QString& ch )
00322 {
00323   if( m_inBlock )
00324     m_text.append( ch );
00325 
00326   if( m_inLink )
00327     m_state.currentFormat.link.append( ch );
00328 
00329   return TRUE;
00330 }
00331 
00332 bool WMLHandler::flushParagraph()
00333 {
00334   // calc length of each format tag
00335   for( unsigned i=0; i<m_state.formatList.count(); i++ )
00336   {
00337     int nextpos;
00338     WMLFormat& format = m_state.formatList[i];
00339     if( i < m_state.formatList.count()-1 )
00340     {
00341       WMLFormat& nextformat = m_state.formatList[i+1];
00342       nextpos = nextformat.pos;
00343     }
00344     else nextpos = m_text.length();
00345     if( format.len <= 0 )
00346       format.len = nextpos - format.pos;
00347   }
00348 
00349   bool result = m_parser->doParagraph( m_text, m_state.formatList, m_state.currentLayout );
00350 
00351   // ready for next paragraph
00352   m_text = "";
00353   m_state.formatList.clear();
00354   m_state.currentLayout = WMLLayout();
00355 
00356   // m_state.currentFormat = WMLFormat();
00357   // FIXME should we reset formatting ?
00358 
00359   return result;
00360 }
00361 
00362 void WMLHandler::pushState()
00363 {
00364   m_stateStack.push( m_state );
00365 }
00366 
00367 void WMLHandler::popState()
00368 {
00369   if( !m_stateStack.isEmpty() )
00370     m_state = m_stateStack.pop();
00371 }
00372 
00373 // formatting for the text
00374 WMLFormat::WMLFormat()
00375 {
00376   pos = len = 0;
00377   fontsize = Normal;
00378   bold = italic = underline = FALSE;
00379   link = "";
00380   href = "";
00381 }
00382 
00383 void WMLFormat::assign( const WMLFormat& f )
00384 {
00385   pos = f.pos;
00386   len = f.len;
00387   bold = f.bold;
00388   italic = f.italic;
00389   underline = f.underline;
00390   fontsize = f.fontsize;
00391   link = f.link;
00392   href= f.href;
00393 }
00394 
00395 WMLFormat::WMLFormat( const WMLFormat& f )
00396 {
00397   assign( f );
00398 }
00399 
00400 WMLFormat& WMLFormat::operator=( const WMLFormat& f )
00401 {
00402   assign( f );
00403   return *this;
00404 }
00405 
00406 // paragraph layout info
00407 WMLLayout::WMLLayout()
00408 {
00409   align = Left;
00410 }
00411 
00412 void WMLLayout::assign( const WMLLayout& l )
00413 {
00414   align = l.align;
00415 }
00416 
00417 WMLLayout::WMLLayout( const WMLLayout& l )
00418 {
00419   assign( l );
00420 }
00421 
00422 WMLLayout& WMLLayout::operator=( const WMLLayout& l )
00423 {
00424   assign( l );
00425   return *this;
00426 }
00427  
00428 // The basic WML parser
00429 void WMLParser::parse( const char* filename )
00430 {
00431    QFile f( filename );
00432    QXmlInputSource source( &f );
00433    QXmlSimpleReader reader;
00434    WMLHandler handler( this );
00435    reader.setContentHandler( &handler );
00436    reader.parse( source );
00437 }
00438 
00439 bool WMLParser::doOpenDocument()
00440 {
00441   return TRUE;
00442 }
00443 
00444 bool WMLParser::doCloseDocument()
00445 {
00446   return TRUE;
00447 }
00448 
00449 bool WMLParser::doOpenCard( QString, QString )
00450 {
00451   return TRUE;
00452 }
00453 
00454 bool WMLParser::doCloseCard()
00455 {
00456   return TRUE;
00457 }
00458 
00459 bool WMLParser::doParagraph( QString, WMLFormatList, WMLLayout )
00460 {
00461   return TRUE;
00462 }
00463 
00464 bool WMLParser::doBeginTable()
00465 {
00466   return TRUE;
00467 }
00468 
00469 bool WMLParser::doEndTable()
00470 {
00471   return TRUE;
00472 }
00473 
00474 bool WMLParser::doTableCell( unsigned, unsigned )
00475 {
00476   return TRUE;
00477 }
KDE Home | KDE Accessibility Home | Description of Access Keys