
/***************************************************************************
                          codeeditor.h  -  description
                             -------------------
    begin                : Fri Aug 1 2003
    copyright            : (C) 2003 by Brian Thomas
    email                : brian.thomas@gsfc.nasa.gov
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#ifndef CODEEDITOR_H
#define CODEEDITOR_H

#include <qpopupmenu.h>
#include <qstring.h>
#include <qlabel.h>
#include <qtextedit.h>
#include "../codeviewerstate.h"

class UMLObject;

class CodeViewerDialog;
class CodeComment;
class CodeDocument;
class CodeClassFieldDeclarationBlock;
class CodeMethodBlock;
class CodeBlockWithComments;
class HierarchicalCodeBlock;

class TextBlockInfo;
class TextBlock;
class ParaInfo;

class CodeEditor : public QTextEdit
{
    Q_OBJECT
public:

	CodeEditor ( const QString & text, const QString & context = QString::null, CodeViewerDialog * parent = 0, const char * name = 0 , CodeDocument * doc = 0);
	CodeEditor ( CodeViewerDialog * parent, const char* name = 0, CodeDocument * doc = 0);
	~CodeEditor ();

	// return code viewer state
	Settings::CodeViewerState getState( );

protected:

	bool close ( bool alsoDelete ); 

	// various methods for appending various types of text blocks in the editor.
        void appendText (TextBlock * tblock);
        void appendText (HierarchicalCodeBlock * hblock);
        void appendText (CodeClassFieldDeclarationBlock * db );
        void appendText (QPtrList<TextBlock> * items);
        void appendText (CodeMethodBlock * mb);
        void appendText (CodeComment * comment, TextBlock * parent, UMLObject * umlObj = 0, const QString & compName="");
	void appendText (CodeBlockWithComments * cb );

        // Rebuild our view of the document. Happens whenever we change
        // some field/aspect of an underlying UML object used to create
        // the view.
        // If connections are right, then the UMLObject will send out the modified()
        // signal which will trigger a call to re-generate the appropriate code within
        // the code document. Our burden is to appropriately prepare the tool: we clear
        // out ALL the textblocks in the QTextEdit widget and then re-show them
        // after the dialog disappears
        void rebuildView( int startCursorPos );

	// override the QT event so we can do appropriate things
	void contentsMouseMoveEvent ( QMouseEvent * e );

	// implemented so we may capture certain key presses, namely backspace
	// and 'return' events.
	void keyPressEvent ( QKeyEvent * e );

	// (re) load the parent code document into the editor
        void loadFromDocument();

	// specialized popup menu for our tool
	QPopupMenu * createPopupMenu ( const QPoint & pos );

private:

	QString parentDocName;
	CodeDocument * m_parentDoc;
	CodeViewerDialog * m_parentDlg;

	int m_lastPara;
        int m_lastPos;

        bool m_newLinePressed;
        bool m_backspacePressed;
        bool m_isHighlighted;
        bool m_showHiddenBlocks;

	TextBlock * m_textBlockToPaste;
        TextBlock * m_selectedTextBlock;
        TextBlock * m_lastTextBlockToBeEdited;

        QMap<TextBlock*, TextBlockInfo*> *m_tbInfoMap;
        QPtrList<TextBlock> m_textBlockList;

	// main insert routine. Will append if startline is not supplied. 
        void insert (const QString & text, TextBlock * parent, bool isEditable = false,
                     const QColor & fgcolor = QColor("black"), const QColor & bgcolor = QColor("white"),
                     UMLObject * umlobj = 0, const QString & displayName = "", int startLine = -1);

        void editTextBlock(TextBlock * tBlock, int para);
	void clearText();
	QLabel * getComponentLabel();
	bool paraIsNotSingleLine (int para);
        void expandSelectedParagraph( int where );
        void contractSelectedParagraph( int where );
        void updateTextBlockFromText (TextBlock * block);

        void initText ( CodeDocument * doc );
	void init ( CodeViewerDialog * parentDlg, CodeDocument * parentDoc );

        void changeTextBlockHighlighting(TextBlock * tb, bool selected);
        bool isParaEditable (int para);
        bool textBlockIsClickable(UMLObject * obj);

	// return whether or not the passed string is empty or 
	// contains nothing but whitespace
	static bool StringIsBlank( const QString &str ); 

public slots:

	void insertParagraph ( const QString & text, int para );
	void removeParagraph ( int para );
        void changeHighlighting(int signal);
	void changeShowHidden (int signal);
	void slotRedrawText();

protected slots:

        void clicked(int para, int pos );
        void doubleClicked(int para, int pos );
        void cursorPositionChanged(int para, int pos );
	void slotCopyTextBlock ( );
	void slotCutTextBlock ( );
	void slotPasteTextBlock ( );
	void slotChangeSelectedBlockView();
	void slotChangeSelectedBlockCommentView();
	void slotInsertCodeBlockAfterSelected();
	void slotInsertCodeBlockBeforeSelected();

signals:

/*
	void sigNewLinePressed ();
	void sigBackspacePressed ();
*/

};

class ParaInfo {
public:
        int start; // this is a relative offset from the beginning of the tblock
        int size;
        QColor fgcolor;
        QColor bgcolor;
        bool isEditable;

        ParaInfo () { isEditable = false; }
};

class TextBlockInfo {
public:
        QPtrList<ParaInfo> m_paraList;
        UMLObject * m_parent;
        QString displayName;
        bool isClickable;
	bool isCodeAccessorMethod;

        TextBlockInfo () { m_parent = 0; isClickable = false; isCodeAccessorMethod = false; }
        void setParent(UMLObject *p = 0) { m_parent = p; }
        UMLObject * getParent() { return m_parent; }

};

#endif // CODEEDITOR_H
