/**************************************************************
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 *
 *************************************************************/



// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sc.hxx"

// System - Includes ---------------------------------------------------------



// INCLUDE -------------------------------------------------------------------
#include <rangelst.hxx>
#include <sfx2/dispatch.hxx>
#include <vcl/waitobj.hxx>

#include "uiitems.hxx"
#include "dbcolect.hxx"
#include "reffact.hxx"
#include "viewdata.hxx"
#include "document.hxx"
#include "docsh.hxx"
#include "scresid.hxx"

#include "foptmgr.hxx"

#include "globstr.hrc"
#include "filter.hrc"

#define _FILTDLG_CXX
#include "filtdlg.hxx"
#undef _FILTDLG_CXX
#include <vcl/msgbox.hxx>

// DEFINE --------------------------------------------------------------------

#define ERRORBOX(rid)   ErrorBox( this, WinBits( WB_OK|WB_DEF_OK), \
                                   ScGlobal::GetRscString(rid) ).Execute()


//============================================================================
//  class ScFilterDlg

//----------------------------------------------------------------------------

ScFilterDlg::ScFilterDlg( SfxBindings* pB, SfxChildWindow* pCW, Window* pParent,
                          const SfxItemSet& rArgSet )

    :   ScAnyRefDlg ( pB, pCW, pParent, RID_SCDLG_FILTER ),
        //
        aFlCriteria     ( this, ScResId( FL_CRITERIA ) ),
        aLbConnect1     ( this, ScResId( LB_OP1 ) ),
        aLbField1       ( this, ScResId( LB_FIELD1 ) ),
        aLbCond1        ( this, ScResId( LB_COND1 ) ),
        aEdVal1         ( this, ScResId( ED_VAL1 ) ),
        aLbConnect2     ( this, ScResId( LB_OP2 ) ),
        aLbField2       ( this, ScResId( LB_FIELD2 ) ),
        aLbCond2        ( this, ScResId( LB_COND2 ) ),
        aEdVal2         ( this, ScResId( ED_VAL2 ) ),
        aLbConnect3     ( this, ScResId( LB_OP3 ) ),
        aLbField3       ( this, ScResId( LB_FIELD3 ) ),
        aLbCond3        ( this, ScResId( LB_COND3 ) ),
        aEdVal3         ( this, ScResId( ED_VAL3 ) ),
        aLbConnect4     ( this, ScResId( LB_OP4 ) ),
        aLbField4       ( this, ScResId( LB_FIELD4 ) ),
        aLbCond4        ( this, ScResId( LB_COND4 ) ),
        aEdVal4         ( this, ScResId( ED_VAL4 ) ),
        aFtConnect      ( this, ScResId( FT_OP ) ),
        aFtField        ( this, ScResId( FT_FIELD ) ),
        aFtCond         ( this, ScResId( FT_COND ) ),
        aFtVal          ( this, ScResId( FT_VAL ) ),
        aFlSeparator    ( this, ScResId( FL_SEPARATOR ) ),
        aScrollBar      ( this, ScResId( LB_SCROLL ) ),
        aFlOptions      ( this, ScResId( FL_OPTIONS ) ),
        aBtnMore        ( this, ScResId( BTN_MORE ) ),
        aBtnHelp        ( this, ScResId( BTN_HELP ) ),
        aBtnOk          ( this, ScResId( BTN_OK ) ),
        aBtnCancel      ( this, ScResId( BTN_CANCEL ) ),
        _INIT_COMMON_FILTER_RSCOBJS
        aStrEmpty       ( ScResId( SCSTR_EMPTY ) ),
        aStrNotEmpty    ( ScResId( SCSTR_NOTEMPTY ) ),
        aStrRow         ( ScResId( SCSTR_ROW ) ),
        aStrColumn      ( ScResId( SCSTR_COLUMN ) ),
        //
        pOptionsMgr     ( NULL ),
        nWhichQuery     ( rArgSet.GetPool()->GetWhich( SID_QUERY ) ),
        theQueryData    ( ((const ScQueryItem&)
                           rArgSet.Get( nWhichQuery )).GetQueryData() ),
        pOutItem        ( NULL ),
        pViewData       ( NULL ),
        pDoc            ( NULL ),
        nSrcTab         ( 0 ),
        nFieldCount     ( 0 ),
        bRefInputMode   ( sal_False ),
        pTimer          ( NULL )
{
    for (sal_uInt16 i=0; i<=MAXCOL; i++)
        pEntryLists[i] = NULL;
    for (SCSIZE i=0;i<MAXQUERY;i++)
    {
         bRefreshExceptQuery[i]=sal_False;
    }
    aBtnMore.SetMoreText( String(ScResId( SCSTR_MOREBTN_MOREOPTIONS )) );
    aBtnMore.SetLessText( String(ScResId( SCSTR_MOREBTN_FEWEROPTIONS )) );
    Init( rArgSet );
    FreeResource();

    // Hack: RefInput-Kontrolle
    pTimer = new Timer;
    pTimer->SetTimeout( 50 ); // 50ms warten
    pTimer->SetTimeoutHdl( LINK( this, ScFilterDlg, TimeOutHdl ) );

    String sAccName (ScResId(RID_FILTER_OPERATOR));
    String sIndexName(sAccName);
    sIndexName.AppendAscii (RTL_CONSTASCII_STRINGPARAM (" 1"));
    aLbConnect1.SetAccessibleName(sIndexName);
    sIndexName = sAccName;
    sIndexName.AppendAscii (RTL_CONSTASCII_STRINGPARAM (" 2"));
    aLbConnect2.SetAccessibleName(sIndexName);

    sAccName = String(ScResId(RID_FILTER_FIELDNAME));
    sIndexName = sAccName;
    sIndexName.AppendAscii (RTL_CONSTASCII_STRINGPARAM (" 1"));
    aLbField1.SetAccessibleName(sIndexName);
    sIndexName = sAccName;
    sIndexName.AppendAscii (RTL_CONSTASCII_STRINGPARAM (" 2"));
    aLbField2.SetAccessibleName(sIndexName);
    sIndexName = sAccName;
    sIndexName.AppendAscii (RTL_CONSTASCII_STRINGPARAM (" 3"));
    aLbField3.SetAccessibleName(sIndexName);


    sAccName = String(ScResId(RID_FILTER_CONDITION));
    sIndexName = sAccName;
    sIndexName.AppendAscii (RTL_CONSTASCII_STRINGPARAM (" 1"));
    aLbCond1.SetAccessibleName(sIndexName);
    sIndexName = sAccName;
    sIndexName.AppendAscii (RTL_CONSTASCII_STRINGPARAM (" 2"));
    aLbCond2.SetAccessibleName(sIndexName);
    sIndexName = sAccName;
    sIndexName.AppendAscii (RTL_CONSTASCII_STRINGPARAM (" 3"));
    aLbCond3.SetAccessibleName(sIndexName);

    sAccName = String(ScResId(RID_FILTER_VALUE));
    sIndexName = sAccName;
    sIndexName.AppendAscii (RTL_CONSTASCII_STRINGPARAM (" 1"));
    aEdVal1.SetAccessibleName(sIndexName);
    sIndexName = sAccName;
    sIndexName.AppendAscii (RTL_CONSTASCII_STRINGPARAM (" 2"));
    aEdVal2.SetAccessibleName(sIndexName);
    sIndexName = sAccName;
    sIndexName.AppendAscii (RTL_CONSTASCII_STRINGPARAM (" 3"));
    aEdVal3.SetAccessibleName(sIndexName);

    aLbCopyArea.SetAccessibleName(ScResId(STR_COPY_AREA_TO));
    aEdCopyArea.SetAccessibleName(ScResId(STR_COPY_AREA_TO));
    aLbCopyArea.SetAccessibleRelationLabeledBy(&aBtnCopyResult);
    aEdCopyArea.SetAccessibleRelationLabeledBy(&aBtnCopyResult);

    aLbConnect1.SetAccessibleRelationLabeledBy(&aFtConnect);
    aLbConnect2.SetAccessibleRelationLabeledBy(&aFtConnect);
    aLbField1.SetAccessibleRelationLabeledBy(&aFtField);
    aLbField2.SetAccessibleRelationLabeledBy(&aFtField);
    aLbField3.SetAccessibleRelationLabeledBy(&aFtField);
    aLbCond1.SetAccessibleRelationLabeledBy(&aFtCond);
    aLbCond2.SetAccessibleRelationLabeledBy(&aFtCond);
    aLbCond3.SetAccessibleRelationLabeledBy(&aFtCond);
    aEdVal1.SetAccessibleRelationLabeledBy(&aFtVal);
    aEdVal2.SetAccessibleRelationLabeledBy(&aFtVal);
    aEdVal3.SetAccessibleRelationLabeledBy(&aFtVal);
}


