#ifndef _PLOTWIDGET_H_
#define _PLOTWIDGET_H_


#include <qwidget.h>
#include <qpopmenu.h>
#include <qpainter.h>
#include <qpixmap.h>
#include <qlist.h>
#include <qfile.h>

#include <kconfig.h>

#include "pageobject.h"
#include "tree.h"
#include "column.h"


class Page;


/** A plot widget ABC for all kind of diagraphs.

	Overview:

	Plot is an ABC for any kind of plots, be it x/y plots, r/phi
	plots or histograms. Because a plot is a very general thing, this
	class is full of pure virtual functions. In fact, this class is only
	the interface definition for plots.

	A plot must provide quite a lot of functionality:

	- Plots must be able to paint themselves onto a given painter. They
	  have to implement the paint(QPainter*) method.

	- Plots must provide information about themselves. That is, they must
	  provide access to their type, a short description, the parameters
	  they take, the icon they want to wear in the tree view, their own
	  main menu entry.

	- Plots can include multiple data sets, so they must provide methods
	  to access them: add a new plot, remove an existing one, change an
	  existing one.

	- A plot type must register itself, i.e. it has to provide a prototype
	  of itself. This prototype delivers information that would have been
	  implemented as "static virtual" functions if that was possible
	  (which it isnīt), and they are clone()d when the user wants a new
	  plot. See [1] for details on the Prototype pattern. The prototype
	  list is used to provide a global list of available plot types.

	A short story about the creation of the design of the ABC:

	I thought long  about how to realize a base  class  for  _all_  plots.
	I thought and Thought and THOUGHT, but to no avail. Clumsily, I longed
	for my last Tannezäpfle,  I opened  it and drunk.  Alocohol and carbon
	dioxide washed through my brain, and the bitter taste of hops thunder-
	strucked the synapses... I was enlighted! I could make the "Plot" menu
	entry local to the plot itself and use getMenu() to get its handle!
	(Patrick Schemitz, 97/10/16)

	In a less prosaic speaking, I hit upon the idea of moving all
	plot-specific widgets (such as menus, dialogs etc) into the widgets
	instead of letting the main widget deal with them. To put it even
	lesser prosaic, I just followed the old o-o rule: if it walks like
	a duck and quacks like a duck, it *is* a duck.

	Since the Plot class wants its subclasses to specify the objects it
    creates, i.e. the Plot's subclasses are created by the main widget,
	I clone() the selected Prototype of the concrete plot. Therefore,
	each plot must register itself to that plot list, plotList().

	Debugging:

	The Plot classes debug output can be controlled by setting
	the debug level for "korigin.pw" to 0 (silent), 1 (warnings/errors),
	3 (verbose), 4 (*very* verbose).

	[1] Gamma, Helm, Johnson, Vlissides: Design Patterns. 
	- Addison-Wesley, 1994.

	@see HistoPlot for a concrete plot
	@see REGISTER_PLOT() to register concrete plots
	@see Plots() the prototype list singleton
	@author Patrick Schemitz
*/

class Plot : public PageObject
{
  Q_OBJECT

public:
  
  /** Construct a Plotīs shell only.

	  Initializes a plot. Warning: the constructor does *not*
	  create the widget belonging to the plot! The widget must be
	  set up with the instantiate() function!!!

	  @see #instantiate() to create actual widget.
  */
  Plot ();

  /** Destructor.

	  Deletes the widget of the plot.
  */
  virtual ~Plot ();

  /** Actually create the plotīs widget.

	  The constructor only creates an empty shell of a plot, and
	  a single menu entry for the plotīs menu(): "Plot columns".
	  This function here creates the actual widget representing
	  the plot. and passes its parameters to QWidget. To access
	  the widget from outside the class, use the widget()
	  function. The widget is destructed by Plotīs destructor.
	  You will have to reimplement this function for nearly any
	  concrete plot: in here, colors and fonts can be initialized,
	  as well as the plotīs menu. DONīT FORGET to call the original
	  function, Plot::instantiate() FIRST! You have been warned.

	  @see #widget()
	  @see #menu()
  */
  virtual void instantiate (Page*, QWidget* parent=0, const char* name=0, 
							WFlags f=0);

