/**************************************************************
 *
 * 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"



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

#include "rangelst.hxx"
#include <sfx2/app.hxx>
#include <sfx2/viewsh.hxx>
#include <vcl/wrkwin.hxx>
#include <vcl/mnemonic.hxx>
#include <tools/shl.hxx>
#include <svtools/taskbar.hxx>
#include <sfx2/bindings.hxx>
#include <sfx2/dispatch.hxx>


#define ANYREFDG_CXX
#include "anyrefdg.hxx"
#undef ANYREFDG_CXX

#include "sc.hrc"
#include "inputhdl.hxx"
#include "scmod.hxx"
#include "scresid.hxx"
#include "inputwin.hxx"
#include "tabvwsh.hxx"
#include "docsh.hxx"
#include "rfindlst.hxx"
#include "compiler.hxx"
#include "cell.hxx"
#include "global.hxx"
#include "inputopt.hxx"
#include "rangeutl.hxx"


ScFormulaReferenceHelper::ScFormulaReferenceHelper(IAnyRefDialog* _pDlg,SfxBindings* _pBindings)
 : m_pDlg(_pDlg)
 , pRefEdit (NULL)
 , m_pWindow(NULL)
 , m_pBindings(_pBindings)
 , pAccel( NULL )
 , pHiddenMarks(NULL)
 , nRefTab(0)
 , bHighLightRef( sal_False )
 , bAccInserted( sal_False )
{
    ScInputOptions aInputOption=SC_MOD()->GetInputOptions();
	bEnableColorRef=aInputOption.GetRangeFinder();
}
// -----------------------------------------------------------------------------
ScFormulaReferenceHelper::~ScFormulaReferenceHelper()
{
    if (bAccInserted)
		Application::RemoveAccel( pAccel.get() );

    // common cleanup for ScAnyRefDlg and ScFormulaDlg is done here

    HideReference();
    enableInput( sal_True );

    ScInputHandler* pInputHdl = SC_MOD()->GetInputHdl();
    if ( pInputHdl )
        pInputHdl->ResetDelayTimer();   // stop the timer for disabling the input line
}
// -----------------------------------------------------------------------------
void ScFormulaReferenceHelper::enableInput( sal_Bool bEnable )
{
    TypeId aType(TYPE(ScDocShell));
    ScDocShell* pDocShell = (ScDocShell*)SfxObjectShell::GetFirst(&aType);
    while( pDocShell )
    {
	    SfxViewFrame* pFrame = SfxViewFrame::GetFirst( pDocShell );
	    while( pFrame )
	    {
		    //	#71577# enable everything except InPlace, including bean frames
            if ( !pFrame->GetFrame().IsInPlace() )
		    {
			    SfxViewShell* p = pFrame->GetViewShell();
			    ScTabViewShell* pViewSh = PTR_CAST(ScTabViewShell,p);
			    if(pViewSh!=NULL)
			    {
				    Window *pWin=pViewSh->GetWindow();
				    if(pWin)
				    {
					    Window *pParent=pWin->GetParent();
					    if(pParent)
					    {
						    pParent->EnableInput(bEnable,sal_True /* sal_False */);
						    if(sal_True /*bChilds*/)
							    pViewSh->EnableRefInput(bEnable);
					    }
				    }
			    }
		    }
		    pFrame = SfxViewFrame::GetNext( *pFrame, pDocShell );
	    }

	    pDocShell = (ScDocShell*)SfxObjectShell::GetNext(*pDocShell, &aType);
    }
}
// -----------------------------------------------------------------------------
void ScFormulaReferenceHelper::ShowSimpleReference( const XubString& rStr )
{
    if( /*!pRefEdit &&*/ bEnableColorRef )
	{
		bHighLightRef=sal_True;
		ScViewData* pViewData=ScDocShell::GetViewData();
		if ( pViewData )
		{
			ScDocument* pDoc=pViewData->GetDocument();
			ScTabViewShell*	pTabViewShell=pViewData->GetViewShell();

			ScRangeList aRangeList;

			pTabViewShell->DoneRefMode( sal_False );
			pTabViewShell->ClearHighlightRanges();

			if( ParseWithNames( aRangeList, rStr, pDoc ) )
			{
				ScRange* pRangeEntry = aRangeList.First();

				sal_uInt16 nIndex=0;
				while(pRangeEntry != NULL)
				{
					ColorData aColName = ScRangeFindList::GetColorName(nIndex++);
					pTabViewShell->AddHighlightRange(*pRangeEntry, aColName);

					pRangeEntry = aRangeList.Next();
				}
			}
		}
	}
}
// -----------------------------------------------------------------------------
bool ScFormulaReferenceHelper::ParseWithNames( ScRangeList& rRanges, const String& rStr, ScDocument* pDoc )
{
    bool bError = false;
    rRanges.RemoveAll();

    ScAddress::Details aDetails(pDoc->GetAddressConvention(), 0, 0);
    ScRangeUtil aRangeUtil;
    xub_StrLen nTokenCnt = rStr.GetTokenCount();
    for( xub_StrLen nToken = 0; nToken < nTokenCnt; ++nToken )
    {
        ScRange aRange;
        String aRangeStr( rStr.GetToken( nToken ) );

        sal_uInt16 nFlags = aRange.ParseAny( aRangeStr, pDoc, aDetails );
        if ( nFlags & SCA_VALID )
        {
            if ( (nFlags & SCA_TAB_3D) == 0 )
                aRange.aStart.SetTab( nRefTab );
            if ( (nFlags & SCA_TAB2_3D) == 0 )
                aRange.aEnd.SetTab( aRange.aStart.Tab() );
            rRanges.Append( aRange );
        }
        else if ( aRangeUtil.MakeRangeFromName( aRangeStr, pDoc, nRefTab, aRange, RUTL_NAMES, aDetails ) )
            rRanges.Append( aRange );
        else
            bError = true;
    }

    return !bError;
}
// -----------------------------------------------------------------------------
void ScFormulaReferenceHelper::ShowFormulaReference( const XubString& rStr )
{
    if( /*!pRefEdit &&*/ bEnableColorRef)
	{
		bHighLightRef=sal_True;
		ScViewData* pViewData=ScDocShell::GetViewData();
		if ( pViewData && pRefComp.get() )
		{
			ScTabViewShell*	pTabViewShell=pViewData->GetViewShell();
			SCCOL nCol = pViewData->GetCurX();
			SCROW nRow = pViewData->GetCurY();
			SCTAB nTab = pViewData->GetTabNo();
			ScAddress aPos( nCol, nRow, nTab );

			ScTokenArray* pScTokA=pRefComp->CompileString(rStr);
			//pRefComp->CompileTokenArray();

			if(pTabViewShell!=NULL && pScTokA!=NULL)
			{
				pTabViewShell->DoneRefMode( sal_False );
				pTabViewShell->ClearHighlightRanges();

				pScTokA->Reset();
				const ScToken* pToken = static_cast<const ScToken*>(pScTokA->GetNextReference());

				sal_uInt16 nIndex=0;

				while(pToken!=NULL)
				{
					sal_Bool bDoubleRef=(pToken->GetType()==formula::svDoubleRef);


					if(pToken->GetType()==formula::svSingleRef || bDoubleRef)
					{
						ScRange aRange;
						if(bDoubleRef)
						{
							ScComplexRefData aRef( pToken->GetDoubleRef() );
							aRef.CalcAbsIfRel( aPos );
							aRange.aStart.Set( aRef.Ref1.nCol, aRef.Ref1.nRow, aRef.Ref1.nTab );
							aRange.aEnd.Set( aRef.Ref2.nCol, aRef.Ref2.nRow, aRef.Ref2.nTab );
						}
						else
						{
							ScSingleRefData aRef( pToken->GetSingleRef() );
							aRef.CalcAbsIfRel( aPos );
							aRange.aStart.Set( aRef.nCol, aRef.nRow, aRef.nTab );
							aRange.aEnd = aRange.aStart;
						}
						ColorData aColName=ScRangeFindList::GetColorName(nIndex++);
						pTabViewShell->AddHighlightRange(aRange, aColName);
					}

					pToken = static_cast<const ScToken*>(pScTokA->GetNextReference());
				}
			}
			if(pScTokA!=NULL) delete pScTokA;
		}
	}
}
// -----------------------------------------------------------------------------
void ScFormulaReferenceHelper::HideReference( sal_Bool bDoneRefMode )
{
	ScViewData* pViewData=ScDocShell::GetViewData();

    if( pViewData && /*!pRefEdit &&*/ bHighLightRef && bEnableColorRef)
	{
		ScTabViewShell*	pTabViewShell=pViewData->GetViewShell();

		if(pTabViewShell!=NULL)
		{
			//	bDoneRefMode is sal_False when called from before SetReference.
			//	In that case, RefMode was just started and must not be ended now.

			if ( bDoneRefMode )
				pTabViewShell->DoneRefMode( sal_False );
			pTabViewShell->ClearHighlightRanges();
		}
		bHighLightRef=sal_False;
	}
}
// -----------------------------------------------------------------------------
void ScFormulaReferenceHelper::ShowReference( const XubString& rStr )
{
    if( /*!pRefEdit &&*/ bEnableColorRef )
	{
		if(	rStr.Search('(')!=STRING_NOTFOUND ||
			rStr.Search('+')!=STRING_NOTFOUND ||
			rStr.Search('*')!=STRING_NOTFOUND ||
			rStr.Search('-')!=STRING_NOTFOUND ||
			rStr.Search('/')!=STRING_NOTFOUND ||
			rStr.Search('&')!=STRING_NOTFOUND ||
			rStr.Search('<')!=STRING_NOTFOUND ||
			rStr.Search('>')!=STRING_NOTFOUND ||
			rStr.Search('=')!=STRING_NOTFOUND ||
			rStr.Search('^')!=STRING_NOTFOUND)
		{
			ShowFormulaReference(rStr);
		}
		else
		{
			ShowSimpleReference(rStr);
		}
	}
}
// -----------------------------------------------------------------------------
void ScFormulaReferenceHelper::ReleaseFocus( formula::RefEdit* pEdit, formula::RefButton* pButton )
{
    if( !pRefEdit && pEdit )
    {
        m_pDlg->RefInputStart( pEdit, pButton );
//        if( pRefEdit )
//            pRefEdit->SilentGrabFocus();
    }

    ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
    if( pViewShell )
    {
        pViewShell->ActiveGrabFocus();
        if( pRefEdit )
        {
            const ScViewData* pViewData = pViewShell->GetViewData();
            ScDocument* pDoc = pViewData->GetDocument();
			ScRangeList aRangeList;
            if( ParseWithNames( aRangeList, pRefEdit->GetText(), pDoc ) )
			{
                const ScRange* pRange = aRangeList.GetObject( 0 );
                if( pRange )
                {
                    pViewShell->SetTabNo( pRange->aStart.Tab() );
                    pViewShell->MoveCursorAbs(  pRange->aStart.Col(),
                        pRange->aStart.Row(), SC_FOLLOW_JUMP, sal_False, sal_False );
                    pViewShell->MoveCursorAbs( pRange->aEnd.Col(),
                        pRange->aEnd.Row(), SC_FOLLOW_JUMP, sal_True, sal_False );
                    m_pDlg->SetReference( *pRange, pDoc );
                }
            }
        }
    }
}
// -----------------------------------------------------------------------------
void ScFormulaReferenceHelper::Init()
{
    ScViewData* pViewData=ScDocShell::GetViewData();    //! use pScViewShell?
	if ( pViewData )
	{
		ScDocument* pDoc = pViewData->GetDocument();
		SCCOL nCol = pViewData->GetCurX();
		SCROW nRow = pViewData->GetCurY();
		SCTAB nTab = pViewData->GetTabNo();
		ScAddress aCursorPos( nCol, nRow, nTab );

		String rStrExp;
		pRefCell.reset( new ScFormulaCell( pDoc, aCursorPos, rStrExp ) );
		pRefComp.reset( new ScCompiler( pDoc, aCursorPos) );
        pRefComp->SetGrammar( pDoc->GetGrammar() );
		pRefComp->SetCompileForFAP(sal_True);

        nRefTab = nTab;
	} // if ( pViewData )
}
// -----------------------------------------------------------------------------
IMPL_LINK( ScFormulaReferenceHelper, AccelSelectHdl, Accelerator *, pSelAccel )
{
    if ( !pSelAccel )
		return 0;

    switch ( pSelAccel->GetCurKeyCode().GetCode() )
	{
		case KEY_RETURN:
		case KEY_ESCAPE:
            if( pRefEdit )
                pRefEdit->GrabFocus();
            m_pDlg->RefInputDone( sal_True );
        break;
	}
	return sal_True;
}
//----------------------------------------------------------------------------
void ScFormulaReferenceHelper::RefInputDone( sal_Bool bForced )
{
	//<!--Modified by PengYunQuan for Validity Cell Range Picker
	//if (pRefEdit && (bForced || !pRefBtn))
	if ( CanInputDone( bForced ) )//if (pRefEdit && (bForced || !pRefBtn))
	//-->Modified by PengYunQuan for Validity Cell Range Picker
	{
		if (bAccInserted)			// Accelerator wieder abschalten
		{
			Application::RemoveAccel( pAccel.get() );
			bAccInserted = sal_False;
		}

		// Fenstertitel anpassen
		m_pWindow->SetText(sOldDialogText);

		// Fenster wieder gross
		m_pWindow->SetOutputSizePixel(aOldDialogSize);

		// pEditCell an alte Position
		pRefEdit->SetPosSizePixel(aOldEditPos, aOldEditSize);

        // set button position and image
        if( pRefBtn )
        {
            pRefBtn->SetPosPixel( aOldButtonPos );
            pRefBtn->SetStartImage();
        }

		// Alle anderen: Show();
		sal_uInt16 nChildren = m_pWindow->GetChildCount();
		for ( sal_uInt16 i = 0; i < nChildren; i++ )
			if (pHiddenMarks[i])
			{
				m_pWindow->GetChild(i)->GetWindow( WINDOW_CLIENT )->Show();
			}
		delete [] pHiddenMarks;

		pRefEdit = NULL;
        pRefBtn = NULL;
	}
}
// -----------------------------------------------------------------------------
void ScFormulaReferenceHelper::RefInputStart( formula::RefEdit* pEdit, formula::RefButton* pButton )
{
	if (!pRefEdit)
	{
		pRefEdit = pEdit;
		pRefBtn  = pButton;

		// Neuen Fenstertitel basteln
		String sNewDialogText;
		sOldDialogText = m_pWindow->GetText();
		sNewDialogText  = sOldDialogText;
		sNewDialogText.AppendAscii(RTL_CONSTASCII_STRINGPARAM( ": " ));

		// Alle Elemente ausser EditCell und Button verstecken
		sal_uInt16 nChildren = m_pWindow->GetChildCount();
		pHiddenMarks = new sal_Bool [nChildren];
		for (sal_uInt16 i = 0; i < nChildren; i++)
		{
			pHiddenMarks[i] = sal_False;
			Window* pWin = m_pWindow->GetChild(i);
			pWin = pWin->GetWindow( WINDOW_CLIENT );
			if (pWin == (Window*)pRefEdit)
			{
				sNewDialogText += m_pWindow->GetChild(i-1)->GetWindow( WINDOW_CLIENT )->GetText();
			}
			else if (pWin == (Window*)pRefBtn)
				;	// do nothing
			else if (pWin->IsVisible())
			{
				pHiddenMarks[i] = sal_True;
				pWin->Hide();
			}
		}

		// Alte Daten merken
		aOldDialogSize = m_pWindow->GetOutputSizePixel();
		aOldEditPos = pRefEdit->GetPosPixel();
		aOldEditSize = pRefEdit->GetSizePixel();
		if (pRefBtn)
			aOldButtonPos = pRefBtn->GetPosPixel();

		// Edit-Feld verschieben und anpassen
		Size aNewDlgSize(aOldDialogSize.Width(), aOldEditSize.Height());
		Size aNewEditSize(aNewDlgSize);
        long nOffset = 0;
		if (pRefBtn)
		{
			aNewEditSize.Width() -= pRefBtn->GetSizePixel().Width();
			aNewEditSize.Width() -= aOldButtonPos.X() - (aOldEditPos.X()+aOldEditSize.Width());

            long nHeight = pRefBtn->GetSizePixel().Height();
            if ( nHeight > aOldEditSize.Height() )
            {
                aNewDlgSize.Height() = nHeight;
                nOffset = (nHeight-aOldEditSize.Height()) / 2;
            }
            aNewEditSize.Width() -= nOffset;
		}
		pRefEdit->SetPosSizePixel(Point(nOffset, nOffset), aNewEditSize);

        // set button position and image
        if( pRefBtn )
        {
            pRefBtn->SetPosPixel( Point( aOldDialogSize.Width() - pRefBtn->GetSizePixel().Width(), 0 ) );
            pRefBtn->SetEndImage();
        }

		// Fenster verkleinern
		m_pWindow->SetOutputSizePixel(aNewDlgSize);

		// Fenstertitel anpassen
		m_pWindow->SetText( MnemonicGenerator::EraseAllMnemonicChars( sNewDialogText ) );

//        if ( pButton )      // ueber den Button: Enter und Escape abfangen
//        {
			if (!pAccel.get())
			{
				pAccel.reset( new Accelerator );
				pAccel->InsertItem( 1, KeyCode( KEY_RETURN ) );
				pAccel->InsertItem( 2, KeyCode( KEY_ESCAPE ) );
				pAccel->SetSelectHdl( LINK( this, ScFormulaReferenceHelper, AccelSelectHdl ) );
			}
			Application::InsertAccel( pAccel.get() );
			bAccInserted = sal_True;
//        }
	}
}
// -----------------------------------------------------------------------------
void ScFormulaReferenceHelper::ToggleCollapsed( formula::RefEdit* pEdit, formula::RefButton* pButton )
{
    if( pEdit )
    {
        if( pRefEdit == pEdit )                 // is this the active ref edit field?
        {
            pRefEdit->GrabFocus();              // before RefInputDone()
            m_pDlg->RefInputDone( sal_True );               // finish ref input
        }
        else
        {
            m_pDlg->RefInputDone( sal_True );               // another active ref edit?
            m_pDlg->RefInputStart( pEdit, pButton );    // start ref input
            // pRefEdit might differ from pEdit after RefInputStart() (i.e. ScFormulaDlg)
            if( pRefEdit )
                pRefEdit->GrabFocus();
        }
    }
}
// -----------------------------------------------------------------------------
sal_Bool ScFormulaReferenceHelper::DoClose( sal_uInt16 nId )
{
	SfxApplication* pSfxApp = SFX_APP();

	SetDispatcherLock( sal_False );			//! here and in dtor ?

	SfxViewFrame* pViewFrm = SfxViewFrame::Current();
	if ( pViewFrm && pViewFrm->HasChildWindow(FID_INPUTLINE_STATUS) )
	{
		//	Die Eingabezeile wird per ToolBox::Disable disabled, muss darum auch
		//	per ToolBox::Enable wieder aktiviert werden (vor dem Enable des AppWindow),
		//	damit die Buttons auch wieder enabled gezeichnet werden.
		SfxChildWindow* pChild = pViewFrm->GetChildWindow(FID_INPUTLINE_STATUS);
		if (pChild)
		{
			ScInputWindow* pWin = (ScInputWindow*)pChild->GetWindow();
			pWin->Enable();
		}
	}

	// find parent view frame to close dialog
	SfxViewFrame* pMyViewFrm = NULL;
	if ( m_pBindings )
	{
		SfxDispatcher* pMyDisp = m_pBindings->GetDispatcher();
		if (pMyDisp)
			pMyViewFrm = pMyDisp->GetFrame();
	}
	SC_MOD()->SetRefDialog( nId, sal_False, pMyViewFrm );

	pSfxApp->Broadcast( SfxSimpleHint( FID_KILLEDITVIEW ) );

    ScTabViewShell* pScViewShell = ScTabViewShell::GetActiveViewShell();
	if ( pScViewShell )
		pScViewShell->UpdateInputHandler(sal_True);

	return sal_True;
}
void ScFormulaReferenceHelper::SetDispatcherLock( sal_Bool bLock )
{
	//	lock / unlock only the dispatchers of Calc documents

	TypeId aType(TYPE(ScDocShell));
	ScDocShell* pDocShell = (ScDocShell*)SfxObjectShell::GetFirst(&aType);
	while( pDocShell )
	{
		SfxViewFrame* pFrame = SfxViewFrame::GetFirst( pDocShell );
		while( pFrame )
		{
			SfxDispatcher* pDisp = pFrame->GetDispatcher();
			if (pDisp)
				pDisp->Lock( bLock );

			pFrame = SfxViewFrame::GetNext( *pFrame, pDocShell );
		}
		pDocShell = (ScDocShell*)SfxObjectShell::GetNext(*pDocShell, &aType);
	}

	//	if a new view is created while the dialog is open,
	//	that view's dispatcher is locked when trying to create the dialog
	//	for that view (ScTabViewShell::CreateRefDialog)
}
// -----------------------------------------------------------------------------
void ScFormulaReferenceHelper::ViewShellChanged(ScTabViewShell* /* pScViewShell */)
{
	enableInput( sal_False );

	EnableSpreadsheets();
}
void ScFormulaReferenceHelper::EnableSpreadsheets(sal_Bool bFlag, sal_Bool bChilds)
{
	TypeId aType(TYPE(ScDocShell));
	ScDocShell* pDocShell = (ScDocShell*)SfxObjectShell::GetFirst(&aType);
	while( pDocShell )
	{
		SfxViewFrame* pFrame = SfxViewFrame::GetFirst( pDocShell );
		while( pFrame )
		{
			//	#71577# enable everything except InPlace, including bean frames
            if ( !pFrame->GetFrame().IsInPlace() )
			{
				SfxViewShell* p = pFrame->GetViewShell();
				ScTabViewShell* pViewSh = PTR_CAST(ScTabViewShell,p);
				if(pViewSh!=NULL)
				{
					Window *pWin=pViewSh->GetWindow();
					if(pWin)
					{
						Window *pParent=pWin->GetParent();
						if(pParent)
						{
							pParent->EnableInput(bFlag,sal_False);
							if(bChilds)
								pViewSh->EnableRefInput(bFlag);
						}
					}
				}
			}
			pFrame = SfxViewFrame::GetNext( *pFrame, pDocShell );
		}

		pDocShell = (ScDocShell*)SfxObjectShell::GetNext(*pDocShell, &aType);
	}
}

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



