/*
 * KMComposeWin Header File
 * Author: Markus Wuebben <markus.wuebben@kde.org>
 */
#ifndef __KMAIL_KMEDIT_H__
#define __KMAIL_KMEDIT_H__

#include <keditcl.h>
#include <tdespell.h>
#include <ksyntaxhighlighter.h>
#include <tqmap.h>
#include <tqstringlist.h>
#include <tqclipboard.h>

class KMComposeWin;
class KSpellConfig;
class SpellingFilter;
class KTempFile;
class KDirWatch;
class TDEProcess;
class TQPopupMenu;

/**
 * Reimplemented to make writePersonalDictionary() public, which we call everytime after
 * adding a word to the dictionary (for safety's sake and because the highlighter needs to reload
 * the personal word list, and for that, it needs to be written to disc)
 */
class KMSpell : public KSpell
{
  public:

    KMSpell( TQObject *receiver, const char *slot, KSpellConfig *spellConfig );
    using KSpell::writePersonalDictionary;
};

/**
 * Reimplemented to add support for ignored words
 */
class KMSyntaxHighter : public KDictSpellingHighlighter
{
  public:

    KMSyntaxHighter( TQTextEdit *textEdit,
                     bool spellCheckingActive = true,
                     bool autoEnable = true,
                     const TQColor& spellColor = red,
                     bool colorQuoting = false,
                     const TQColor& QuoteColor0 = black,
                     const TQColor& QuoteColor1 = TQColor( 0x00, 0x80, 0x00 ),
                     const TQColor& QuoteColor2 = TQColor( 0x00, 0x70, 0x00 ),
                     const TQColor& QuoteColor3 = TQColor( 0x00, 0x60, 0x00 ),
                     KSpellConfig *spellConfig = 0 );

    /** Reimplemented */
    virtual bool isMisspelled( const TQString &word );

    void ignoreWord( const TQString &word );

    TQStringList ignoredWords() const;

  private:
    TQStringList mIgnoredWords;
};

class KMEdit : public KEdit {
  TQ_OBJECT
  
public:
  KMEdit(TQWidget *parent=0,KMComposeWin* composer=0,
         KSpellConfig* spellConfig = 0,
	 const char *name=0);
  ~KMEdit();

  /**
   * Start the spell checker.
   */
  void spellcheck();

  /**
   * Text with lines breaks inserted after every row
   */
  TQString brokenText();

   /**
   * Toggle automatic spellchecking
   */
  int autoSpellChecking( bool );

  /**
   * For the external editor
   */
  void setUseExternalEditor( bool use ) { mUseExtEditor = use; }
  void setExternalEditorPath( const TQString & path ) { mExtEditor = path; }

  /**
   * Check that the external editor has finished and output a warning
   * if it hasn't.
   * @return false if the user chose to cancel whatever operation
   * called this method.
   */
  bool checkExternalEditorFinished();

  TQPopupMenu* createPopupMenu(const TQPoint&);
  void setSpellCheckingActive(bool spellCheckingActive);

  /** Drag and drop methods */
  void contentsDragEnterEvent(TQDragEnterEvent *e);
  void contentsDragMoveEvent(TQDragMoveEvent *e);
  void contentsDropEvent(TQDropEvent *e);

  void deleteAutoSpellChecking();

  unsigned int lineBreakColumn() const;
  
  /** set cursor to absolute position pos */
  void setCursorPositionFromStart(unsigned int pos);

  int indexOfCurrentLineStart( int paragraph, int index );

signals:
  void spellcheck_done(int result);
  void attachPNGImageData(const TQByteArray &image);
  void pasteImage();
  void focusUp();
  void focusChanged( bool );
  void selectionAvailable( bool );
  void insertSnippet();
public slots:
  void initializeAutoSpellChecking();
  void slotSpellcheck2(KSpell*);
  void slotSpellResult(const TQString&);
  void slotSpellDone();
  void slotExternalEditorDone(TDEProcess*);
  void slotMisspelling(const TQString &, const TQStringList &, unsigned int);
  void slotCorrected (const TQString &, const TQString &, unsigned int);
  void addSuggestion(const TQString& text, const TQStringList& lst, unsigned int );
  void cut();
  void clear();
  void del();
  void paste();
protected:
  /**
   * Event filter that does Tab-key handling.
   */
  bool eventFilter(TQObject*, TQEvent*);
  void keyPressEvent( TQKeyEvent* );

  void contentsMouseReleaseEvent( TQMouseEvent * e );

  /// Reimplemented to select words under the cursor on double-clicks in our way,
  /// not the broken TQt way (https://issues.kolab.org/issue4089)
  virtual void contentsMouseDoubleClickEvent( TQMouseEvent *e );

private slots:
  void slotExternalEditorTempFileChanged( const TQString & fileName );
  void slotSelectionChanged() {
    // use !text.isEmpty() here, as null-selections exist, but make no sense
    emit selectionAvailable( !selectedText().isEmpty() );
  }

  /// Called when mSpeller is ready to rumble. Does nothing, but KSpell requires a slot as otherwise
  /// it will show a dialog itself, which we want to avoid.
  void spellerReady( KSpell *speller );

  /// Called when mSpeller died for some reason.
  void spellerDied();

  /// Re-creates the spellers, called when the dictionary is changed
  void createSpellers();

private:
  void killExternalEditor();

private:
  KMComposeWin* mComposer;

  // This is the speller used for the spellcheck dialog. It is only active as long as the spellcheck
  // dialog is shown
  KSpell *mKSpellForDialog;

  // This is the speller used when right-clicking a word and choosing "add to dictionary". It lives
  // as long as the composer lives.
  KMSpell *mSpeller;

  KSpellConfig *mSpellConfig;
  TQMap<TQString,TQStringList> mReplacements;
  SpellingFilter* mSpellingFilter;
  KTempFile *mExtEditorTempFile;
  KDirWatch *mExtEditorTempFileWatcher;
  TDEProcess  *mExtEditorProcess;
  bool      mUseExtEditor;
  TQString   mExtEditor;
  bool      mWasModifiedBeforeSpellCheck;
  KMSyntaxHighter *mHighlighter;
  bool mSpellLineEdit;
  TQClipboard::Mode mPasteMode;
};

#endif // __KMAIL_KMEDIT_H__

