/*-*-c++-*-
 * $Id: cgraphmanager.h,v 1.1 2002/01/28 15:38:32 holzheu Exp $
 *
 * This file is part of qlcrash, a GUI for the dump-analysis tool lcrash.
 *
 * Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
 *
 * Authors:
 * Michael Geselbracht (let@users.sourceforge.net)
 * Fritz Elfert (elfert@de.ibm.com)
 * Michael Holzheu (holzheu@de.ibm.com)
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version. See the file COPYING for more
 * information.
 */
#ifndef CGRAPHMANAGER_H
#define CGRAPHMANAGER_H

#include <qlist.h>
#include <qscrollview.h>
#include <qtimer.h>
#include <qintdict.h>

#include "crashtypes.h"

struct SMoveInfo;
#include "cgraphobject.h"

class QPushButton;
template<class T> class QVector;

/**Manages a set of widgets within a scrollview
  *@author Michael Geselbracht
  */

class CGraphManager : public QScrollView {
	Q_OBJECT

public:
	CGraphManager(QWidget* parent, const char* name=0);
	~CGraphManager();
	
	enum Direction { None, Left, Right, Up, Down };
	
	/** Add a new graph object to be managed.
	*/
	CGraphObject* addWidget(QWidget* child, const QString title);
	
	/** Remove a managed graph object. If a child is attached to this object, it will be detached.
	*/
	void removeWidget(CGraphObject* child);
	
	/** Auto layout all objects begining with child, which must be a root node.
	*/
	void layout();
	
	/** layout a single object.
	*/
	void layoutObject(CGraphObject*);
	
	/** Attach a child object to a parent. Both objects must be managed.
	*/
	void attach(CGraphObject* parent, CGraphObject* child, const QString& label);
	
	/** Detach a child from its parent.
	*/
	void detach(CGraphObject* child);
	
	/** Return the central widget managed by this scroll view.
	*/
	inline QWidget* mainWidget() {
		return oMainWidget;
	}
	
	/** Move viewport to make object visible. */
	void adjustNewObject(CGraphObject*);
	
	/** Set cursor for all objects. */
	virtual void setCursor(const QCursor& c);
	
	/** Unset cursor for all objects. */
	virtual void unsetCursor();
	
	/** Calculate start and end points for all children of this object. */
	void calculateEdges(CGraphObject*);
	
	/** Start/stop autoscroll */
	void scrollStart(Direction d);
	void scrollEnd();
	
	/** Return the currently selected object or null if there is no selected object */
	inline CGraphObject* selectedObject() const {
		return oSelectedObject;
	}
	
	/** Redraw contents */
	void redraw();
		
signals:
	/** A graph manager has been closed. */
	void sigClosed(CGraphManager*);
	
	/** A child has been closed. */
	void sigChildClosed(QWidget*);

public slots:
	void slotClicked(CGraphObject*);
	
protected:
	virtual void viewportResizeEvent(QResizeEvent*);
	virtual void closeEvent(QCloseEvent*);
	virtual bool eventFilter(QObject*, QEvent*);
	
private slots:
	void slotPostTimeout();
	void slotScrollTimeout();
	void slotChildMoved(CGraphObject*);
	void slotCloseChild(CGraphObject*);
	void slotDiscChild(CGraphObject*);
	
private:
	void postUpdate(int time=100);
	
	/** highlight the edge under the mouse pointer. */
	void highlightEdge(QPoint pos);
	
    /** Draw a line with arrow */
    void drawArrow(QPainter* p, int x1, int y1, int x2, int y2, QString str=QString::null);
	
    /** Layout all objects in a matrix. rootList is a list with all root objects. */
	void layoutMatrix(QList<CGraphObject>& rootList);
	
	/** Create a matrix with all object. */
	void layoutTraverse(CGraphObject* root, unsigned level);
	
	int layoutSizeX(int col);
	int layoutSizeY(int col);
	
	/** Calculate the width of all columns up to 'toCol'. */
	int layoutMaxX(int toCol=-1);

	/** Calculate the maximum height. */
	int layoutMaxY();
	
	/** Calculate y-position for 'obj', if it is a parent. Otherwise -1 is returned. */
	int layoutParentYPos(CGraphObject* obj);
	
	/** Calculate y-position for the first child of 'obj'. Returns -1 if there is no child. */
	int layoutChildYPos(CGraphObject* obj);
	
	/** which column is the heighest? */
	int layoutHighestCol();
		
	void print();
	
	void connectNodes(QPainter* p, CGraphObject*);
	int findQuadrant(int x1, int y1, int x2, int y2) const;
	
	/** Calculate the absolute angle of the line connecting the two points x1,y1 and x2,y2.
		x1 and x2 must not have the same value.
	*/
	double tanAlpha(int x1, int y1, int x2, int y2) const;
	
	void clearHighlight();
	
	/** (debug)
	*/
	void printMatrix();
	void printChildList();
	
private:
	QList<CGraphObject> oChildList;
	QWidget* oMainWidget;
	QTimer oPostTimer;
	int oGridX;
	int oGridY;
	QIntDict<QIntDict<CGraphObject> > oMatrix;
	CGraphObject* oSelectedObject;
	CGraphObject* oLastAddedObject;
	int oOldChildX;
	int oOldChildY;
	QPoint oOldContentPos;
	CLine oCurrentHighlight;
	QTimer oScrollTimer;
	Direction oScrollDirection;
};

#endif