void lcl_InvalidateWindows()
{
	TypeId aType(TYPE(ScDocShell));
	ScDocShell* pDocShell = (ScDocShell*)SfxObjectShell::GetFirst(&aType);
	while( pDocShell )
	{
		SfxViewFrame* pFrame = SfxViewFrame::GetFirst( pDocShell );
		while( pFrame )
		{
			//	#71577# enable everything except InPlace, including bean frames
            if ( !pFrame->GetFrame().IsInPlace() )
			{
				SfxViewShell* p = pFrame->GetViewShell();
				ScTabViewShell* pViewSh = PTR_CAST(ScTabViewShell,p);
				if(pViewSh!=NULL)
				{
					Window *pWin=pViewSh->GetWindow();
					if(pWin)
					{
						Window *pParent=pWin->GetParent();
						if(pParent)
							pParent->Invalidate();
					}
				}
			}
			pFrame = SfxViewFrame::GetNext( *pFrame, pDocShell );
		}

		pDocShell = (ScDocShell*)SfxObjectShell::GetNext(*pDocShell, &aType);
	}
}
//----------------------------------------------------------------------------

void lcl_HideAllReferences()
{
	TypeId aScType = TYPE(ScTabViewShell);
	SfxViewShell* pSh = SfxViewShell::GetFirst( &aScType );
	while ( pSh )
	{
		((ScTabViewShell*)pSh)->ClearHighlightRanges();
		pSh = SfxViewShell::GetNext( *pSh, &aScType );
	}
}

