/* This file is part of the KDE project
   Copyright (C) 1998, 1999 Reginald Stadlbauer <reggie@kde.org>
   Copyright (C) 2001, S.R.Haque <srhaque@iee.org>
   Copyright (C) 2001, David Faure <faure@kde.org>

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

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LIB.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
*/

#ifndef kosearchdia_h
#define kosearchdia_h

#include <kfind.h>
#include <kfinddialog.h>
#include <kreplace.h>
#include <kreplacedialog.h>
#include "KoTextIterator.h"
#include "KoTextFormat.h"

#include <tqcolor.h>
#include <tqstring.h>
#include <tqstringlist.h>
#include <koffice_export.h>

class TQPushButton;
class TQRadioButton;
class TQGridLayout;
class TQCheckBox;
class TQComboBox;
class TQSpinBox;
class KColorButton;
class KMacroCommand;
class KoTextView;
class KoTextObject;
class KCommand;
class KoTextDocument;
class KoFindReplace;
class TDEFontCombo;
class KoTextCursor;
//
// This class represents the KWord-specific search extension items, and also the
// corresponding replace items.
//
class KOTEXT_EXPORT KoSearchContext
{
public:

    // Options.

    typedef enum
    {
        Family = 1 * KFindDialog::MinimumUserOption,
        Color = 2 * KFindDialog::MinimumUserOption,
        Size = 4 * KFindDialog::MinimumUserOption,
        Bold = 8 * KFindDialog::MinimumUserOption,
        Italic = 16 * KFindDialog::MinimumUserOption,
        Underline = 32 * KFindDialog::MinimumUserOption,
        VertAlign = 64 * KFindDialog::MinimumUserOption,
        StrikeOut = 128 * KFindDialog::MinimumUserOption,
        BgColor = 256 * KFindDialog::MinimumUserOption,
        Shadow = 512 * KFindDialog::MinimumUserOption,
        WordByWord = 1024 * KFindDialog::MinimumUserOption,
        Attribute = 2048 * KFindDialog::MinimumUserOption,
        Language = 4096 * KFindDialog::MinimumUserOption
    } Options;

    KoSearchContext();
    ~KoSearchContext();

    TQString m_family;
    TQColor m_color;
    TQColor m_backGroundColor;
    int m_size;
    KoTextFormat::VerticalAlignment m_vertAlign;
    KoTextFormat::UnderlineType m_underline;
    KoTextFormat::StrikeOutType m_strikeOut;
    KoTextFormat::AttributeStyle m_attribute;

    TQStringList m_strings; // history
    long m_optionsMask;
    long m_options;
    TQString m_language;
};

//
// This class represents the GUI elements that correspond to KWSearchContext.
//
class KoSearchContextUI : public TQObject
{
    Q_OBJECT
  
public:
    KoSearchContextUI( KoSearchContext *ctx, TQWidget *parent );
    void setCtxOptions( long options );
    void setCtxHistory( const TQStringList & history );
    KoSearchContext *context() const { return m_ctx;}
    bool optionSelected() const { return m_bOptionsShown;}
private slots:
    void slotShowOptions();

private:
    KoSearchContext *m_ctx;
    TQGridLayout *m_grid;
    bool m_bOptionsShown;
    TQPushButton *m_btnShowOptions;
    TQWidget *m_parent;
};

//
// This class is the KWord search dialog.
//
class KOTEXT_EXPORT KoSearchDia:
    public KFindDialog
{
    Q_OBJECT
  

public:
    KoSearchDia( TQWidget *parent, const char *name, KoSearchContext *find, bool hasSelection, bool hasCursor );
    KoSearchContext * searchContext() {
        return m_findUI->context();
    }
    bool optionSelected() const { return m_findUI->optionSelected();}

protected slots:
    void slotOk();

private:
    KoSearchContextUI *m_findUI;
};

//
// This class is the kotext replace dialog.
//
class KOTEXT_EXPORT KoReplaceDia:
    public KReplaceDialog
{
    Q_OBJECT
  

public:

    KoReplaceDia( TQWidget *parent, const char *name, KoSearchContext *find, KoSearchContext *replace, bool hasSelection, bool hasCursor );
    KoSearchContext * searchContext() {
        return m_findUI->context();
    }
    KoSearchContext * replaceContext() {
        return m_replaceUI->context();
    }
    bool optionFindSelected() const { return m_findUI->optionSelected();}
    bool optionReplaceSelected() const { return m_replaceUI->optionSelected();}
protected slots:
    void slotOk();

private:

    KoSearchContextUI *m_findUI;
    KoSearchContextUI *m_replaceUI;
};

/**
 * Reimplement KFind to provide our own validateMatch - for the formatting options
 */
class KoTextFind : public KFind
{
    Q_OBJECT
  
public:
    KoTextFind(const TQString &pattern, long options, KoFindReplace *_findReplace, TQWidget *parent = 0);
    ~KoTextFind();
    virtual bool validateMatch( const TQString &text, int index, int matchedlength );
private:
    KoFindReplace * m_findReplace;
};

/**
 * Reimplement KoReplace to provide our own validateMatch - for the formatting options
 */