//----------------------------------------------------------------------------

__EXPORT ScFilterDlg::~ScFilterDlg()
{
    for (sal_uInt16 i=0; i<=MAXCOL; i++)
        delete pEntryLists[i];

    delete pOptionsMgr;
    delete pOutItem;

    // Hack: RefInput-Kontrolle
    pTimer->Stop();
    delete pTimer;
}


//----------------------------------------------------------------------------

void __EXPORT ScFilterDlg::Init( const SfxItemSet& rArgSet )
{
    const ScQueryItem& rQueryItem = (const ScQueryItem&)
                                    rArgSet.Get( nWhichQuery );

    aBtnOk.SetClickHdl      ( LINK( this, ScFilterDlg, EndDlgHdl ) );
    aBtnCancel.SetClickHdl  ( LINK( this, ScFilterDlg, EndDlgHdl ) );
    aBtnMore.SetClickHdl    ( LINK( this, ScFilterDlg, MoreClickHdl ) );
    aBtnHeader.SetClickHdl  ( LINK( this, ScFilterDlg, CheckBoxHdl ) );
    aBtnCase.SetClickHdl    ( LINK( this, ScFilterDlg, CheckBoxHdl ) );
    //
    aLbField1.SetSelectHdl  ( LINK( this, ScFilterDlg, LbSelectHdl ) );
    aLbField2.SetSelectHdl  ( LINK( this, ScFilterDlg, LbSelectHdl ) );
    aLbField3.SetSelectHdl  ( LINK( this, ScFilterDlg, LbSelectHdl ) );
    aLbField4.SetSelectHdl  ( LINK( this, ScFilterDlg, LbSelectHdl ) );
    aLbConnect1.SetSelectHdl( LINK( this, ScFilterDlg, LbSelectHdl ) );
    aLbConnect2.SetSelectHdl( LINK( this, ScFilterDlg, LbSelectHdl ) );
    aLbConnect3.SetSelectHdl( LINK( this, ScFilterDlg, LbSelectHdl ) );
    aLbConnect4.SetSelectHdl( LINK( this, ScFilterDlg, LbSelectHdl ) );

    aLbCond1.SetSelectHdl( LINK( this, ScFilterDlg, LbSelectHdl ) );
    aLbCond2.SetSelectHdl( LINK( this, ScFilterDlg, LbSelectHdl ) );
    aLbCond3.SetSelectHdl( LINK( this, ScFilterDlg, LbSelectHdl ) );
    aLbCond4.SetSelectHdl( LINK( this, ScFilterDlg, LbSelectHdl ) );

    pViewData   = rQueryItem.GetViewData();
    pDoc        = pViewData ? pViewData->GetDocument() : NULL;
    nSrcTab     = pViewData ? pViewData->GetTabNo() : static_cast<SCTAB>(0);

    // fuer leichteren Zugriff:
    aFieldLbArr  [0] = &aLbField1;
    aFieldLbArr  [1] = &aLbField2;
    aFieldLbArr  [2] = &aLbField3;
    aFieldLbArr  [3] = &aLbField4;
    aValueEdArr  [0] = &aEdVal1;
    aValueEdArr  [1] = &aEdVal2;
    aValueEdArr  [2] = &aEdVal3;
    aValueEdArr  [3] = &aEdVal4;
    aCondLbArr   [0] = &aLbCond1;
    aCondLbArr   [1] = &aLbCond2;
    aCondLbArr   [2] = &aLbCond3;
    aCondLbArr   [3] = &aLbCond4;
    aConnLbArr   [0] = &aLbConnect1;
    aConnLbArr   [1] = &aLbConnect2;
    aConnLbArr   [2] = &aLbConnect3;
    aConnLbArr   [3] = &aLbConnect4;

    // Optionen initialisieren lassen:

    pOptionsMgr  = new ScFilterOptionsMgr(
                            this,
                            pViewData,
                            theQueryData,
                            aBtnMore,
                            aBtnCase,
                            aBtnRegExp,
                            aBtnHeader,
                            aBtnUnique,
                            aBtnCopyResult,
                            aBtnDestPers,
                            aLbCopyArea,
                            aEdCopyArea,
                            aRbCopyArea,
                            aFtDbAreaLabel,
                            aFtDbArea,
                            aFlOptions,
                            aStrNoName,
                            aStrUndefined );

    // Feldlisten einlesen und Eintraege selektieren:

    FillFieldLists();

    for ( SCSIZE i=0; i<4; i++ )
    {
        String  aValStr;
        sal_uInt16  nCondPos     = 0;
        sal_uInt16  nFieldSelPos = 0;

        ScQueryEntry& rEntry = theQueryData.GetEntry(i);
        if ( rEntry.bDoQuery )
        {
            nCondPos     = (sal_uInt16)rEntry.eOp;
            nFieldSelPos = GetFieldSelPos( static_cast<SCCOL>(rEntry.nField) );
            if ( rEntry.nVal == SC_EMPTYFIELDS && !rEntry.bQueryByString && *rEntry.pStr == EMPTY_STRING )
            {
                aValStr = aStrEmpty;
                aCondLbArr[i]->Disable();
            }
            else if ( rEntry.nVal == SC_NONEMPTYFIELDS && !rEntry.bQueryByString && *rEntry.pStr == EMPTY_STRING )
            {
                aValStr = aStrNotEmpty;
                aCondLbArr[i]->Disable();
            }
            else
                aValStr = *rEntry.pStr;
        }
        else if ( i == 0 )
        {
            nFieldSelPos = GetFieldSelPos( pViewData->GetCurX() );
            rEntry.nField = nFieldSelPos ? (theQueryData.nCol1 +
                static_cast<SCCOL>(nFieldSelPos) - 1) : static_cast<SCCOL>(0);
            rEntry.bDoQuery=sal_True;
            bRefreshExceptQuery[i]=sal_True;

        }
        aFieldLbArr[i]->SelectEntryPos( nFieldSelPos );
        aCondLbArr [i]->SelectEntryPos( nCondPos );
        aValueEdArr[i]->SetText( aValStr );
        aValueEdArr[i]->SetModifyHdl( LINK( this, ScFilterDlg, ValModifyHdl ) );
        UpdateValueList( static_cast<sal_uInt16>(i+1) );
    }

    aScrollBar.SetEndScrollHdl( LINK( this, ScFilterDlg, ScrollHdl ) );
    aScrollBar.SetScrollHdl( LINK( this, ScFilterDlg, ScrollHdl ) );

    aScrollBar.SetRange( Range( 0, 4 ) );
    aScrollBar.SetLineSize( 1 );
    aLbConnect1.Hide();
    // Disable/Enable Logik:

       (aLbField1.GetSelectEntryPos() != 0)
    && (aLbField2.GetSelectEntryPos() != 0)
        ? aLbConnect2.SelectEntryPos( (sal_uInt16)theQueryData.GetEntry(1).eConnect )
        : aLbConnect2.SetNoSelection();

       (aLbField2.GetSelectEntryPos() != 0)
    && (aLbField3.GetSelectEntryPos() != 0)
        ? aLbConnect3.SelectEntryPos( (sal_uInt16)theQueryData.GetEntry(2).eConnect )
        : aLbConnect3.SetNoSelection();

       (aLbField3.GetSelectEntryPos() != 0)
    && (aLbField4.GetSelectEntryPos() != 0)
        ? aLbConnect4.SelectEntryPos( (sal_uInt16)theQueryData.GetEntry(3).eConnect )
        : aLbConnect4.SetNoSelection();
    if ( aLbField1.GetSelectEntryPos() == 0 )
    {
        aLbConnect2.Disable();
        aLbField2.Disable();
        aLbCond2.Disable();
        aEdVal2.Disable();
    }
    else if ( aLbConnect2.GetSelectEntryCount() == 0 )
    {
        aLbField2.Disable();
        aLbCond2.Disable();
        aEdVal2.Disable();
    }

    if ( aLbField2.GetSelectEntryPos() == 0 )
    {
        aLbConnect3.Disable();
        aLbField3.Disable();
        aLbCond3.Disable();
        aEdVal3.Disable();
    }
    else if ( aLbConnect3.GetSelectEntryCount() == 0 )
    {
        aLbField3.Disable();
        aLbCond3.Disable();
        aEdVal3.Disable();
    }
    if ( aLbField3.GetSelectEntryPos() == 0 )
    {
        aLbConnect4.Disable();
        aLbField4.Disable();
        aLbCond4.Disable();
        aEdVal4.Disable();
    }
    else if ( aLbConnect4.GetSelectEntryCount() == 0 )
    {
        aLbField4.Disable();
        aLbCond4.Disable();
        aEdVal4.Disable();
    }

    if(pDoc!=NULL &&
        pDoc->GetChangeTrack()!=NULL) aBtnCopyResult.Disable();
    // Modal-Modus einschalten
//  SetDispatcherLock( sal_True );
    //@BugID 54702 Enablen/Disablen nur noch in Basisklasse
//  SFX_APPWINDOW->Disable(sal_False);      //! allgemeine Methode im ScAnyRefDlg
}