//============================================================================
//The class of ScAnyRefDlg is rewritten by PengYunQuan for Validity Cell Range Picker
//	class ScRefHandler
//----------------------------------------------------------------------------

ScRefHandler::ScRefHandler( Window &rWindow, SfxBindings* pB/*, SfxChildWindow* pCW,
						  Window* pParent, sal_uInt16 nResId*/, bool bBindRef )
	:	//SfxModelessDialog ( pB, pCW, pParent, ScResId( nResId ) ),
		m_rWindow( rWindow ),
		m_bInRefMode( false ),
        m_aHelper(this,pB),
		pMyBindings( pB ),
        pActiveWin(NULL)
{
	m_aHelper.SetWindow(/*this*/&m_rWindow);
	if(m_rWindow.GetHelpId().getLength()==0)				//Hack, da im SfxModelessDialog die HelpId
		m_rWindow.SetHelpId(m_rWindow.GetUniqueId());	//fuer einen ModelessDialog entfernt und
									//in eine UniqueId gewandelt wird, machen
									//wir das an dieser Stelle rueckgaengig.
	aTimer.SetTimeout(200);
	aTimer.SetTimeoutHdl(LINK( this, ScRefHandler, UpdateFocusHdl));

	if( bBindRef ) EnterRefMode();
}

