/*************************************************************************
 *
 *  $RCSfile: editbrowsebox.hxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: vg $ $Date: 2001/06/18 15:31:05 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  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
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc..
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _SVTOOLS_EDITBROWSEBOX_HXX_
#define _SVTOOLS_EDITBROWSEBOX_HXX_

#ifndef _REF_HXX
#include <tools/ref.hxx>
#endif

#ifndef _RTTI_HXX
#include <tools/rtti.hxx>
#endif

#ifndef _WINDOW_HXX
#include <vcl/window.hxx>
#endif

#ifndef _SV_COMBOBOX_HXX
#include <vcl/combobox.hxx>
#endif

#ifndef _SV_LSTBOX_HXX
#include <vcl/lstbox.hxx>
#endif

#ifndef _IMAGEBTN_HXX
#include <vcl/imagebtn.hxx>
#endif

#ifndef _SVX_BRWBOX_HXX
#include <svtools/brwbox.hxx>
#endif

#ifndef _SV_TIMER_HXX
#include <vcl/timer.hxx>
#endif

#ifndef _BRWHEAD_HXX
#include <svtools/brwhead.hxx>
#endif

#ifndef _SV_SVAPP_HXX
#include <vcl/svapp.hxx>
#endif

//==================================================================
// EditBrowseBoxFlags (EBBF)

#define EBBF_NONE					((sal_Int32)0x0000)
#define EBBF_NOROWPICTURE			((sal_Int32)0x0001)
	// if this bit is _not_ set, the handle column will be invalidated upon changing the row in the browse box.
	// This is for forcing the row picture to be repainted. If you do not have row pictures, you don't need this
	// invalidation, then you would specify this bit to prevent flicker
#define EBBF_ACTIVATE_ON_BUTTONDOWN	((sal_Int32)0x0002)
	// set this bit to activate the cell on a MouseButtonDown, not a MouseButtonUp event

//==================================================================

class Edit;
class ListBoxFrame;
class ButtonCtrl;
class SpinField;

// .......................................................................
namespace svt
{
// .......................................................................

	class CellControllerRef;

	//==================================================================
	//= CellController
	//==================================================================
	class CellController : public SvRefBase
	{
		friend class EditBrowseBox;

	protected:
		Window* pWindow;

	public:
		TYPEINFO();

		CellController(Window* pW);
		virtual ~CellController();

		Window& GetWindow() const {return *((CellController*) this)->pWindow;}

		virtual void SetModified();
		virtual void ClearModified() = 0;
		virtual sal_Bool IsModified()  const = 0;

	protected:
		virtual sal_Bool MoveAllowed(const KeyEvent& rEvt) const;
		virtual void SetModifyHdl(const Link& rLink) = 0;
		virtual sal_Bool WantMouseEvent() const;
	};

	SV_DECL_IMPL_REF(CellController);

	//==================================================================
	//= EditCellController
	//==================================================================
	class EditCellController : public CellController
	{
	public:
		TYPEINFO();
		EditCellController(Edit* pEdit);
		Edit& GetEditWindow() const {return (Edit &)GetWindow();}

		virtual void SetModified();
		virtual sal_Bool IsModified() const;
		virtual void ClearModified();

	protected:
		virtual sal_Bool MoveAllowed(const KeyEvent& rEvt) const;
		virtual void SetModifyHdl(const Link& rLink);
	};

	//==================================================================
	//= SpinCellController
	//==================================================================
	class SpinCellController : public CellController
	{
	public:
		TYPEINFO();
		SpinCellController(SpinField* pSpinField);
		SpinField& GetSpinWindow() const {return (SpinField &)GetWindow();}

		virtual void SetModified();
		virtual sal_Bool IsModified() const;
		virtual void ClearModified();

	protected:
		virtual sal_Bool MoveAllowed(const KeyEvent& rEvt) const;
		virtual void SetModifyHdl(const Link& rLink);
	};

	//==================================================================
	//= CheckBoxControl
	//==================================================================
	class CheckBoxControl : public Control
	{
		CheckBox*	pBox;
		Rectangle	aFocusRect;
		Link		m_aClickLink,m_aModifyLink;

	public:
		CheckBoxControl(Window* pParent, WinBits nWinStyle = 0);
		~CheckBoxControl();

		virtual void GetFocus();
		virtual long PreNotify(NotifyEvent& rEvt);
		virtual void Paint(const Rectangle& rClientRect);
		virtual void Resize();

		void SetClickHdl(const Link& rHdl) {m_aClickLink = rHdl;}
		const Link& GetClickHdl() const {return m_aClickLink;}

		void SetModifyHdl(const Link& rHdl) {m_aModifyLink = rHdl;}
		const Link& GetModifyHdl() const {return m_aModifyLink;}

		CheckBox&	GetBox() {return *pBox;};

	private:
		DECL_LINK( OnClick, void* );
	};

	//==================================================================
	//= CheckBoxCellController
	//==================================================================
	class CheckBoxCellController : public CellController
	{
	public:
		TYPEINFO();

		CheckBoxCellController(CheckBoxControl* pWin):CellController(pWin){}
		CheckBox& GetCheckBox() const;

		virtual sal_Bool IsModified() const;
		virtual void ClearModified();

	protected:
		virtual void SetModifyHdl(const Link& rLink);
		virtual sal_Bool WantMouseEvent() const;
	};

	//==================================================================
	//= ComboBoxControl
	//==================================================================
	class ComboBoxControl : public ComboBox
	{
		friend class ComboBoxCellController;

	public:
		ComboBoxControl(Window* pParent, WinBits nWinStyle = 0);

	protected:
		virtual long PreNotify( NotifyEvent& rNEvt );
	};

	//==================================================================
	//= ComboBoxCellController
	//==================================================================
	class ComboBoxCellController : public CellController
	{
	public:
		TYPEINFO();

		ComboBoxCellController(ComboBoxControl* pParent);
		ComboBoxControl& GetComboBox() const {return (ComboBoxControl &)GetWindow();}

		virtual sal_Bool IsModified() const;
		virtual void ClearModified();

	protected:
		virtual sal_Bool MoveAllowed(const KeyEvent& rEvt) const;
		virtual void SetModifyHdl(const Link& rLink);
	};

	//==================================================================
	//= ListBoxControl
	//==================================================================
	class ListBoxControl : public ListBox
	{
		friend class ListBoxCellController;

	public:
		ListBoxControl(Window* pParent, WinBits nWinStyle = 0);

	protected:
		virtual long PreNotify( NotifyEvent& rNEvt );
	};

	//==================================================================
	//= ListBoxCellController
	//==================================================================
	class ListBoxCellController : public CellController
	{
	public:
		TYPEINFO();

		ListBoxCellController(ListBoxControl* pParent);
		ListBoxControl& GetListBox() const {return (ListBoxControl &)GetWindow();}

		virtual sal_Bool IsModified() const;
		virtual void ClearModified();

	protected:
		virtual sal_Bool MoveAllowed(const KeyEvent& rEvt) const;
		virtual void SetModifyHdl(const Link& rLink);
	};

	//==================================================================
	//= EditBrowserHeader
	//==================================================================
	class EditBrowserHeader : public BrowserHeader
	{
	public:
		EditBrowserHeader( BrowseBox* pParent, WinBits nWinBits = WB_BUTTONSTYLE )
			:BrowserHeader(pParent, nWinBits){}

	protected:
		virtual void DoubleClick();
	};

	//==================================================================
	//= EditBrowseBox
	//==================================================================
	class EditBrowseBox: public BrowseBox
	{
		friend class EditBrowserHeader;

		enum BrowseInfo
		{
			COLSELECT	=	1,
			ROWSELECT	=	2,
			ROWCHANGE	=	4,
			COLCHANGE	=	8
		};

	public:
		enum RowStatus
		{
			CLEAN				=	0,
			CURRENT				=	1,
			CURRENTNEW			=	2,
			MODIFIED			=	3,
			NEW					=	4,
			DELETED				=	5,
			PRIMARYKEY			=	6,
			CURRENT_PRIMARYKEY	=	7,
			FILTER				=	8
		};

	private:
		class BrowserMouseEventPtr
		{
			BrowserMouseEvent* pEvent;
			sal_Bool bDown;

		public:
			BrowserMouseEventPtr():pEvent(NULL){}
			~BrowserMouseEventPtr(){Clear();}

			sal_Bool Is() const {return pEvent != NULL;}
			sal_Bool IsDown() const {return bDown;}
			const BrowserMouseEvent* operator->() const {return pEvent;}
			const BrowserMouseEvent& operator*() const {return *pEvent;}

			void Clear();
			void Set(const BrowserMouseEvent* pEvt, sal_Bool bIsDown);
		} aMouseEvent;

		const BrowserMouseEvent* pMouseEvent;	// is set during a mouse event
		CellControllerRef		 aController,
								 aOldController;

		sal_uInt32	nStartEvent, nEndEvent, nCellModifiedEvent;		// event ids
		Window*	m_pFocusWhileRequest;
			// In ActivateCell, we grab the focus asynchronously, but if between requesting activation
			// and the asynchornous event the focus has changed, we won't grab it for ourself.

		long	nPaintRow;	// row beeing painted
		long	nEditRow, nOldEditRow;
		sal_uInt16	nEditCol, nOldEditCol;

		sal_Bool	bHasFocus : 1;
		sal_Bool	bPaintStatus : 1;	// paint a status (image) in the handle column

		CheckBoxControl* pCheckBoxPaint;

		sal_Int32	m_nBrowserFlags;
		ImageList	m_aStatusImages;

	protected:
		BrowserHeader*  pHeader;

		sal_Bool isGetCellFocusPending() const { return nStartEvent != 0; }
		void cancelGetCellFocus() { if (nStartEvent) Application::RemoveUserEvent(nStartEvent); nStartEvent = 0; }
		void forceGetCellFocus() { cancelGetCellFocus(); LINK(this, EditBrowseBox, StartEditHdl).Call((void*)NULL); }

		BrowserMouseEventPtr& getMouseEvent() { return aMouseEvent; }

	protected:
		BrowserHeader*	GetHeaderBar() const {return pHeader;}

		virtual BrowserHeader* CreateHeaderBar(BrowseBox* pParent);

		// if you want to have an own header ...
		virtual BrowserHeader* imp_CreateHeaderBar(BrowseBox* pParent);

		virtual void ColumnMoved(sal_uInt16 nId);
		virtual void ColumnResized(sal_uInt16 nColId);
		virtual void Resize();
		virtual void ArrangeControls(sal_uInt16& nX, sal_uInt16 nY);
		virtual sal_Bool SeekRow(long nRow);

		virtual void GetFocus();
		virtual void LoseFocus();
		virtual void KeyInput(const KeyEvent& rEvt);
		virtual void MouseButtonDown(const BrowserMouseEvent& rEvt);
		virtual void MouseButtonUp(const BrowserMouseEvent& rEvt);
		virtual void StateChanged( StateChangedType nType );
		virtual void DataChanged( const DataChangedEvent& rDCEvt );

		virtual long PreNotify(NotifyEvent& rNEvt );
		virtual long Notify(NotifyEvent& rNEvt);

		virtual void EndScroll();

		// should be used instead of GetFieldRectPixel, 'cause this method here takes into account the borders
		Rectangle GetCellRect(long nRow, sal_uInt16 nColId, sal_Bool bRelToBrowser = sal_True) const;
		virtual sal_uInt32 GetTotalCellWidth(long nRow, sal_uInt16 nColId);
		virtual sal_uInt32 GetAutoColumnWidth(sal_uInt16 nColId);

		virtual void PaintStatusCell(OutputDevice& rDev, const Rectangle& rRect) const;
		virtual void PaintCell(OutputDevice& rDev, const Rectangle& rRect, sal_uInt16 nColId) const = 0;

		virtual RowStatus GetRowStatus(long nRow) const;

		// when changing a row:
		// CursorMoving:	cursor is beeing moved, but GetCurRow() still provides the old row
		virtual sal_Bool CursorMoving(long nNewRow, sal_uInt16 nNewCol);

		// cursor has been moved
		virtual void CursorMoved();

		virtual void CellModified();		// called whenever a cell has been modified
		virtual sal_Bool SaveModified();	// called whenever a cell should be left, and it's content should be saved
											// return sal_False prevents leaving the cell
		virtual sal_Bool SaveRow();			// commit the current row

		virtual sal_Bool IsModified() const {return aController.Is() && aController->IsModified();}

		virtual CellController* GetController(long nRow, sal_uInt16 nCol);
		virtual void InitController(CellControllerRef& rController, long nRow, sal_uInt16 nCol);
		virtual void ResizeController(CellControllerRef& rController, const Rectangle&);
		virtual void ReleaseController(CellControllerRef& pController, long nRow, sal_uInt16 nCol);
		virtual void DoubleClick(const BrowserMouseEvent&);

		void ActivateCell() { ActivateCell(GetCurRow(), GetCurColumnId()); }

		// retrieve the image for the row status
		virtual Image GetImage(RowStatus) const;

		// inserting columns
		// width = 0 means the default size for the handle column will be used
		virtual void InsertHandleColumn(sal_uInt16 nWidth = 0);
		// if you don't set a width, this will be calculated automatically
		// if the id isn't set the smallest unused will do it ...
		virtual sal_uInt16 AppendColumn(const String& rName, sal_uInt16 nWidth = 0, sal_uInt16 nPos = HEADERBAR_APPEND, sal_uInt16 nId = (sal_uInt16)-1);

		// called whenever (Shift)Tab or Enter is pressed. If true is returned, these keys
		// result in traveling to the next or to th previous cell
		virtual sal_Bool IsTabAllowed(sal_Bool bForward) const;

		virtual sal_Bool IsCursorMoveAllowed(long nNewRow, sal_uInt16 nNewColId) const;

		void PaintTristate(OutputDevice& rDev, const Rectangle& rRect,const TriState& eState,sal_Bool _bEnabled=sal_True) const;

		void AsynchGetFocus();
			// secure starting of StartEditHdl

	public:
		EditBrowseBox(Window* pParent, sal_Int32 nBrowserFlags = EBBF_NONE, WinBits nBits = WB_TABSTOP, BrowserMode nMode = 0 );
		EditBrowseBox(Window* pParent, const ResId& rId, sal_Int32 nBrowserFlags = EBBF_NONE, BrowserMode nMode = 0 );
		~EditBrowseBox();

		sal_Bool IsEditing() const {return aController.Is();}
		void InvalidateStatusCell(long nRow) {RowModified(nRow, 0);}
		void InvalidateHandleColumn();

		virtual sal_uInt16 GetDefaultColumnWidth(const String& rName) const;

		// late construction
		virtual void Init();
		virtual void RemoveRows();
		virtual void Dispatch(sal_uInt16 nId);

		CellControllerRef Controller() const { return aController; }
		sal_Int32	GetBrowserFlags() const { return m_nBrowserFlags; }
		void	SetBrowserFlags(sal_Int32 nFlags);

		virtual void ActivateCell(long nRow, sal_uInt16	nCol, sal_Bool bSetCellFocus = sal_True);
		virtual void DeactivateCell(sal_Bool bUpdate = sal_True);

	private:
		virtual void PaintField(OutputDevice& rDev, const Rectangle& rRect,
								sal_uInt16 nColumnId ) const;
		void ImplInitSettings( sal_Bool bFont, sal_Bool bForeground, sal_Bool bBackground );
		void DetermineFocus();
		inline void HideAndDisable(CellControllerRef& rController);
		inline void EnableAndShow() const;

		void implActivateCellOnMouseEvent(const BrowserMouseEvent& _rEvt, sal_Bool _bUp);

		DECL_LINK(ModifyHdl, void* );
		DECL_LINK(StartEditHdl, void* );
		DECL_LINK(EndEditHdl, void* );
		DECL_LINK(CellModifiedHdl, void* );
	};

// .......................................................................
}	// namespace svt
// .......................................................................

#endif // _SVTOOLS_EDITBROWSEBOX_HXX_

/*************************************************************************
 * history:
 *	$Log: editbrowsebox.hxx,v $
 *	Revision 1.2  2001/06/18 15:31:05  vg
 *	#65293# corrected include path
 *	
 *	Revision 1.1  2001/06/15 12:48:20  fs
 *	initial checkin - moved this herein from svx/inc/dbbrowse.hxx
 *	
 *
 *	Revision 1.0 15.06.01 12:34:40  fs
 ************************************************************************/