//----------------------------------------------------------------------------

sal_Bool __EXPORT ScFilterDlg::Close()
{
    if (pViewData)
        pViewData->GetDocShell()->CancelAutoDBRange();

    return DoClose( ScFilterDlgWrapper::GetChildWindowId() );
}


//----------------------------------------------------------------------------
// Uebergabe eines mit der Maus selektierten Tabellenbereiches, der dann als
// neue Selektion im Referenz-Edit angezeigt wird.

void ScFilterDlg::SetReference( const ScRange& rRef, ScDocument* pDocP )
{
    if ( bRefInputMode )    // Nur moeglich, wenn im Referenz-Editmodus
    {
        if ( rRef.aStart != rRef.aEnd )
            RefInputStart( &aEdCopyArea );
        String aRefStr;
        rRef.aStart.Format( aRefStr, SCA_ABS_3D, pDocP, pDocP->GetAddressConvention() );
        aEdCopyArea.SetRefString( aRefStr );
    }
}


//----------------------------------------------------------------------------

void ScFilterDlg::SetActive()
{
    if ( bRefInputMode )
    {
        aEdCopyArea.GrabFocus();
        if ( aEdCopyArea.GetModifyHdl().IsSet() )
            ((Link&)aEdCopyArea.GetModifyHdl()).Call( &aEdCopyArea );
    }
    else
        GrabFocus();

    RefInputDone();
}