bool ScRefHandler::EnterRefMode()
{
	if( m_bInRefMode ) return false;

	SC_MOD()->InputEnterHandler();
//    ScTabViewShell* pScViewShell = ScTabViewShell::GetActiveViewShell();

    ScTabViewShell* pScViewShell = NULL;

	// title has to be from the view that opened the dialog,
	// even if it's not the current view

	SfxObjectShell* pParentDoc = NULL;
	if ( pMyBindings )
	{
		SfxDispatcher* pMyDisp = pMyBindings->GetDispatcher();
		if (pMyDisp)
		{
			SfxViewFrame* pMyViewFrm = pMyDisp->GetFrame();
			if (pMyViewFrm)
            {
                pScViewShell = PTR_CAST( ScTabViewShell, pMyViewFrm->GetViewShell() );
                if( pScViewShell )
		            pScViewShell->UpdateInputHandler(sal_True);
				pParentDoc = pMyViewFrm->GetObjectShell();
            }
		}
	}
	if ( !pParentDoc && pScViewShell )					// use current only if above fails
		pParentDoc = pScViewShell->GetObjectShell();
	if ( pParentDoc )
		aDocName = pParentDoc->GetTitle();

    ScInputHandler*	pInputHdl = SC_MOD()->GetInputHdl(pScViewShell);

	DBG_ASSERT( pInputHdl, "Missing input handler :-/" );

	if ( pInputHdl )
		pInputHdl->NotifyChange( NULL );

	m_aHelper.enableInput( sal_False );

	m_aHelper.EnableSpreadsheets();

    m_aHelper.Init();

	m_aHelper.SetDispatcherLock( sal_True );
	//@Test
	//SFX_APPWINDOW->Disable(sal_True);	  //@BugID 54702

	return m_bInRefMode = true;
}

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