  /** Return the QWidget of the plot.

	  Since the Plot is not a QWidget itself (it only inherits QObject),
	  you need this function to get the associated widget. The widget
	  is set up by instantiate(). If you call widget() before you call
	  instantiate(), a null pointer is returned. Note that the widget
	  is destructed by Plotīs destructor.

	  @see #instantiate()
  */
  QWidget* widget () { return the_widget; }

  /** Clone function.

	  This function is used to clone the prototype of a
	  derived Plot. Thus the name, Prototype pattern.
  */
  virtual Plot* clone () = 0;

  /** Return appropriate "Plot" submenu.

	  A variable "the_menu" of type QPopupMenu* is already defined for you,
	  but the default instantiate() routine inserts only one entry, thus
	  the "Plot columns" entry which is connected to the plotīs
	  plotSelectedColumns() slot. If you want more entries (this is very
	  likely), add them in your instantiate() function.

	  @return the main menu entry for the concrete plot.
  */
  virtual QPopupMenu* menu (QPopupMenu* predefined = 0) = 0;

  /** Set active plot and icon.

	  This sets the activePage to the invoked plots, and changes
	  the plotīs icon to active.
  */
  virtual void activate ();

  /** Set inactive plot and icon.

	  This changes the plotīs icon to active.
  */
  virtual void deactivate ();

  /** Store overall options for the plot.

	  With overall options I mean the options that are valid
	  for *all* plots of a kind, i.e. static class variables.

	  The implementation should store the options in the applicationīs
	  KConfig object, kapp->getConfig().

	  @see #restoreOptions()
	  @see #optionsDialog()
  */
  virtual void storeOptions () = 0;

  /** Restore overall options for the plot.

	  With overall options I mean the options that are valid
	  for *all* plots of a kind, i.e. static class variables.

	  The implementation should restore the options from the applicationīs
	  KConfig object, kapp->getConfig().

	  @see #storeOptions()
	  @see #optionsDialog()
  */
  virtual void restoreOptions () = 0;

  /** Start-of-plot mark.

	  Should be something like <histo>.
  */
  virtual const char* start_mark () = 0;

  /** End-of-plot mark.

	  Should be something like </histo>.
  */
  virtual const char* end_mark () = 0;

  /** Store a plot to a QFile.

	  This function is intended to write a plot to the given QFile.
	  If with_data==false, only the settings of this instance are
	  stored; if with_data==true, the columns are to be stored, too.
	  Please note that QFile is already opened and positioned when
	  passed to store(). Also note that QFile may already contain
	  other plots and/or worksheets.

	  @see #restore()
  */
  virtual bool store (QFile&, bool with_data) = 0;

  /** Restore a plot from a QFile.

	  This function is intended to read a plot from the given QFile.
	  If with_data==false, only the settings of this instance are
	  restored; if with_data==true, the columns are to be restored, too.
	  Please note that QFile is already opened and positioned when
	  passed to restore(). Also note that QFile may already contain
	  other plots and/or worksheets.

	  @see #store()
	  @see PageObject#store()
  */
  virtual bool restore (QFile&, bool with_data) = 0;

  /** [pure virtual] Return name/type info for your plot.

	  The histogram type, HistoPlot, for example, returns "Histogram 1D".

	  @return type info for concrete plot.
  */
  virtual const char* name () = 0;

  /** [pure virtual] Return a short description of instance.

	  The canonical example of a plot, HistoPlot, returns a string
	  with information on the binning (i.e. the x step width) of the
	  histogram.

	  @return brief description of an instance of a concrete plot.
  */
  virtual const char* description () = 0;

  /** [pure virtual] Return the pixmap for the tree view.

	  x/y plots have other symbols than R/Phi plots, so pure virtual. BTW,
	  you should check whether this==activePlot and select the "active"
	  symbol if appropriate.

	  @return pixmap for concrete plot type.
  */
  virtual QPixmap* icon () = 0;

  /** [pure virtual] Number of the plots parameters.

	  This function defines how many columns are feed to a concrete
	  plot (via insertSet). The canonical example,
	  the HistoPlot, has only one parameter, the "Event". An X/Y plot is
	  more interesting: 5 parameters x, y, x error, y error, label.

	  @return number of parameters.
  */
  virtual int paramCount () = 0;