//----------------------------------------------------------------------------

void ScFilterDlg::FillFieldLists()
{
    aLbField1.Clear();
    aLbField2.Clear();
    aLbField3.Clear();
    aLbField4.Clear();
    aLbField1.InsertEntry( aStrNone, 0 );
    aLbField2.InsertEntry( aStrNone, 0 );
    aLbField3.InsertEntry( aStrNone, 0 );
    aLbField4.InsertEntry( aStrNone, 0 );

    if ( pDoc )
    {
        String  aFieldName;
        SCTAB   nTab        = nSrcTab;
        SCCOL   nFirstCol   = theQueryData.nCol1;
        SCROW   nFirstRow   = theQueryData.nRow1;
        SCCOL   nMaxCol     = theQueryData.nCol2;
        SCCOL   col = 0;
        sal_uInt16  i=1;

        for ( col=nFirstCol; col<=nMaxCol; col++ )
        {
            pDoc->GetString( col, nFirstRow, nTab, aFieldName );
            if ( !aBtnHeader.IsChecked() || (aFieldName.Len() == 0) )
            {
                aFieldName  = aStrColumn;
                aFieldName += ' ';
                aFieldName += ScColToAlpha( col );
            }
            aLbField1.InsertEntry( aFieldName, i );
            aLbField2.InsertEntry( aFieldName, i );
            aLbField3.InsertEntry( aFieldName, i );
            aLbField4.InsertEntry( aFieldName, i );
            i++;
        }
        nFieldCount = i;
    }
}


//----------------------------------------------------------------------------

void ScFilterDlg::UpdateValueList( sal_uInt16 nList )
{
    if ( pDoc && nList>0 && nList<=4 )
    {
        ComboBox*   pValList        = aValueEdArr[nList-1];
        sal_uInt16      nFieldSelPos    = aFieldLbArr[nList-1]->GetSelectEntryPos();
        sal_uInt16      nListPos        = 0;
        String      aCurValue       = pValList->GetText();

        pValList->Clear();
        pValList->InsertEntry( aStrNotEmpty, 0 );
        pValList->InsertEntry( aStrEmpty, 1 );
        nListPos = 2;

        if ( nFieldSelPos )
        {
            WaitObject aWaiter( this );     // auch wenn nur die ListBox gefuellt wird

            SCCOL nColumn = theQueryData.nCol1 + static_cast<SCCOL>(nFieldSelPos) - 1;
            if (!pEntryLists[nColumn])
            {
                sal_uInt16 nOffset = GetSliderPos();
                SCTAB nTab       = nSrcTab;
                SCROW nFirstRow = theQueryData.nRow1;
                SCROW nLastRow   = theQueryData.nRow2;
                mbHasDates[nOffset+nList-1] = false;

                //  erstmal ohne die erste Zeile

                pEntryLists[nColumn] = new TypedScStrCollection( 128, 128 );
                pEntryLists[nColumn]->SetCaseSensitive( aBtnCase.IsChecked() );
                pDoc->GetFilterEntriesArea( nColumn, nFirstRow+1, nLastRow,
                                            nTab, *pEntryLists[nColumn], mbHasDates[nOffset+nList-1] );

                //  Eintrag fuer die erste Zeile
                //! Eintrag (pHdrEntry) ohne Collection erzeugen?

                nHeaderPos[nColumn] = USHRT_MAX;
                TypedScStrCollection aHdrColl( 1, 1 );
                bool bDummy = false;
                pDoc->GetFilterEntriesArea( nColumn, nFirstRow, nFirstRow,
                                            nTab, aHdrColl, bDummy );
                TypedStrData* pHdrEntry = aHdrColl[0];
                if ( pHdrEntry )
                {
                    TypedStrData* pNewEntry = new TypedStrData(*pHdrEntry);
                    if ( pEntryLists[nColumn]->Insert( pNewEntry ) )
                    {
                        nHeaderPos[nColumn] = pEntryLists[nColumn]->IndexOf( pNewEntry );
                        DBG_ASSERT( nHeaderPos[nColumn] != USHRT_MAX,
                                    "Header-Eintrag nicht wiedergefunden" );
                    }
                    else
                        delete pNewEntry;           // war schon drin
                }
            }

            TypedScStrCollection* pColl = pEntryLists[nColumn];
            sal_uInt16 nValueCount = pColl->GetCount();
            if ( nValueCount > 0 )
            {
                for ( sal_uInt16 i=0; i<nValueCount; i++ )
                {
                    pValList->InsertEntry( (*pColl)[i]->GetString(), nListPos );
                    nListPos++;
                }
            }
        }
        pValList->SetText( aCurValue );
    }

    UpdateHdrInValueList( nList );
}