ScRefHandler::~ScRefHandler()
{
	LeaveRefMode();
}

bool ScRefHandler::LeaveRefMode()
{
	if( !m_bInRefMode ) return false;

	lcl_HideAllReferences();

	if( Dialog *pDlg = dynamic_cast<Dialog*>( static_cast<Window*>(*this) ) )
		pDlg->SetModalInputMode(sal_False);
	SetDispatcherLock( sal_False );			//! here and in DoClose ?

    ScTabViewShell* pScViewShell = ScTabViewShell::GetActiveViewShell();
    if( pScViewShell )
		pScViewShell->UpdateInputHandler(sal_True);

	//SFX_APPWINDOW->Enable(sal_True,sal_True);
	lcl_InvalidateWindows();

	m_bInRefMode = false;
	return true;
}

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

//SfxBindings& ScRefHandler::GetBindings()
//{
//	//!	SfxModelessDialog should allow access to pBindings pointer
//
//	return *pMyBindings;
//}

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

void ScRefHandler::SwitchToDocument()
{
	ScTabViewShell* pCurrent = ScTabViewShell::GetActiveViewShell();
	if (pCurrent)
	{
		SfxObjectShell* pObjSh = pCurrent->GetObjectShell();
		if ( pObjSh && pObjSh->GetTitle() == aDocName )
		{
			//	right document already visible -> nothing to do
			return;
		}
	}

	TypeId aScType = TYPE(ScTabViewShell);
	SfxViewShell* pSh = SfxViewShell::GetFirst( &aScType );
	while ( pSh )
	{
		SfxObjectShell* pObjSh = pSh->GetObjectShell();
		if ( pObjSh && pObjSh->GetTitle() == aDocName )
		{
			//	switch to first TabViewShell for document
			((ScTabViewShell*)pSh)->SetActive();
			return;
		}
		pSh = SfxViewShell::GetNext( *pSh, &aScType );
	}
}

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