class KoTextReplace : public KReplace
{
    Q_OBJECT
  
public:
    KoTextReplace(const TQString &pattern, const TQString &replacement, long options, KoFindReplace *_findReplace, TQWidget *parent = 0);
    ~KoTextReplace();
    virtual bool validateMatch( const TQString &text, int index, int matchedlength );
private:
    KoFindReplace * m_findReplace;
};

/**
 * This class implements the 'find' functionality ( the "search next, prompt" loop )
 * and the 'replace' functionality. Same class, to allow centralizing the findNext() code.
 */
class KOTEXT_EXPORT KoFindReplace : public TQObject
{
    Q_OBJECT
  
public:
    KoFindReplace( TQWidget * parent, KoSearchDia * dialog, const TQValueList<KoTextObject *> & lstObject, KoTextView* textView );
    KoFindReplace( TQWidget * parent, KoReplaceDia * dialog, const TQValueList<KoTextObject *> & lstObject, KoTextView* textView );
    ~KoFindReplace();

    KoTextParag *currentParag() {
        return m_textIterator.currentParag();
    }

    bool isReplace() const { return m_replace != 0L; }

    bool shouldRestart();

    //int numMatches() const;
    //int numReplacements() const;

    /** Look for the next match. Returns false if we're finished. */
    bool findNext();

    /** Look for the previous match. Returns false if we're finished. */
    bool findPrevious();

    /** Bring to front (e.g. when menuitem called twice) */
    void setActiveWindow();

    /** Emit undo/redo command for the last replacements made. */
    void emitUndoRedo();

    virtual void emitNewCommand(KCommand *) = 0;

    /**
     * Highlight a match.
     */
    virtual void highlightPortion(KoTextParag * parag, int index, int length, KoTextDocument *textdoc, KDialogBase* dialog) = 0;

    /** For KoTextFind and KoTextReplace */
    bool validateMatch( const TQString &text, int index, int matchedlength );

protected:
    void replaceWithAttribut( KoTextCursor * cursor, int index );
    KMacroCommand* macroCommand();
    long options() const;
    void setOptions(long opt);
    void removeHighlight();
    bool needData() const { return m_find ? m_find->needData() : m_replace->needData(); }
    void setData( const TQString& data, int startPos = -1 ) {
        if ( m_find ) m_find->setData( data, startPos );
        else m_replace->setData( data, startPos );
    }

protected slots:
    void slotFindNext();
    void optionsChanged();
    void dialogClosed();
    void highlight( const TQString &text, int matchingIndex, int matchingLength );
    void replace( const TQString &text, int replacementIndex, int replacedLength, int searchLength );
    void slotCurrentParagraphModified( int, int, int );

private:
    void connectFind( KFind* find );

    // Only one of those two will be set
    KoTextFind * m_find;
    KoTextReplace * m_replace;

    KoSearchContext m_searchContext;
    KoSearchContext m_replaceContext;
    bool m_searchContextEnabled;
    bool m_doCounting;
    bool m_bInit;
    bool m_currentParagraphModified;

    KMacroCommand *m_macroCmd;
    int m_offset;
    int m_matchingIndex; // can be removed once we use kde-3.2 (for kfind::index())

    KoTextIterator m_textIterator;

    // For removing the last highlight
    KoTextObject* m_lastTextObjectHighlighted;
};

/**
 * The separate dialog that pops up to ask for which formatting options
 * should be used to match text, or when replacing text.
 */
class KoFormatDia: public KDialogBase
{
    Q_OBJECT
  
public:
    KoFormatDia( TQWidget* parent, const TQString & _caption, KoSearchContext *_ctx, const char* name=0L);
    //apply to parameter to context !
    void ctxOptions( );

protected slots:
    void slotReset();
    void slotClear();
private:
    TQCheckBox *m_checkFamily;
    TQCheckBox *m_checkSize;
    TQCheckBox *m_checkColor;
    TQCheckBox *m_checkBgColor;
    TQCheckBox *m_checkBold;
    TQCheckBox *m_checkItalic;
    TQCheckBox *m_checkShadow;
    TQCheckBox *m_checkWordByWord;
    TQCheckBox *m_checkUnderline;
    TQCheckBox *m_checkVertAlign;
    TQCheckBox *m_checkStrikeOut;
    TQCheckBox *m_checkFontAttribute;
    TQCheckBox *m_checkLanguage;

    TDEFontCombo *m_familyItem;
    TQSpinBox *m_sizeItem;
    KColorButton *m_colorItem;
    KColorButton *m_bgColorItem;
    TQRadioButton *m_boldYes;
    TQRadioButton *m_boldNo;
    TQRadioButton *m_italicYes;
    TQRadioButton *m_italicNo;
    TQRadioButton *m_shadowYes;
    TQRadioButton *m_shadowNo;
    TQRadioButton *m_wordByWordYes;
    TQRadioButton *m_wordByWordNo;

    TQComboBox *m_vertAlignItem;
    TQComboBox *m_underlineItem;
    TQComboBox *m_strikeOutItem;
    TQComboBox *m_fontAttributeItem;
    TQComboBox *m_languageItem;
    KoSearchContext *m_ctx;
};

#endif
