#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