sal_Bool ScRefHandler::IsDocAllowed(SfxObjectShell* pDocSh) const	// pDocSh may be 0
{
	//	default: allow only same document (overridden in function dialog)
	String aCmpName;
	if ( pDocSh )
		aCmpName = pDocSh->GetTitle();

	//	if aDocName isn't initialized, allow
	return ( aDocName.Len() == 0 || aDocName == aCmpName );
}

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

sal_Bool __EXPORT ScRefHandler::IsRefInputMode() const
{
	return m_rWindow.IsVisible(); // nur wer sichtbar ist kann auch Referenzen bekommen
}

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

sal_Bool __EXPORT ScRefHandler::DoClose( sal_uInt16 nId )
{
    m_aHelper.DoClose(nId);
	return sal_True;
}

void ScRefHandler::SetDispatcherLock( sal_Bool bLock )
{
	m_aHelper.SetDispatcherLock( bLock );
}

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

void ScRefHandler::ViewShellChanged(ScTabViewShell*  pScViewShell )
{
	m_aHelper.ViewShellChanged(pScViewShell);
}

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

void ScRefHandler::AddRefEntry()
{
	//	wenn nicht ueberladen, gibt es keine Mehrfach-Referenzen
}

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

sal_Bool __EXPORT ScRefHandler::IsTableLocked() const
{
	// per Default kann bei Referenzeingabe auch die Tabelle umgeschaltet werden

	return sal_False;
}

