gui/xml.h
author deba
Wed, 01 Mar 2006 10:17:25 +0000
changeset 1990 15fb7a4ea6be
parent 1894 f794a0bb40c9
permissions -rw-r--r--
Some classes assumed that the GraphMaps should be inherited
from an ObserverBase. These classes parents replaced with
DefaultMap which cause that the graph maps should not be
inherited from the ObserverBase.
alpar@1735
     1
/* -*- C++ -*-
alpar@1735
     2
 * gui/xml.h - Part of LEMON, a generic C++ optimization library
alpar@1735
     3
 *
alpar@1875
     4
 * Copyright (C) 2006 Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
alpar@1735
     5
 * (Egervary Research Group on Combinatorial Optimization, EGRES).
alpar@1735
     6
 *
alpar@1735
     7
 * Permission to use, modify and distribute this software is granted
alpar@1735
     8
 * provided that this copyright notice appears in all copies. For
alpar@1735
     9
 * precise terms see the accompanying LICENSE file.
alpar@1735
    10
 *
alpar@1735
    11
 * This software is provided "AS IS" with no warranty of any kind,
alpar@1735
    12
 * express or implied, and with no claim as to its suitability for any
alpar@1735
    13
 * purpose.
alpar@1735
    14
 *
alpar@1735
    15
 */
alpar@1428
    16
alpar@1428
    17
#include <iostream>
alpar@1428
    18
#include <string>
alpar@1428
    19
#include <vector>
alpar@1428
    20
#include <list>
alpar@1428
    21
#include <map>
alpar@1588
    22
#include <lemon/error.h>
alpar@1428
    23
#include <lemon/xy.h>
alpar@1428
    24
alpar@1588
    25
