/* This file is part of the KDE libraries
    Copyright (c) 1998 Emmeran Seehuber (the_emmy@hotmail.com)
 
    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library 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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.
*/

#ifndef KLCHILDMETA_H
#define KLCHILDMETA_H

#include "qstring.h"
#include "qtstream.h"
#include "qdict.h"
#include "qlist.h"
#include "qstrlist.h"

/**
* This is the baseclass for all metaclasses
* in the KLE
*
* It describes all things important for a
* GUI designer and for serialising
*/

class KLDumpDevice;
class KLChild;
class KLGridGroup;
class KLChildMeta 
{
public:
  /**
  * Constructor/Destructor
  */
  KLChildMeta() : parentMeta(0) {};
  virtual ~KLChildMeta() {};

  /**
  * Metaclass of the parent class
  */
  KLChildMeta *parentMeta; 

  /**
  * Unique Class Name
  *
  * This can be:
  *  - A buildin name (e.g. "KLLineEdit")
  *  - A named instance of an existing class: Syntax "clone:className#Name". 
  *    This is used, when you autoedit an existing layout
  *  - A URL-Name of a shared lib class (e.g. "file:/opt/kde/shared/controls/hypergigangitg.ctrl") (not yet)
  *  - A Application URL (e.g. "app:/superdebugger/stack/backtracelistbox") (not yet)
  *    - At the first step, such controls can only be in one application
  *    - (Perhaps) later this will change, so that you could import such controls from other applications.
  *      (Would be directly using CORBA be a better model -- Would it make this possible ?)
  */
  QString className;

  /**
  * User Class Name
  *
  * The name, under wich the user will see the control (will also be translated)
  */
  QString userClassName;

  /**
  * Tree display path ("/" sepearated)  
  * (in the GUI editor "avail widget tree")
  * If no displaypath is specified, the Class is not
  * displayed. This is also the default
  *
  * You may change the path of exiting metaclass
  * to fit in your controltree.
  *
  * This path is only for displaying the widget tree.
  * So changing it will perhaps only currupt the widget tree.
  */
  QString displayPath;

  /**
  * Class types
  *
  * - StandAlone: Objects of this class don't need a specific application
  *               environment. (e.g. a command execute button, a label or a image,
  *               also HVGroups and GridGroups)
  * - FixUnique:  This metaclass was created by autoedit with an existing
  *               object. It depends where much on a existing applicaton
  *               envirnoment. The object should never be delete inside the KLE! 
  *               It can only be displayed one time. (Because it is not possible
  *               to recreate the object)
  * - Multiple:   Objects of this class can exists as many as you want.
  *               There setup there environment (connect()-ions, etc) thereself.
  *               They all display the same data. If you change
  *               the data in one object, there will/must be synced
  *               with all other existing objects of this class.
  */ 
  enum ClassType { StandAlone, FixUnique, Multiple };

  /**
  * Get the classtype of this class.
  */
  virtual ClassType classType() const = 0;

  /**
  * Creates an empty object of this class
  *
  * @param envinfo Application depending environment information
  */
  virtual KLChild *createObject(void *envinfo) const = 0;


  /**
  * Create the object edit 
  *
  * First call createObjectEdit() of KLChildMeta. It will
  * create a KLGridGroup with 2 coloums for you, and insert its
  * edits. Then you should add your edits. Note: The first
  * coloum should be a description. If you don't have
  * a description (e.g. when you have a checkbox), insert 
  * a HVSpace() for the description, so that the checkbox would
  * be in the second coloumn.
  *
  * Note that you can change this behavor.E.g. if you want to 
  * display tabctrls. In this case you should e.g. insert
  * the baseclass settings as one page. But please documentate
  * this, so that derivided classes knows how they must insert
  * there additional edits.
  *
  * If extended is false, than you should not display very
  * "danguras" or complex options (e.g. when specifing false
  * when calling createObjectEdit() of the KLChild-Metaclass,
  * there will be now fixXSize and fixYSize edits). 
  *
  * You must (of course) not call the baseclass, e.g. if you
  * only want your special edits.
  *
  * @param object Pointer to the object to create the edit for
  * @param extended If true, create an extended edit
  */
  virtual KLChild *createObjectEdit(KLChild *object, bool extended=false) const;

  /**
  * Dump the object (and all containted subobjects)
  *
  * You have only to write the <Data>. DON`T write the 
  * <Hierarchie identifing key> nor <ClassName>. This 
  * will be done for you. 
  *
  * You donīt need to call the method of your 
  * supermetaclass.
  *
  * @return true, if successfull dumped.
  * @param object Object to dump
  * @param stream Stream to dump on
  * @see restoreObject
  */
  virtual bool dumpObject(KLChild *object, KLDumpDevice &stream) const;

  /**
  * Restore the object (and all contained subobjects)
  *
  * Read your data from the stream.
  *
  * IMPORTANT NOTE: You must make sure yourself, that you not read
  * too much data from the stream !! (Which you perhaps will
  * not need)
  *
  * You donīt need to call the method of your 
  * supermetaclass.
  * @param object Object to restore 
  * @param stream Stream to restore the object from
  */
  virtual void restoreObject(KLChild *object, KLDumpDevice &stream) const;