//----------------------------------------------------------------------------
//
//	RefInputStart/Done: Zoom-In (AutoHide) auf einzelnes Feld
//	(per Button oder Bewegung)
//
//----------------------------------------------------------------------------

void ScRefHandler::RefInputStart( formula::RefEdit* pEdit, formula::RefButton* pButton )
{
    m_aHelper.RefInputStart( pEdit, pButton );
}


void ScRefHandler::ToggleCollapsed( formula::RefEdit* pEdit, formula::RefButton* pButton )
{
    m_aHelper.ToggleCollapsed( pEdit, pButton );
}

//The two following function is commentted out by PengYunQuan for Validity Cell Range Picker
//long ScAnyRefDlg::PreNotify( NotifyEvent& rNEvt )
//{
//	sal_uInt16 nSwitch=rNEvt.GetType();
//	if(nSwitch==EVENT_GETFOCUS)
//	{
//		pActiveWin=rNEvt.GetWindow();
//	}
//	return SfxModelessDialog::PreNotify(rNEvt);
//}
//
//void ScAnyRefDlg::StateChanged( StateChangedType nStateChange )
//{
//	SfxModelessDialog::StateChanged( nStateChange );
//
//	if(nStateChange == STATE_CHANGE_VISIBLE)
//	{
//		if(IsVisible())
//		{
//			m_aHelper.enableInput( sal_False );
//			m_aHelper.EnableSpreadsheets();
//			m_aHelper.SetDispatcherLock( sal_True );
//			aTimer.Start();
//		}
//		else
//		{
//			m_aHelper.enableInput( sal_True );
//			m_aHelper.SetDispatcherLock( sal_False );			//! here and in DoClose ?
//		}
//	}
//}