  /** [pure virtual] Names of the plots parameters.

	  This function defines the names of the parameters of a concrete
	  class. The canonical example,
	  the HistoPlot, has only one parameter, the "Event". An X/Y plot is
	  more interesting: x, y, x error, y error, label.

	  @param i number of the requested parameter name.
	  @return name of the i-th parameters.
  */
  virtual const char* paramName (int i) = 0;

  /** [pure virtual] Paint yourself on a given painter.

	  Your concrete plot must implement this function. The QPainter
	  parameter is where the plot must paint itself on. This may be
	  the plot page's QWidget, or a QPrinter.

	  @param p the painter where your plot has to plot itself on.
  */
  virtual void paint (QPainter* p) = 0;

  /** Implement mouse handling.

	  The default implementation does nothing, i.e. ignores mouse events.
	  Your plot widget might pop up a menu on right mouse button, for
	  example.

	  Note, however, that only right mouse button clicks are passed to
	  this function; the left mouse button is used to move plots around
	  the page.
  */
  virtual void mousePressEvent (QMouseEvent*) { }

  /** Returns pointer to the default plot typeīs prototype.

	  This function reads the KConfig entry "default_plot" in the
	  [Plot] group, scans the Plots() list for it and returns a
	  pointer to the corresponding prototype. If it canīt find the
	  default_plot, it returns the first plot in the Plots() list.
	  If the list is empty, it returns 0.
  */
  static Plot* defaultPlot ();

signals:

  /** This signal is emitted when the tree item of the plot has changed.

 	  (By editing the caption, (de)activating the plot, deleteing or
	  inserting datasets.)
  */
  void changedTreeItem ();

public slots:

  /** Display the plotīs options dialog.

	  With overall options I mean the options that are valid
	  for *all* plots of a kind, i.e. static class variables.

	  @see #storeOptions()
	  @see #restoreOptions()
  */
  virtual void optionsDialog () = 0;

  /** Plot the data in selected columns of the active worksheet.

	  This function gets the selected (highlighted) columns in
	  the active worksheet via activeWS->getSelected(), and plots
	  then in itself. Of course, this function must be implemented
	  by the concrete plot classes.
  */
  virtual void plotSelectedColumns () = 0;

protected:

  /** variable to store the plotīs widget. */
  QWidget* the_widget;

  /** variable to store the concrete plot's menu entry. */
  QPopupMenu* the_menu;

  /** variable to store the active icon. */
  QPixmap* active_icon;
  /** variable to store the inactive icon. */
  QPixmap* inactive_icon;

  /** DON'T RE-IMPLEMENT THIS!

	  Just a wrapper for paint(QPainter*).
  */
  void paintEvent (QPaintEvent*);
};


/** Pointer to the currently active plotwidget.

	Provided for the main widget, this variable determinates the pixmap
	returned by getSymbol(): the active plot has a different symbol than
	an inactive plot. Also used to send the selected columns of a worksheet
	to the right plotwidget.
*/
extern Plot* activePlot;


/** Type definition for plotList.

	This is just a template instatiation of Qt's QList for
	a list of Plot. Intelligent as the QList is, it actually
	stores a list of pointers, which is exactly what we want here,
	since class Plot is abstract and therefore cannot be instantiated.

	@see Plots()
*/
typedef QList<Plot> PlotList;


/** List of all concrete plots.

	This Singleton collects all concrete plots. To get registered,
	the concrete plot must invoke REGISTER_PLOT().

	This list is used to build and execute the "Plot|New Plot"
	submenu.

	@see REGISTER_PLOT() to fill the list.
*/
PlotList& Plots ();


/** Register a concrete plot class.

	Generates a class and an instance to register a Prototype of the plot
	type in the PlotList. "type" is the name of the plot class, e.g.
	HistoPlot.

	In your implementation file of your concrete plot, myplot.cc, this
	macro *must* be invoked on top level, i.e. globally. Best place it
	just behind the #include orgy.

	Do not forget the semicolon after the macro name!

	@see Plots() which gets filled by REGISTER_PLOT
*/
#define REGISTER_PLOT(type)                    \
                                               \
  class Creator##type {                        \
  public:                                      \
    Creator##type () {                         \
      Plots().append(new type);                \
    }                                          \
  };                                           \
                                               \
  Creator##type initCreator##type


#endif

Documentation generated by patrick@nemesis on Tue Feb 10 23:05:12 MET 1998