void ScFilterDlg::UpdateHdrInValueList( sal_uInt16 nList )
{
    //! GetText / SetText ??

    if ( pDoc && nList>0 && nList<=4 )
    {
        sal_uInt16 nFieldSelPos = aFieldLbArr[nList-1]->GetSelectEntryPos();
        if ( nFieldSelPos )
        {
            SCCOL nColumn = theQueryData.nCol1 + static_cast<SCCOL>(nFieldSelPos) - 1;
            if ( pEntryLists[nColumn] )
            {
                sal_uInt16 nPos = nHeaderPos[nColumn];
                if ( nPos != USHRT_MAX )
                {
                    ComboBox* pValList = aValueEdArr[nList-1];
                    sal_uInt16 nListPos = nPos + 2;                 // nach "leer" und "nicht leer"

                    TypedStrData* pHdrEntry = (*pEntryLists[nColumn])[nPos];
                    if ( pHdrEntry )
                    {
                        String aHdrStr = pHdrEntry->GetString();
                        sal_Bool bWasThere = ( pValList->GetEntry(nListPos) == aHdrStr );
                        sal_Bool bInclude = !aBtnHeader.IsChecked();

                        if (bInclude)           // Eintrag aufnehmen
                        {
                            if (!bWasThere)
                                pValList->InsertEntry(aHdrStr, nListPos);
                        }
                        else                    // Eintrag weglassen
                        {
                            if (bWasThere)
                                pValList->RemoveEntry(nListPos);
                        }
                    }
                    else
                    {
                        DBG_ERROR("Eintag in Liste nicht gefunden");
                    }
                }
            }
            else
            {
                DBG_ERROR("Spalte noch nicht initialisiert");
            }
        }
    }
}

//----------------------------------------------------------------------------

void ScFilterDlg::ClearValueList( sal_uInt16 nList )
{
    if ( nList>0 && nList<=4 )
    {
        ComboBox* pValList = aValueEdArr[nList-1];
        pValList->Clear();
        pValList->InsertEntry( aStrNotEmpty, 0 );
        pValList->InsertEntry( aStrEmpty, 1 );
        pValList->SetText( EMPTY_STRING );
    }
}


//----------------------------------------------------------------------------

sal_uInt16 ScFilterDlg::GetFieldSelPos( SCCOL nField )
{
    if ( nField >= theQueryData.nCol1 && nField <= theQueryData.nCol2 )
        return static_cast<sal_uInt16>(nField - theQueryData.nCol1 + 1);
    else
        return 0;
}

//----------------------------------------------------------------------------

ScQueryItem* ScFilterDlg::GetOutputItem()
{
    ScAddress       theCopyPos;
    ScQueryParam    theParam( theQueryData );
    sal_Bool            bCopyPosOk = sal_False;

    if ( aBtnCopyResult.IsChecked() )
    {
        String theCopyStr( aEdCopyArea.GetText() );
        xub_StrLen nColonPos = theCopyStr.Search( ':' );

        if ( STRING_NOTFOUND != nColonPos )
            theCopyStr.Erase( nColonPos );

        sal_uInt16 nResult = theCopyPos.Parse( theCopyStr, pDoc, pDoc->GetAddressConvention() );
        bCopyPosOk = ( SCA_VALID == (nResult & SCA_VALID) );
    }

    if ( aBtnCopyResult.IsChecked() && bCopyPosOk )
    {
        theParam.bInplace   = sal_False;
        theParam.nDestTab   = theCopyPos.Tab();
        theParam.nDestCol   = theCopyPos.Col();
        theParam.nDestRow   = theCopyPos.Row();
    }
    else
    {
        theParam.bInplace   = sal_True;
        theParam.nDestTab   = 0;
        theParam.nDestCol   = 0;
        theParam.nDestRow   = 0;
    }

    theParam.bHasHeader     = aBtnHeader.IsChecked();
    theParam.bByRow         = sal_True;
    theParam.bDuplicate     = !aBtnUnique.IsChecked();
    theParam.bCaseSens      = aBtnCase.IsChecked();
    theParam.bRegExp        = aBtnRegExp.IsChecked();
    theParam.bDestPers      = aBtnDestPers.IsChecked();

    //  nur die drei eingestellten - alles andere zuruecksetzen

    DELETEZ( pOutItem );
    pOutItem = new ScQueryItem( nWhichQuery, &theParam );

    return pOutItem;
}


//----------------------------------------------------------------------------

sal_Bool ScFilterDlg::IsRefInputMode() const
{
    return bRefInputMode;
}


//----------------------------------------------------------------------------
// Handler:
// ========

IMPL_LINK( ScFilterDlg, EndDlgHdl, Button*, pBtn )
{
    if ( pBtn == &aBtnOk )
    {
        sal_Bool bAreaInputOk = sal_True;

        if ( aBtnCopyResult.IsChecked() )
        {
            if ( !pOptionsMgr->VerifyPosStr( aEdCopyArea.GetText() ) )
            {
                if ( !aBtnMore.GetState() )
                    aBtnMore.SetState( sal_True );

                ERRORBOX( STR_INVALID_TABREF );
                aEdCopyArea.GrabFocus();
                bAreaInputOk = sal_False;
            }
        }

        if ( bAreaInputOk )
        {
            SetDispatcherLock( sal_False );
            SwitchToDocument();
            GetBindings().GetDispatcher()->Execute( FID_FILTER_OK,
                                      SFX_CALLMODE_SLOT | SFX_CALLMODE_RECORD,
                                      GetOutputItem(), 0L, 0L );
            Close();
        }
    }
    else if ( pBtn == &aBtnCancel )
    {
        Close();
    }

    return 0;
}


//----------------------------------------------------------------------------

IMPL_LINK( ScFilterDlg, MoreClickHdl, MoreButton*, EMPTYARG )
{
    if ( aBtnMore.GetState() )
        pTimer->Start();
    else
    {
        pTimer->Stop();
        bRefInputMode = sal_False;
        //@BugID 54702 Enablen/Disablen nur noch in Basisklasse
        //SFX_APPWINDOW->Disable(sal_False);        //! allgemeine Methode im ScAnyRefDlg
    }
    return 0;
}