  /**
  * Completly dump this object. This means, that the dumpObject method
  * of this metaClass is called and of all parent metaclasses.
  * @param object Object to dump
  * @param stream Stream to dump the object into
  * @see dumpObject
  */
  static bool dumpCompleteObject(KLChild *object, KLDumpDevice &stream);

  /**
  * Completly restore this object. This means, that it will create
  * the object and than call the restoreObject() methods
  * of all metaclasses.
  *
  * If you give a object as paramter, it will use this object and not
  * create a new one. It will also HASSERT the same metaclass !
  * 
  * Assumes this on the stream:
  * <pre>
  * { ClassName
  * <Data>
  * }
  * </pre>
  *
  * @param stream Stream to restore the object from
  * @param object If not 0, object to restore the data in 
  */
  static KLChild *restoreCompleteObject( KLDumpDevice &stream, KLChild *object = 0);
};

/**
* MetaClass for standalone classes
*/
class KLChildMetaStandAlone.html">KLChildMetaStandAlone : public KLChildMeta {
public:
  virtual ClassType classType() const;
};
#define DECLARE_KLMETA_STANDALONE()                           \
  public:                                                     \
  class MyChildMeta : public KLChildMetaStandAlone            \
  {                                                           \
    public:                                                   \
    MyChildMeta();                                            \
    virtual KLChild *createObject(void *) const;              \
    virtual KLChild *createObjectEdit(KLChild *,bool) const;  \
    virtual bool dumpObject(KLChild *, KLDumpDevice&) const;  \
    virtual void restoreObject(KLChild *, KLDumpDevice&) const;\
  };                                                          \
  static MyChildMeta metaClass;                               \
  friend MyChildMeta;                                         \
  public:                                                     \
  virtual const KLChildMeta *getMetaClass() const             \
  { return &metaClass; }

#define DECLARE_KLMETA_STANDALONE_SIMPLE()                    \
  public:                                                     \
  class MyChildMeta : public KLChildMetaStandAlone            \
  {                                                           \
    public:                                                   \
    MyChildMeta();                                            \
    virtual KLChild *createObject(void *) const;              \
  };                                                          \
  friend MyChildMeta;                                         \
  static MyChildMeta metaClass;                               \
  public:                                                     \
  virtual const KLChildMeta *getMetaClass() const             \
  { return &metaClass; }

#define IMPLEMENT_KLMETA_STANDALONE(classname,superclassname,userclassname) \
  classname::MyChildMeta::MyChildMeta()                       \
  {                                                           \
    userClassName = userclassname;                            \
    className = #classname ;                                  \
    parentMeta = &superclassname::metaClass;                  \
  }                                                           \
  KLChild *classname::MyChildMeta::createObject(void *) const \
  {                                                           \
    return new classname();                                   \
  }                                                           \
  classname::MyChildMeta classname::metaClass

  

/**
* MetaClass for FixUnique classes
*/
class KLChildMetaFixUnique.html">KLChildMetaFixUnique : public KLChildMeta {
public:
  KLChild *a_object;
  virtual ClassType classType() const;
  virtual KLChild *createObject(void *envinfo) const;
};

/**
* Metaclass for Multiple classes
*/
class KLChildMetaMultiple.html">KLChildMetaMultiple : public KLChildMeta 
{
public:
  virtual ClassType classType() const;
};

/**
* Metaclass registration list. 
*/
class KLMetaRegList : public QList<KLChildMeta> 
{
public:
  /**
  * Register a metaclas
  */
  void regMetaClass(KLChildMeta *);

  /**
  * Unregister a metaclass
  */
  void unRegMetaClass(KLChildMeta *);

  /**
  * Find a metaclass via itīs classname
  *
  * A leading "{ " will be deleted
  */
  KLChildMeta *findMetaClass(const char *className) const;

private:
  QDict<KLChildMeta> index;
};

/**
* Dump device for Layouts. 
*
* NOTE: The actual implementation is not very optimal.
* Itīs a quick maked and slow runing implementation. Should be replaced
* by something more optimized in future.
* So forget about performance at the moment.
*/
class KLDumpDevice : public QTextStream 
{
public:
  KLDumpDevice(QIODevice &file);
  void readFile(); // Readīs the complete file into an strlist array
  
  /**
  * Helper: Iterate through the line list of one level.
  * Start at line. Level must be initaliesed at start to 0.
  * 
  * You can use this in a while-construct to get all lines of one level
  * 
  * QString linestr;
  * ulong line = 0, level = 0;
  * while( dev.readLine(linestr,line,level) ) {
  *  // Do whatever you want with linestr
  * }
  */
  bool readLine( QString &string, ulong &line, ulong &level);

  /**
  * Read an Entry in the form of 
  *
  * KEY=data
  */
  QString readEntry(const char *entryname, const char *def);

  /**
  * Same as readEntry(). It only converts \n and \t in the data.
  */  
  QString readEntryConv(const char *entryname, const char *def);

  void writeLevelStart(const char *levelname);
  void writeEntry(const char *entryname, const char *entrydata);
  void writeEntryConv(const char *entryname, const char *entrydata);
  void writeComment(const char *comment);
  void writeLevelEnd();

public:
  QStrList lineBuff;
  ulong    linestart;
  QString  indent;
  KLMetaRegList *reglist;
  /**
  * Must be set when reading
  */
  void    *appenv; 
};

#endif 


Documentation generated by emmy@gate on Tue Sep 22 21:13:27 MEST 1998