#if defined( _MSC_VER )
#define INTRODUCE_TEMPLATE
#else
#define INTRODUCE_TEMPLATE	template <>
#endif

#define IMPL_TWINDOW_PRENOTIFY( TWindow,bBindRef )	\
INTRODUCE_TEMPLATE long ScRefHdlrImplBase<TWindow,bBindRef>::PreNotify( NotifyEvent& rNEvt )\
{\
	if( bBindRef || m_bInRefMode )\
	{\
		sal_uInt16 nSwitch=rNEvt.GetType();\
		if(nSwitch==EVENT_GETFOCUS)\
		{\
			pActiveWin=rNEvt.GetWindow();\
		}\
	}\
	return TWindow::PreNotify(rNEvt);\
}

#define IMPL_TWINDOW_STATECHANGED( TWindow,bBindRef )	\
INTRODUCE_TEMPLATE void ScRefHdlrImplBase<TWindow,bBindRef>::StateChanged( StateChangedType nStateChange )\
{\
	TWindow::StateChanged( nStateChange );\
\
	if( !bBindRef && !m_bInRefMode ) return;\
	\
	if(nStateChange == STATE_CHANGE_VISIBLE)\
	{\
		if(m_rWindow.IsVisible())\
		{\
			m_aHelper.enableInput( sal_False );\
			m_aHelper.EnableSpreadsheets();\
			m_aHelper.SetDispatcherLock( sal_True );\
			aTimer.Start();\
		}\
		else\
		{\
			m_aHelper.enableInput( sal_True );\
			m_aHelper.SetDispatcherLock( sal_False );			/*//! here and in DoClose ?*/\
		}\
	}\
}

IMPL_TWINDOW_PRENOTIFY( SfxModelessDialog, true )
IMPL_TWINDOW_PRENOTIFY( SfxTabDialog, false )
IMPL_TWINDOW_STATECHANGED( SfxModelessDialog, true )
IMPL_TWINDOW_STATECHANGED( SfxTabDialog, false )

IMPL_LINK( ScRefHandler, UpdateFocusHdl, Timer*, EMPTYARG )
{
	if (pActiveWin)
	{
		pActiveWin->GrabFocus();
	}
	return 0;
}
// -----------------------------------------------------------------------------
bool ScRefHandler::ParseWithNames( ScRangeList& rRanges, const String& rStr, ScDocument* pDoc )
{
    return m_aHelper.ParseWithNames( rRanges, rStr, pDoc );
}
// -----------------------------------------------------------------------------
void ScRefHandler::HideReference( sal_Bool bDoneRefMode )
{
    m_aHelper.HideReference( bDoneRefMode );
}
// -----------------------------------------------------------------------------
void ScRefHandler::ShowReference( const XubString& rStr )
{
    m_aHelper.ShowReference( rStr );
}
// -----------------------------------------------------------------------------
void ScRefHandler::ReleaseFocus( formula::RefEdit* pEdit, formula::RefButton* pButton )
{
    m_aHelper.ReleaseFocus( pEdit,pButton );
}
//----------------------------------------------------------------------------
void ScRefHandler::RefInputDone( sal_Bool bForced )
{
    m_aHelper.RefInputDone( bForced );
}