//----------------------------------------------------------------------------

IMPL_LINK( ScFilterDlg, TimeOutHdl, Timer*, _pTimer )
{
    // alle 50ms nachschauen, ob RefInputMode noch stimmt

    if( _pTimer == pTimer && IsActive() )
        bRefInputMode = (aEdCopyArea.HasFocus() || aRbCopyArea.HasFocus());

    if ( aBtnMore.GetState() )
        pTimer->Start();

    return 0;
}


//----------------------------------------------------------------------------

IMPL_LINK( ScFilterDlg, LbSelectHdl, ListBox*, pLb )
{
    /*
     * Behandlung der Enable/Disable-Logik,
     * abhaengig davon, welche ListBox angefasst wurde:
     */
    sal_uInt16 nOffset = GetSliderPos();

    if ( pLb == &aLbConnect1 )
    {
        aLbField1.Enable();
        aLbCond1.Enable();
        aEdVal1.Enable();

        sal_uInt16  nConnect1 = aLbConnect1.GetSelectEntryPos();
        sal_uInt16 nQE = nOffset;
        theQueryData.GetEntry(nQE).eConnect =(ScQueryConnect)nConnect1;
        bRefreshExceptQuery[nQE]=sal_True;
    }

    else if ( pLb == &aLbConnect2 )
    {
        aLbField2.Enable();
        aLbCond2.Enable();
        aEdVal2.Enable();

        sal_uInt16  nConnect2 = aLbConnect2.GetSelectEntryPos();
        sal_uInt16 nQE = 1+nOffset;
        theQueryData.GetEntry(nQE).eConnect =(ScQueryConnect)nConnect2;
         bRefreshExceptQuery[nQE]=sal_True;
    }
    else if ( pLb == &aLbConnect3 )
    {
        aLbField3.Enable();
        aLbCond3.Enable();
        aEdVal3.Enable();

        sal_uInt16  nConnect3 = aLbConnect3.GetSelectEntryPos();
        sal_uInt16 nQE = 2+nOffset;
        theQueryData.GetEntry(nQE).eConnect = (ScQueryConnect)nConnect3;
        bRefreshExceptQuery[nQE]=sal_True;

    }
    else if ( pLb == &aLbConnect4 )
    {
        aLbField4.Enable();
        aLbCond4.Enable();
        aEdVal4.Enable();

        sal_uInt16  nConnect4 = aLbConnect4.GetSelectEntryPos();
        sal_uInt16 nQE = 3+nOffset;
        theQueryData.GetEntry(nQE).eConnect = (ScQueryConnect)nConnect4;
        bRefreshExceptQuery[nQE]=sal_True;

    }
    else if ( pLb == &aLbField1 )
    {
        if ( aLbField1.GetSelectEntryPos() == 0 )
        {
            aLbConnect2.SetNoSelection();
            aLbConnect3.SetNoSelection();
            aLbConnect4.SetNoSelection();
            aLbField2.SelectEntryPos( 0 );
            aLbField3.SelectEntryPos( 0 );
            aLbField4.SelectEntryPos( 0 );
            aLbCond2.SelectEntryPos( 0 );
            aLbCond3.SelectEntryPos( 0 );
            aLbCond4.SelectEntryPos( 0 );
            ClearValueList( 1 );
            ClearValueList( 2 );
            ClearValueList( 3 );
            ClearValueList( 4 );

            aLbConnect2.Disable();
            aLbConnect3.Disable();
            aLbConnect4.Disable();
            aLbField2.Disable();
            aLbField3.Disable();
            aLbField4.Disable();
            aLbCond2.Disable();
            aLbCond3.Disable();
            aLbCond4.Disable();
            aEdVal2.Disable();
            aEdVal3.Disable();
            aEdVal4.Disable();
            for (sal_uInt16 i= nOffset; i< MAXQUERY; i++)
            {
                theQueryData.GetEntry(i).bDoQuery = sal_False;
                bRefreshExceptQuery[i]=sal_False;
                theQueryData.GetEntry(i).nField =  static_cast<SCCOL>(0);
            }
            bRefreshExceptQuery[nOffset] =sal_True;
        }
        else
        {
            UpdateValueList( 1 );
            if ( !aLbConnect2.IsEnabled() )
            {
                aLbConnect2.Enable();
            }
            theQueryData.GetEntry(nOffset).bDoQuery = sal_True;
            sal_uInt16  nField  = pLb->GetSelectEntryPos();
            theQueryData.GetEntry(nOffset).nField = theQueryData.nCol1 + static_cast<SCCOL>(nField) - 1 ;
        }
    }
    else if ( pLb == &aLbField2 )
    {
        if ( aLbField2.GetSelectEntryPos() == 0 )
        {
            aLbConnect3.SetNoSelection();
            aLbConnect4.SetNoSelection();
            aLbField3.SelectEntryPos( 0 );
            aLbField4.SelectEntryPos( 0 );
            aLbCond3.SelectEntryPos( 0 );
            aLbCond4.SelectEntryPos( 0 );
            ClearValueList( 2 );
            ClearValueList( 3 );
            ClearValueList( 4 );

            aLbConnect3.Disable();
            aLbConnect4.Disable();
            aLbField3.Disable();
            aLbField4.Disable();
            aLbCond3.Disable();
            aLbCond4.Disable();
            aEdVal3.Disable();
            aEdVal4.Disable();

            sal_uInt16 nTemp=nOffset+1;
            for (sal_uInt16 i= nTemp; i< MAXQUERY; i++)
            {
                theQueryData.GetEntry(i).bDoQuery = sal_False;
                bRefreshExceptQuery[i]=sal_False;
                theQueryData.GetEntry(i).nField =  static_cast<SCCOL>(0);
            }
            bRefreshExceptQuery[nTemp]=sal_True;
        }
        else
        {
            UpdateValueList( 2 );
            if ( !aLbConnect3.IsEnabled() )
            {
                aLbConnect3.Enable();
            }
            sal_uInt16  nField  = pLb->GetSelectEntryPos();
            sal_uInt16 nQ=1+nOffset;
            theQueryData.GetEntry(nQ).bDoQuery = sal_True;
            theQueryData.GetEntry(nQ).nField = theQueryData.nCol1 + static_cast<SCCOL>(nField) - 1 ;
        }
    }
    else if ( pLb == &aLbField3 )
    {
        if ( aLbField3.GetSelectEntryPos() == 0 )
        {
            aLbConnect4.SetNoSelection();
            aLbField4.SelectEntryPos( 0 );
            aLbCond4.SelectEntryPos( 0 );
            ClearValueList( 3 );
            ClearValueList( 4 );

            aLbConnect4.Disable();
            aLbField4.Disable();
            aLbCond4.Disable();
            aEdVal4.Disable();

            sal_uInt16 nTemp=nOffset+2;
            for (sal_uInt16 i= nTemp; i< MAXQUERY; i++)
            {
                theQueryData.GetEntry(i).bDoQuery = sal_False;
                bRefreshExceptQuery[i]=sal_False;
                theQueryData.GetEntry(i).nField =  static_cast<SCCOL>(0);
            }
            bRefreshExceptQuery[nTemp]=sal_True;
        }
        else
        {
            UpdateValueList( 3 );
            if ( !aLbConnect4.IsEnabled() )
            {
                aLbConnect4.Enable();
            }

            sal_uInt16  nField  = pLb->GetSelectEntryPos();
            sal_uInt16 nQ=2+nOffset;
            theQueryData.GetEntry(nQ).bDoQuery = sal_True;
            theQueryData.GetEntry(nQ).nField = theQueryData.nCol1 + static_cast<SCCOL>(nField) - 1 ;

        }
    }
    else if ( pLb == &aLbField4 )
    {
        if ( aLbField4.GetSelectEntryPos() == 0 )
        {
            ClearValueList( 4 );
            sal_uInt16 nTemp=nOffset+3;
            for (sal_uInt16 i= nTemp; i< MAXQUERY; i++)
            {
                theQueryData.GetEntry(i).bDoQuery = sal_False;
                bRefreshExceptQuery[i]=sal_False;
                theQueryData.GetEntry(i).nField =  static_cast<SCCOL>(0);
            }
            bRefreshExceptQuery[nTemp]=sal_True;
        }
        else
        {
            UpdateValueList( 4 );
            sal_uInt16  nField  = pLb->GetSelectEntryPos();
            sal_uInt16 nQ=3+nOffset;
            theQueryData.GetEntry(nQ).bDoQuery = sal_True;
            theQueryData.GetEntry(nQ).nField = theQueryData.nCol1 + static_cast<SCCOL>(nField) - 1 ;
        }

    }
    else if ( pLb == &aLbCond1)
    {
        theQueryData.GetEntry(nOffset).eOp=(ScQueryOp)pLb->GetSelectEntryPos();
    }
    else if ( pLb == &aLbCond2)
    {
        sal_uInt16 nQ=1+nOffset;
        theQueryData.GetEntry(nQ).eOp=(ScQueryOp)pLb->GetSelectEntryPos();
    }
    else if ( pLb == &aLbCond3)
    {
        sal_uInt16 nQ=2+nOffset;
        theQueryData.GetEntry(nQ).eOp=(ScQueryOp)pLb->GetSelectEntryPos();
    }
    else
    {
        sal_uInt16 nQ=3+nOffset;
        theQueryData.GetEntry(nQ).eOp=(ScQueryOp)pLb->GetSelectEntryPos();
    }

    return 0;
}


