basehandler.h 8.71 KB
Newer Older
Dimitri van Heesch's avatar
Dimitri van Heesch committed
1 2 3 4 5
/******************************************************************************
 *
 * $Id$
 *
 *
6
 * Copyright (C) 1997-2012 by Dimitri van Heesch.
Dimitri van Heesch's avatar
Dimitri van Heesch committed
7 8 9 10 11 12 13 14 15
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation under the terms of the GNU General Public License is hereby 
 * granted. No representations are made about the suitability of this software 
 * for any purpose. It is provided "as is" without express or implied warranty.
 * See the GNU General Public License for more details.
 *
 */

Dimitri van Heesch's avatar
Dimitri van Heesch committed
16 17 18 19 20 21 22
#ifndef _BASEHANDLER_H
#define _BASEHANDLER_H

#include <qxml.h>
#include <qdict.h>
#include <qstring.h>

23 24
#include "debug.h"

25 26
//-----------------------------------------------------------------------------

Dimitri van Heesch's avatar
Dimitri van Heesch committed
27 28 29 30 31
class IBaseHandler
{
  public:
    virtual void setDelegate(QXmlDefaultHandler *delegate) = 0;
    virtual QXmlDefaultHandler *delegate() const = 0;
32
    virtual ~IBaseHandler() {}
Dimitri van Heesch's avatar
Dimitri van Heesch committed
33 34
};

35 36
//-----------------------------------------------------------------------------

Dimitri van Heesch's avatar
Dimitri van Heesch committed
37 38 39 40 41 42
class IFallBackHandler
{
  public:
    virtual bool handleStartElement(const QString & name, 
                                    const QXmlAttributes & attrib) = 0;
    virtual bool handleEndElement(const QString &name) = 0;
43
    virtual ~IFallBackHandler() {}
Dimitri van Heesch's avatar
Dimitri van Heesch committed
44 45
};

46 47
//-----------------------------------------------------------------------------

Dimitri van Heesch's avatar
Dimitri van Heesch committed
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
template<class T> class ElementMapper
{
    class StartElementHandler
    {
         typedef void (T::*Handler)(const QXmlAttributes &attrib);
       public:
         StartElementHandler() : m_parent(0) {}
         StartElementHandler(T *parent, Handler h) 
           : m_parent(parent), m_handler(h) {}
         void operator()(const QXmlAttributes &attrib) 
           { if (m_parent) (m_parent->*m_handler)(attrib); }
       private:
         T *m_parent;
         Handler m_handler;
    };

    class EndElementHandler
    {
        typedef void (T::*Handler)();
      public:
        EndElementHandler() : m_parent(0) {}
        EndElementHandler(T *parent, Handler h) 
          : m_parent(parent), m_handler(h) {}
        void operator()() 
          { if (m_parent) (m_parent->*m_handler)(); }
      private:
        T *m_parent;
        Handler m_handler;
    };

78
  public:
Dimitri van Heesch's avatar
Dimitri van Heesch committed
79 80
    typedef StartElementHandler StartElementHandlerT;
    typedef EndElementHandler   EndElementHandlerT;
81 82
	  
	ElementMapper() : m_startHandlers(67), m_endHandlers(67)
Dimitri van Heesch's avatar
Dimitri van Heesch committed
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
    {
      m_startHandlers.setAutoDelete(TRUE);
      m_endHandlers.setAutoDelete(TRUE);
    }
    virtual ~ElementMapper()
    {
    }

    void addStartHandler(const char *key)
    {
      m_startHandlers.insert(key,new StartElementHandlerT);
    }

    void addStartHandler(const char *key, T *obj, void (T::*handler)(const QXmlAttributes &))
    {
      m_startHandlers.insert(key,new StartElementHandlerT(obj,handler));
    }
    
    void addEndHandler(const char *key)
    {
      m_endHandlers.insert(key,new EndElementHandlerT);
    }

    void addEndHandler(const char *key, T *obj, void (T::*handler)())
    {
      m_endHandlers.insert(key,new EndElementHandlerT(obj,handler));
    }


  protected:
    QDict<StartElementHandlerT> m_startHandlers;
    QDict<EndElementHandlerT>   m_endHandlers;
};

