/*
 * Copyright Johannes Sixt
 * This file is licensed under the GNU General Public License Version 2.
 * See the file COPYING in the toplevel directory of the source directory.
 */

#ifndef SOURCEWND_H
#define SOURCEWND_H

#include <tqpixmap.h>
#include <tqtextedit.h>
#include <tqsyntaxhighlighter.h>
#include <vector>
#include "dbgdriver.h"

// forward declarations
class KDebugger;
struct DbgAddr;

class SourceWindow : public TQTextEdit
{
    TQ_OBJECT
public:
    SourceWindow(const TQString& fileName, TQWidget* parent, const char* name);
    ~SourceWindow();
    
    bool loadFile();
    void reloadFile();
    bool fileNameMatches(const TQString& other);
    void scrollTo(int lineNo, const DbgAddr& address);
    const TQString& fileName() const { return m_fileName; }
    void updateLineItems(const KDebugger* dbg);
    void setPC(bool set, int lineNo, const DbgAddr& address, int frameNo);
    enum FindDirection { findForward = 1, findBackward = -1 };
    void find(const TQString& text, bool caseSensitive, FindDirection dir);
    bool wordAtPoint(const TQPoint& p, TQString& word, TQRect& r);
    /**
     * Translates row number (zero-based) to zero-based source line number.
     * If sourceRow is non-zero, it is filled with the source code row
     * belonging to the line number.
     */
    int rowToLine(int row, int* sourceRow = 0);
    /** Translates zero-based source line number to row number (zero-based) */
    int lineToRow(int line);
    /** Is the row disassembled? */
    bool isRowExpanded(int row);
    /** Does the row show disassembled code? */
    bool isRowDisassCode(int row);

    /** lineNo is zero-based */
    void disassembled(int lineNo, const std::list<DisassembledCode>& disass);

    void activeLine(int& lineNo, DbgAddr& address);

protected:
    virtual void drawFrame(TQPainter* p);
    virtual bool eventFilter(TQObject* watched, TQEvent* e);
    virtual void contextMenuEvent(TQContextMenuEvent* e);
    virtual void mousePressEvent(TQMouseEvent* ev);
    virtual void keyPressEvent(TQKeyEvent* ev);
    virtual void paletteChange(const TQPalette&);
    void expandRow(int row);
    void collapseRow(int row);
    void scrollToRow(int row);
    /** translates (0-based) line number plus a code address into a row number */
    int lineToRow(int row, const DbgAddr& address);

    void actionExpandRow(int row);
    void actionCollapseRow(int row);

signals:
    void clickedLeft(const TQString&, int, const DbgAddr& address, bool);
    void clickedMid(const TQString&, int, const DbgAddr& address);
    void disassemble(const TQString&, int);
    void expanded(int lineNo);		/* source lineNo has been expanded */
    void collapsed(int lineNo);		/* source lineNo has been collapsed */
public slots:
    void setTabWidth(int numChars);
    void cursorChanged(int row);

protected:
    TQString m_fileName;
    enum LineItem { liPC = 1, liPCup = 2,
	liBP = 4, liBPdisabled = 8, liBPtemporary = 16,
	liBPconditional = 32, liBPorphan = 64,
	liBPany = liBP|liBPdisabled|liBPtemporary|liBPconditional|liBPorphan
    };

    struct SourceLine {
	TQString code;			/* a line of text */
	std::vector<TQString> disass;		/* its disassembled code */
	std::vector<DbgAddr> disassAddr;	/* the addresses thereof */
	bool canDisass;			/* if line can be disassembled */
	SourceLine() : canDisass(true) { }
	int findAddressRowOffset(const DbgAddr& address) const;
    };
    std::vector<SourceLine> m_sourceCode;

    std::vector<int> m_rowToLine;	//!< The source line number for each row
    std::vector<uchar> m_lineItems;	//!< Icons displayed on the line
    TQPixmap m_pcinner;			/* PC at innermost frame */
    TQPixmap m_pcup;			/* PC at frame up the stack */
    TQPixmap m_brkena;			/* enabled breakpoint */
    TQPixmap m_brkdis;			/* disabled breakpoint */
    TQPixmap m_brktmp;			/* temporary breakpoint marker */
    TQPixmap m_brkcond;			/* conditional breakpoint marker */
    TQPixmap m_brkorph;			/* orphaned breakpoint marker */
    TQFont m_lineNoFont;			//!< The font used to draw line numbers
    int m_curRow;			//!< The highlighted row
    int m_widthItems;			//!< The width of the item column
    int m_widthPlus;			//!< The width of the expander column
    int m_widthLineNo;			//!< The width of the line number columns
};

class HighlightCpp : public TQSyntaxHighlighter
{
    SourceWindow* m_srcWnd;

public:
    HighlightCpp(SourceWindow* srcWnd);
    virtual int highlightParagraph(const TQString& text, int state);
};

#endif // SOURCEWND_H