//----------------------------------------------------------------------------

IMPL_LINK( ScFilterDlg, CheckBoxHdl, CheckBox*, pBox )
{
    //  Spaltenkoepfe:
    //      FeldListen: Spaltexx <-> Spaltenkopf-String
    //      WertListen: Spaltenkopf-Wert entfaellt.
    //  Gross-/Kleinschreibung:
    //      WertListen: komplett neu

    if ( pBox == &aBtnHeader )              // Feldlisten und Wertlisten
    {
        sal_uInt16 nCurSel1 = aLbField1.GetSelectEntryPos();
        sal_uInt16 nCurSel2 = aLbField2.GetSelectEntryPos();
        sal_uInt16 nCurSel3 = aLbField3.GetSelectEntryPos();
        sal_uInt16 nCurSel4 = aLbField4.GetSelectEntryPos();
        FillFieldLists();
        aLbField1.SelectEntryPos( nCurSel1 );
        aLbField2.SelectEntryPos( nCurSel2 );
        aLbField3.SelectEntryPos( nCurSel3 );
        aLbField4.SelectEntryPos( nCurSel4 );

        UpdateHdrInValueList( 1 );
        UpdateHdrInValueList( 2 );
        UpdateHdrInValueList( 3 );
        UpdateHdrInValueList( 4 );
    }

    if ( pBox == &aBtnCase )            // Wertlisten komplett
    {
        for (sal_uInt16 i=0; i<=MAXCOL; i++)
            DELETEZ( pEntryLists[i] );

        UpdateValueList( 1 );       // aktueller Text wird gemerkt
        UpdateValueList( 2 );
        UpdateValueList( 3 );
        UpdateValueList( 4 );
    }

    return 0;
}


//----------------------------------------------------------------------------