namespace lemon {
alpar@1428
    26
alpar@1735
    27
  class XmlIo 
alpar@1588
    28
  {
alpar@1735
    29
    bool _writeMode;
alpar@1735
    30
  public:
alpar@1735
    31
    ///Check if XmlIo is in write mode.
alpar@1735
    32
    bool write() { return _writeMode;}
alpar@1735
    33
    ///Check if XmlIo is in read mode.
alpar@1735
    34
    bool read() { return !_writeMode;}
alpar@1735
    35
alpar@1588
    36
    std::ostream& os;
alpar@1588
    37
    int level;
alpar@1735
    38
    
alpar@1588
    39
  protected:
alpar@1588
    40
    void indent(int level) {
alpar@1588
    41
      os << std::endl;
alpar@1588
    42
      for(int i=0;i<level;i++) os << ' ';
alpar@1588
    43
    }
alpar@1588
    44
    void tag(const std::string &_tag) {
alpar@1588
    45
      os << '<' << _tag << '>';
alpar@1588
    46
    }
alpar@1588
    47
    void etag(const std::string &_tag) {
alpar@1588
    48
      os << "</" << _tag << '>';
alpar@1588
    49
    }
alpar@1588
    50
    void itag(const std::string &_tag) { indent();tag(_tag); }
alpar@1588
    51
    void ietag(const std::string &_tag) { indent();etag(_tag); }
alpar@1428
    52
alpar@1588
    53
    void beginTag(const std::string &_tag) {
alpar@1588
    54
      itag(_tag);
alpar@1588
    55
      level++;
alpar@1588
    56
    }
alpar@1588
    57
    void endTag(const std::string &_tag) {
alpar@1588
    58
      level--;
alpar@1588
    59
      ietag(_tag);
alpar@1588
    60
    }
alpar@1428
    61
alpar@1588
    62
  public:
alpar@1735
    63
    ///Indent the line according to its level.
alpar@1588
    64
alpar@1735
    65
    ///\warning It can only be used in write mode.
alpar@1735
    66
    ///
alpar@1735
    67
    void indent()
alpar@1588
    68
    {
alpar@1735
    69
      if(write())
alpar@1735
    70
	if(level>=0) indent(level);
alpar@1735
    71
	else level=0;
alpar@1735
    72
      else throw LogicError();	
alpar@1588
    73
    }
alpar@1428
    74
  
alpar@1735
    75
    ///Read/write a tag
alpar@1428
    76
  
alpar@1735
    77
    ///Read/write a tag.
alpar@1735
    78
    ///In write mode it does not start a new line.
alpar@1588
    79
    class ContTag
alpar@1588
    80
    {
alpar@1735
    81
      XmlIo &ix;
alpar@1588
    82
      const std::string _tag;
alpar@1588
    83
    public:
alpar@1588
    84
      ///\e
alpar@1428
    85
  
alpar@1588
    86
      ///\e
alpar@1588
    87
      ///
alpar@1735
    88
      ContTag(XmlIo &_ix,const std::string &_t) :
alpar@1588
    89
	ix(_ix), _tag(_t)
alpar@1588
    90
      {
alpar@1735
    91
	if(ix.write()) ix.tag(_tag);
alpar@1735
    92
	else ix.useTag(_tag);
alpar@1588
    93
      }
alpar@1735
    94
      ~ContTag() { 
alpar@1735
    95
	if(ix.write()) ix.etag(_tag);
alpar@1735
    96
	else if(!std::uncaught_exception()) ix.useTag('/'+_tag);      
alpar@1735
    97
      }
alpar@1588
    98
    };
alpar@1588
    99
alpar@1735
   100
    ///Read/write a tag
alpar@1735
   101
  
alpar@1735
   102
    ///Read/write a tag.
alpar@1894
   103
    ///The whole \<foo\> ... \</foo\> will be placed in a single line.
alpar@1588
   104
    class LineTag
alpar@1428
   105
    {
alpar@1735
   106
      XmlIo &ix;
alpar@1588
   107
      const std::string _tag;
alpar@1588
   108
    public:
alpar@1588
   109
      ///\e
alpar@1588
   110
    
alpar@1588
   111
      ///\e
alpar@1588
   112
      ///
alpar@1735
   113
      LineTag(XmlIo &_ix,const std::string &_t) :
alpar@1588
   114
	ix(_ix), _tag(_t)
alpar@1588
   115
      {
alpar@1735
   116
	if(ix.write()) ix.itag(_tag);
alpar@1735
   117
	else ix.useTag(_tag);
alpar@1588
   118
      }
alpar@1735
   119
      ~LineTag() { 
alpar@1735
   120
	if(ix.write()) ix.etag(_tag);
alpar@1735
   121
	else if(!std::uncaught_exception()) ix.useTag('/'+_tag);
alpar@1735
   122
      }
alpar@1588
   123
    };
alpar@1588
   124
alpar@1735
   125
    ///Read/write a tag
alpar@1588
   126
  
alpar@1735
   127
    ///Read/write a tag.
alpar@1588
   128
    ///
alpar@1588
   129
    class Tag
alpar@1588
   130
    {
alpar@1735
   131
      XmlIo &ix;
alpar@1588
   132
      const std::string _tag;
alpar@1588
   133
    public:
alpar@1588
   134
      ///\e
alpar@1588
   135
  
alpar@1588
   136
      ///\e
alpar@1588
   137
      ///
alpar@1735
   138
      Tag(XmlIo &_ix,const std::string &_t) :
alpar@1588
   139
	ix(_ix), _tag(_t)
alpar@1588
   140
      {
alpar@1735
   141
	if(ix.write()) ix.beginTag(_tag);
alpar@1735
   142
	else ix.useTag(_tag);
alpar@1588
   143
      }
alpar@1735
   144
      ~Tag() {
alpar@1735
   145
	if(ix.write()) ix.endTag(_tag);
alpar@1735
   146
	else if(!std::uncaught_exception()) ix.useTag('/'+_tag);
alpar@1588
   147
      }
alpar@1588
   148
    };
alpar@1735
   149
alpar@1735
   150
  private:
alpar@1735
   151
    std::istream& is;
alpar@1735
   152
    std::string next_tag;
alpar@1735
   153
    int line_number;
alpar@1735
   154
alpar@1735
   155
    void skipWhiteSpaces()
alpar@1735
   156
    {
alpar@1735
   157
      if(write()) throw LogicError();
alpar@1735
   158
      {
alpar@1735
   159
	char c;
alpar@1735
   160
	while (is.get(c) && std::isspace(c,is.getloc()))
alpar@1735
   161
	  if(c=='\n') line_number++;
alpar@1735
   162
	is.unget();
alpar@1735
   163
      }
alpar@1735
   164
    }
alpar@1735
   165
  protected:
alpar@1735
   166
    /// Use the next tag.
alpar@1735
   167
alpar@1735
   168
    ///\e
alpar@1735
   169
    ///
alpar@1735
   170
    void useTag() {next_tag.clear();}
alpar@1735
   171
  
alpar@1735
   172
    ///Use the next tag and check if it is equal with \c _tag
alpar@1735
   173
  
alpar@1735
   174
    ///\e
alpar@1735
   175
    ///
alpar@1735
   176
    void useTag(const std::string &_tag) {
alpar@1735
   177
      if(nextTag()==_tag) useTag();
alpar@1735
   178
      else throw DataFormatError("",line_number,"Unexpected token name");
alpar@1735
   179
    }
alpar@1735
   180
  public:
alpar@1735
   181
    ///Return the next tag (if a tag follows on the stream).
alpar@1735
   182
  
alpar@1735
   183
    ///\warning It can only be used in read mode.
alpar@1735
   184
    ///
alpar@1735
   185
    const std::string &nextTag() 
alpar@1735
   186
    {
alpar@1735
   187
      if(write()) throw LogicError();
alpar@1735
   188
      else if(next_tag.empty()) {
alpar@1735
   189
	char c;
alpar@1735
   190
	skipWhiteSpaces();
alpar@1735
   191
	if(!is.get(c) || c!='<')
alpar@1735
   192
	  throw DataFormatError("",line_number,"Bad format");
alpar@1735
   193
	next_tag.clear();
alpar@1735
   194
	while (is.get(c) && c!='>') next_tag.push_back(c);
alpar@1735
   195
	if(c!='>')
alpar@1735
   196
	  throw DataFormatError("",line_number,"Bad format");
alpar@1735
   197
      }
alpar@1735
   198
      return next_tag;
alpar@1735
   199
    }
alpar@1735
   200
alpar@1735
   201
    /**********************************************************************/
alpar@1735
   202
alpar@1735
   203
alpar@1588
   204
    ///\e
alpar@1588
   205
  
alpar@1588
   206
    ///\e
alpar@1588
   207
    ///
alpar@1735
   208
    XmlIo(std::ostream& _os) : _writeMode(true), os(_os),
alpar@1735
   209
			       level(-1),
alpar@1936
   210
			       is(std::cin) {}
alpar@1735
   211
    ///\e
alpar@1735
   212
    ///
alpar@1735
   213
    XmlIo(std::istream& _is) : _writeMode(false),
alpar@1936
   214
			       os(std::cout), is(_is),
alpar@1735
   215
			       line_number(1) {}
alpar@1735
   216
alpar@1735
   217
    ~XmlIo() { if(write()) os<< std::endl; }
alpar@1588
   218
  
alpar@1735
   219
alpar@1735
   220
alpar@1735
   221
    XmlIo &operator()(const int &v) 
alpar@1588
   222
    { 
alpar@1735
   223
      if(write()) os << v;
alpar@1735
   224
      else {
alpar@1735
   225
	skipWhiteSpaces();
alpar@1735
   226
	if(!(is >> const_cast<int &>(v))) 
alpar@1735
   227
	  throw DataFormatError("",line_number,"Not an 'int'");
alpar@1735
   228
      }
alpar@1588
   229
      return *this;
alpar@1428
   230
    }
alpar@1735
   231
    XmlIo &operator()(const double &v) 
alpar@1735
   232
    {
alpar@1735
   233
      if(write()) os << v;
alpar@1735
   234
      else {
alpar@1735
   235
	skipWhiteSpaces();
alpar@1735
   236
	if(!(is >> const_cast<double &>(v))) 
alpar@1735
   237
	  throw DataFormatError("",line_number,"Not an 'double'");
alpar@1735
   238
      }
alpar@1735
   239
      return *this;
alpar@1735
   240
    }
alpar@1735
   241
    XmlIo &operator()(const std::string &v)
alpar@1735
   242
    {
alpar@1735
   243
      if(write())
alpar@1735
   244
	for(std::string::const_iterator i=v.begin();i!=v.end();++i)
alpar@1735
   245
	  switch(*i) {
alpar@1735
   246
	  case '\\':
alpar@1735
   247
	    os << "\\\\";
alpar@1735
   248
	    break;
alpar@1735
   249
	  case '<':
alpar@1735
   250
	    os << "\\<";
alpar@1735
   251
	    break;
alpar@1735
   252
	  case '&':
alpar@1735
   253
	    os << "\\&";
alpar@1735
   254
	    break;
alpar@1735
   255
	  case '\n':
alpar@1735
   256
	    os << "\\n";
alpar@1735
   257
	    break;
alpar@1735
   258
	  default:
alpar@1735
   259
	    os<<*i;
alpar@1735
   260
	    break;
alpar@1735
   261
	  }
alpar@1735
   262
      else {
alpar@1735
   263
	std::string &w = const_cast<std::string &>(v);
alpar@1735
   264
	w.clear();
alpar@1735
   265
	char c;
alpar@1735
   266
	while (is.get(c) && c!='<')
alpar@1735
   267
	  if(c=='\\')
alpar@1735
   268
	    if(!is.get(c))
alpar@1735
   269
	      throw DataFormatError("",line_number,"Bad string");
alpar@1735
   270
	    else switch(c) {
alpar@1735
   271
	    case 'n':
alpar@1735
   272
	      w.push_back('\n');
alpar@1735
   273
	      break;
alpar@1735
   274
	    default:
alpar@1735
   275
	      w.push_back(c);
alpar@1735
   276
	      break;
alpar@1735
   277
	    }
alpar@1735
   278
	  else {
alpar@1735
   279
	    if(c=='\n') line_number++;
alpar@1735
   280
	    w.push_back(c);
alpar@1735
   281
	  }
alpar@1735
   282
	if(c!='<')
alpar@1735
   283
	  throw DataFormatError("",line_number,"Unexpected eof");
alpar@1735
   284
	is.unget();
alpar@1735
   285
      }
alpar@1735
   286
      return *this;
alpar@1735
   287
    }
alpar@1735
   288
alpar@1735
   289
alpar@1735
   290
    XmlIo &operator()(const std::string &_tag,const int &v) 
alpar@1588
   291
    { 
alpar@1588
   292
      LineTag t(*this,_tag);
alpar@1588
   293
      (*this)(v);
alpar@1588
   294
      return *this;
alpar@1588
   295
    }
alpar@1735
   296
    XmlIo &operator()(const std::string &_tag,const double &v) 
alpar@1588
   297
    {
alpar@1588
   298
      LineTag t(*this,_tag);
alpar@1588
   299
      (*this)(v);
alpar@1588
   300
      return *this;
alpar@1588
   301
    }
alpar@1735
   302
    XmlIo &operator()(const std::string &_tag,const std::string &v)
alpar@1588
   303
    {
alpar@1588
   304
      LineTag t(*this,_tag);
alpar@1588
   305
      (*this)(v);
alpar@1588
   306
      return *this;
alpar@1588
   307
    }
alpar@1588
   308
    ///\e
alpar@1588
   309
  
alpar@1588
   310
    ///\e
alpar@1588
   311
    ///
alpar@1588
   312
    template<class V>
alpar@1735
   313
    XmlIo &operator()(const std::string &_tag,const V &v)
alpar@1588
   314
    {
alpar@1588
   315
      Tag t(*this,_tag);
alpar@1735
   316
      xml(*this,const_cast<V &>(v));
alpar@1588
   317
      return *this;
alpar@1588
   318
    }
alpar@1588
   319
    ///\e
alpar@1588
   320
  
alpar@1588
   321
    ///\e
alpar@1588
   322
    ///
alpar@1588
   323
    template<class V>
alpar@1735
   324
    XmlIo &operator()(const V &v)
alpar@1588
   325
    {
alpar@1735
   326
      xml(*this,const_cast<V &>(v));
alpar@1588
   327
      return *this;
alpar@1588
   328
    }
alpar@1735
   329
    };
alpar@1428
   330
alpar@1588
   331
  //////////////////////////////////////////////////////////////////////
alpar@1588
   332
  //////////////////////////////////////////////////////////////////////
alpar@1588
   333
alpar@1735
   334
  ///\e
alpar@1735
   335
  
alpar@1735
   336
  ///\relates XmlIo
alpar@1735
   337
  ///
alpar@1588
   338
  template<class A>
alpar@1735
   339
  void xml(XmlIo &x,std::auto_ptr<A> &v)
alpar@1588
   340
  {
alpar@1735
   341
    if(x.write()) v=new A;
alpar@1588
   342
    x(*v);
alpar@1588
   343
  }
alpar@1735
   344
  
alpar@1735
   345
  ///\e
alpar@1735
   346
  
alpar@1735
   347
  ///\relates XmlIo
alpar@1735
   348
  ///
alpar@1588
   349
  template<class A,class B>
alpar@1735
   350
  void xml(XmlIo &x,std::pair<A,B> &v)
alpar@1588
   351
  {
alpar@1588
   352
    x("first",v.first);
alpar@1588
   353
    x("second",v.second);
alpar@1588
   354
  }
alpar@1588
   355
alpar@1735
   356
  ///\e
alpar@1735
   357
  
alpar@1735
   358
  ///\relates XmlIo
alpar@1735
   359
  ///
alpar@1735
   360
  template<class T>
alpar@1735
   361
  void xml(XmlIo &x,std::list<T> &v)
alpar@1588
   362
  {
alpar@1735
   363
    if(x.write())
alpar@1735
   364
      for(typename std::list<T>::const_iterator it=v.begin();
alpar@1735
   365
	  it!=v.end();++it) x("item",*it);
alpar@1735
   366
    else while(x.nextTag()=="item")
alpar@1588
   367
      {
alpar@1588
   368
	v.push_back(T());
alpar@1588
   369
	x("item",v.back());
alpar@1588
   370
      }
alpar@1588
   371
  }
alpar@1735
   372
  ///\e
alpar@1735
   373
  
alpar@1735
   374
  ///\relates XmlIo
alpar@1735
   375
  ///
alpar@1588
   376
  template<class T>
alpar@1735
   377
  void xml(XmlIo &x,std::vector<T> &v)
alpar@1588
   378
  {
alpar@1735
   379
    if(x.write())
alpar@1735
   380
      for(typename std::vector<T>::const_iterator it=v.begin();
alpar@1735
   381
	  it!=v.end();++it) x("item",*it);
alpar@1735
   382
    else while(x.nextTag()=="item")
alpar@1588
   383
      {
alpar@1588
   384
	v.push_back(T());
alpar@1588
   385
	x("item",v.back());      
alpar@1588
   386
      }
alpar@1588
   387
  }
alpar@1588
   388
alpar@1735
   389
  ///\e
alpar@1735
   390
  
alpar@1735
   391
  ///\relates XmlIo
alpar@1735
   392
  ///
alpar@1588
   393
  template<class K,class V>
alpar@1735
   394
  void xml(XmlIo &x,std::map<K,V> &v)
alpar@1588
   395
  {
alpar@1735
   396
    if(x.write()) 
alpar@1735
   397
      for(typename std::map<K,V>::const_iterator it=v.begin();
alpar@1735
   398
	  it!=v.end();++it) x("item",*it);
alpar@1735
   399
    else while(x.nextTag()=="item")
alpar@1588
   400
      {
alpar@1588
   401
	typename std::map<K,V>::value_type it;
alpar@1588
   402
	x("item",it);
alpar@1588
   403
	v.insert(it);
alpar@1588
   404
      }
alpar@1588
   405
  }
alpar@1588
   406
alpar@1735
   407
  ///\e
alpar@1735
   408
  
alpar@1735
   409
  ///\relates XmlIo
alpar@1735
   410
  ///
alpar@1588
   411
  template<class T>
alpar@1735
   412
  void xml(XmlIo &x,lemon::xy<T> &v)
alpar@1588
   413
  {
alpar@1735
   414
    { XmlIo::LineTag t(x,"x"); x(v.x); }
alpar@1735
   415
    { XmlIo::ContTag t(x,"y"); x(v.y); }
alpar@1588
   416
  }
alpar@1588
   417
alpar@1735
   418
  ///\e
alpar@1735
   419
  
alpar@1735
   420
  ///\relates XmlIo
alpar@1735
   421
  ///
alpar@1588
   422
  template<class T>
alpar@1735
   423
  void xml(XmlIo &x,lemon::BoundingBox<T> &v)
alpar@1588
   424
  {
alpar@1735
   425
    if(x.write()) {
alpar@1735
   426
      if(!v.empty()) {
alpar@1735
   427
	x("point",v.bottomLeft());
alpar@1735
   428
	if(v.bottomLeft()!=v.topRight()) x("point",v.topRight());
alpar@1735
   429
      }
alpar@1588
   430
    }
alpar@1735
   431
    else {
alpar@1735
   432
      v.clear();
alpar@1735
   433
      while(x.nextTag()=="point") {
alpar@1735
   434
	lemon::xy<T> co;
alpar@1735
   435
	x("point",co);
alpar@1735
   436
	v.add(co);
alpar@1735
   437
      }
alpar@1588
   438
    }
alpar@1588
   439
  }
alpar@1428
   440
  
alpar@1428
   441
}
alpar@1735
   442