117 118
//-----------------------------------------------------------------------------

119 120 121 122 123
struct LocatorContainer
{
    static QXmlLocator *s_theLocator;
};

124 125
//-----------------------------------------------------------------------------

126 127 128 129
template<class T> class BaseHandler : public QXmlDefaultHandler,
                                      public ElementMapper<T>,
                                      public LocatorContainer,
                                      public IBaseHandler
Dimitri van Heesch's avatar
Dimitri van Heesch committed
130 131
{
  public:
132 133 134
    typedef typename ElementMapper<T>::StartElementHandlerT StartElementHandlerT;
    typedef typename ElementMapper<T>::EndElementHandlerT EndElementHandlerT;

Dimitri van Heesch's avatar
Dimitri van Heesch committed
135 136 137 138 139 140
    BaseHandler() : m_delegateHandler(0), m_fallBackHandler(0)
    {
    }

    virtual ~BaseHandler() 
    {
141
      ASSERT(m_delegateHandler==0);
Dimitri van Heesch's avatar
Dimitri van Heesch committed
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
    }

    virtual bool startDocument() 
    {
      return TRUE;
    }

    virtual bool startElement(  const QString & namespaceURI, 
                                const QString & localName, 
                                const QString & name, 
                                const QXmlAttributes & attrib
                             )
    {
      if (m_delegateHandler) 
      {
        return m_delegateHandler->startElement(namespaceURI,localName,name,attrib);
      }
      if (!m_skipUntil.isEmpty()) // skip mode 
      {
        if (m_skipUntil==name) m_skipCount++;
162 163 164
        debug(1,"line %d, col %d: skipping start tag %s count=%d\n",
            s_theLocator->lineNumber(),s_theLocator->columnNumber(),
            name.data(),m_skipCount);
Dimitri van Heesch's avatar
Dimitri van Heesch committed
165 166 167
        return TRUE; 
      }

168
      StartElementHandlerT *handler = ElementMapper<T>::m_startHandlers[name];
Dimitri van Heesch's avatar
Dimitri van Heesch committed
169 170 171 172 173
      if (handler)
      {
        (*handler)(attrib);
        //printf("found start tag %s\n",name.data());
      }
Dimitri van Heesch's avatar
Dimitri van Heesch committed
174
      else if (!m_fallBackHandler ||
Dimitri van Heesch's avatar
Dimitri van Heesch committed
175 176 177
               !m_fallBackHandler->handleStartElement(name,attrib)
              )
      {
178 179 180
        debug(1,"line %d, col %d: found unexpected tag `%s', skipping until matching end tag\n",
            s_theLocator->lineNumber(),s_theLocator->columnNumber(),
            name.data());
Dimitri van Heesch's avatar
Dimitri van Heesch committed
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
        m_skipUntil = name;
        m_skipCount=1;
      }
      return TRUE;
    }

    virtual bool endElement( const QString& namespaceURI, const QString& localName, const QString& name )
    {
      if (m_delegateHandler) 
      {
        return m_delegateHandler->endElement(namespaceURI,localName,name);
      }

      if (name==m_skipUntil)
      {
        m_skipCount--;
197 198 199
        debug(1,"line %d, col %d: skipping end tag %s count=%d\n",
            s_theLocator->lineNumber(),s_theLocator->columnNumber(),
            name.data(),m_skipCount);
Dimitri van Heesch's avatar
Dimitri van Heesch committed
200 201 202 203 204 205 206 207
        if (m_skipCount==0)
        {
          m_skipUntil="";
        }
        //printf("found end tag %s\n",name.data());
      }
      else if (m_skipUntil.isEmpty())
      {
208
        EndElementHandlerT *handler = ElementMapper<T>::m_endHandlers[name];
Dimitri van Heesch's avatar
Dimitri van Heesch committed
209 210 211 212 213 214 215 216 217 218 219 220 221
        if (handler)
        {
          (*handler)();
          //printf("found end tag %s\n",name.data());
        }
        else if (m_fallBackHandler)
        {
          m_fallBackHandler->handleEndElement(name);
        }
      }
      m_curString="";
      return TRUE;
    }
222 223 224 225 226 227 228 229
    
    bool skippedEntity ( const QString &s )
    {
      if (m_delegateHandler)
      {
        return m_delegateHandler->skippedEntity(s);
      }
      
230 231 232
      debug(1,"line %d, col %d: Skipped unhandled entity %s\n",
          s_theLocator->lineNumber(),s_theLocator->columnNumber(),
          s.data());
233 234
      return TRUE;
    }
Dimitri van Heesch's avatar
Dimitri van Heesch committed
235

Dimitri van Heesch's avatar
Dimitri van Heesch committed
236 237 238
    /*! called when a number of characters are received by the parser.
     *  \param ch the characters.
     */
Dimitri van Heesch's avatar
Dimitri van Heesch committed
239 240 241 242 243 244 245
    virtual bool characters ( const QString & ch ) 
    {
      if (m_delegateHandler) 
      {
        return m_delegateHandler->characters(ch);
      }

246
      //printf("Found characters \"%s\"\n",ch.data());
Dimitri van Heesch's avatar
Dimitri van Heesch committed
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
      m_curString+=ch;
      return TRUE;
    }

    void setDelegate(QXmlDefaultHandler *delegate)
    {
      m_delegateHandler = delegate;
    }

    QXmlDefaultHandler *delegate() const
    {
      return m_delegateHandler;
    }

    void setFallBackHandler(IFallBackHandler *h)
    {
      m_fallBackHandler = h;
    }

    IFallBackHandler *fallBackHandler() const
    {
      return m_fallBackHandler;
269 270 271 272 273 274
    }

    void setDocumentLocator( QXmlLocator * locator )
    {
      debug(2,"setDocumentLocator(%p)\n",locator);
      s_theLocator = locator;
Dimitri van Heesch's avatar
Dimitri van Heesch committed
275 276 277 278 279 280 281 282 283 284
    }

  protected:
    QString                     m_curString;
    QString                     m_skipUntil;
    int                         m_skipCount;
    QXmlDefaultHandler         *m_delegateHandler;
    IFallBackHandler           *m_fallBackHandler;
};