IMPL_LINK( ScFilterDlg, ValModifyHdl, ComboBox*, pEd )
{
    sal_uInt16   nOffset = GetSliderPos();
    sal_uInt16   i=0;
    sal_uInt16   nQE =i + nOffset;
    if ( pEd )
    {
        String    aStrVal   = pEd->GetText();
        ListBox*  pLbCond   = &aLbCond1;
        ListBox*  pLbField  = &aLbField1;
        if ( pEd == &aEdVal2 )
        {
            pLbCond  = &aLbCond2;
            pLbField = &aLbField2;
            i=1;
            nQE=i+nOffset;
        }
        if ( pEd == &aEdVal3 )
        {
            pLbCond = &aLbCond3;
            pLbField = &aLbField3;
            i=2;
            nQE=i+nOffset;
        }
        if ( pEd == &aEdVal4 )
        {
            pLbCond = &aLbCond4;
            pLbField = &aLbField4;
            i=3;
            nQE=i+nOffset;
        }

        if ( aStrEmpty == aStrVal || aStrNotEmpty == aStrVal )
        {
            pLbCond->SelectEntry( '=' );
            pLbCond->Disable();
        }
        else
            pLbCond->Enable();

        ScQueryEntry& rEntry = theQueryData.GetEntry( nQE );
        sal_Bool bDoThis = (pLbField->GetSelectEntryPos() != 0);
        rEntry.bDoQuery = bDoThis;

        if ( rEntry.bDoQuery || bRefreshExceptQuery[nQE] )
        {
            if ( aStrVal == aStrEmpty )
            {
                rEntry.pStr->Erase();
                rEntry.nVal = SC_EMPTYFIELDS;
                rEntry.bQueryByString = sal_False;
            }
            else if ( aStrVal == aStrNotEmpty )
            {
                rEntry.pStr->Erase();
                rEntry.nVal = SC_NONEMPTYFIELDS;
                rEntry.bQueryByString = sal_False;
            }
            else
            {
                *rEntry.pStr          = aStrVal;
                rEntry.nVal           = 0;
                rEntry.bQueryByString = sal_True;
            }

            sal_uInt16  nField  = pLbField->GetSelectEntryPos();
            rEntry.nField = nField ? (theQueryData.nCol1 +
                static_cast<SCCOL>(nField) - 1) : static_cast<SCCOL>(0);

            ScQueryOp eOp  = (ScQueryOp)pLbCond->GetSelectEntryPos();
            rEntry.eOp     = eOp;
            rEntry.bQueryByDate = mbHasDates[nQE];

        }
    }
    return 0;
}

//----------------------------------------------------------------------------
IMPL_LINK( ScFilterDlg, ScrollHdl, ScrollBar*, EMPTYARG )
{
    SliderMoved();
    return 0;
}

void ScFilterDlg::SliderMoved()
{
    sal_uInt16 nOffset = GetSliderPos();
    RefreshEditRow( nOffset);
}
sal_uInt16 ScFilterDlg::GetSliderPos()
{
    return (sal_uInt16) aScrollBar.GetThumbPos();
}
void ScFilterDlg::RefreshEditRow( sal_uInt16 nOffset )
{
    if (nOffset==0)
        aConnLbArr[0]->Hide();
    else
        aConnLbArr[0]->Show();

    for ( sal_uInt16 i=0; i<4; i++ )
    {
        String  aValStr;
        sal_uInt16  nCondPos     = 0;
        sal_uInt16  nFieldSelPos = 0;
        sal_uInt16  nQE = i+nOffset;

        ScQueryEntry& rEntry = theQueryData.GetEntry( nQE);
        if ( rEntry.bDoQuery || bRefreshExceptQuery[nQE] )
        {
            nCondPos     = (sal_uInt16)rEntry.eOp;
            if(rEntry.bDoQuery)
               nFieldSelPos = GetFieldSelPos( static_cast<SCCOL>(rEntry.nField) );

            if ( rEntry.nVal == SC_EMPTYFIELDS && !rEntry.bQueryByString && *rEntry.pStr == EMPTY_STRING )
            {
                aValStr = aStrEmpty;
                aCondLbArr[i]->Disable();
            }
            else if ( rEntry.nVal == SC_NONEMPTYFIELDS && !rEntry.bQueryByString && *rEntry.pStr == EMPTY_STRING )
            {
                aValStr = aStrNotEmpty;
                aCondLbArr[i]->Disable();
            }
            else
            {
                aValStr = *rEntry.pStr;
                aCondLbArr[i]->Enable();
            }
            aFieldLbArr[i]->Enable();
            aValueEdArr[i]->Enable();

            if (nOffset==0)
            {
                if (i<3)
                {
                    if(rEntry.bDoQuery)
                        aConnLbArr[i+1]->Enable();
                    else
                        aConnLbArr[i+1]->Disable();
                    sal_uInt16 nQENext = nQE+1;
                    if(theQueryData.GetEntry(nQENext).bDoQuery || bRefreshExceptQuery[nQENext])
                        aConnLbArr[i+1]->SelectEntryPos( (sal_uInt16) theQueryData.GetEntry(nQENext).eConnect );
                    else
                        aConnLbArr[i+1]->SetNoSelection();
                }
            }
            else
            {
                if(theQueryData.GetEntry( nQE-1).bDoQuery)
                    aConnLbArr[i]->Enable();
                else
                    aConnLbArr[i]->Disable();

                if(rEntry.bDoQuery || bRefreshExceptQuery[nQE])
                    aConnLbArr[i]->SelectEntryPos( (sal_uInt16) rEntry.eConnect );
                else
                    aConnLbArr[i]->SetNoSelection();
            }

        }
        else
        {
            if (nOffset==0)
            {
                if(i<3)
                {
                    aConnLbArr[i+1]->SetNoSelection();
                    aConnLbArr[i+1]->Disable();
                }
            }
            else
            {
                if(theQueryData.GetEntry( nQE-1).bDoQuery)
                    aConnLbArr[i]->Enable();
                else
                    aConnLbArr[i]->Disable();
                aConnLbArr[i]->SetNoSelection();
            }
            aFieldLbArr[i]->Disable();
            aCondLbArr[i]->Disable();
            aValueEdArr[i]->Disable();
        }
        aFieldLbArr[i]->SelectEntryPos( nFieldSelPos );
        aCondLbArr [i]->SelectEntryPos( nCondPos );
        aValueEdArr[i]->SetText( aValStr );
        UpdateValueList( static_cast<sal_uInt16>(i+1) );
    }
}