285 286
//-----------------------------------------------------------------------------

Dimitri van Heesch's avatar
Dimitri van Heesch committed
287 288 289 290
template<class T> class BaseFallBackHandler : public ElementMapper<T>,
                                              public IFallBackHandler
{
  public:
291 292 293
    typedef typename ElementMapper<T>::StartElementHandlerT StartElementHandlerT;
    typedef typename ElementMapper<T>::EndElementHandlerT EndElementHandlerT;

Dimitri van Heesch's avatar
Dimitri van Heesch committed
294 295 296 297 298 299
    BaseFallBackHandler() 
    {
    }
    virtual ~BaseFallBackHandler()
    {
    }
300
    
Dimitri van Heesch's avatar
Dimitri van Heesch committed
301 302 303
    bool handleStartElement(const QString & name, 
                                    const QXmlAttributes & attrib)
    {
304
      StartElementHandlerT *handler = ElementMapper<T>::m_startHandlers[name];
Dimitri van Heesch's avatar
Dimitri van Heesch committed
305 306 307 308 309 310 311 312 313
      if (handler)
      {
        (*handler)(attrib);
        return TRUE;
      }
      return FALSE;
    }
    bool handleEndElement(const QString &name)
    {
314
      EndElementHandlerT *handler = ElementMapper<T>::m_endHandlers[name];
Dimitri van Heesch's avatar
Dimitri van Heesch committed
315 316 317 318 319 320 321 322 323 324 325
      if (handler)
      {
        (*handler)();
        return TRUE;
      }
      return FALSE;
    }
};


#endif