//****************************************************************************************
BOOL CBCGPGridSerializeManager::Paste (CBCGPGridItemID idPasteTo, BOOL bCut)
{
	m_Operation = OP_CopyPaste;
	m_bSkipData = FALSE;
	
	CBCGPGridItemID idFrom;
	idFrom.SetNull ();

	if (m_ClipboardFormatType == CF_Rows)
	{
		return DoDropRows (idPasteTo, idFrom, bCut, FALSE);
	}
	
	return DoDropItems (idPasteTo, idFrom, bCut);
}
//****************************************************************************************
BOOL CBCGPGridSerializeManager::DoDropRows (CBCGPGridItemID idDropTo, CBCGPGridItemID idDragFrom,
											BOOL bMove, BOOL bInsertAfter)
{
	ASSERT (m_pOwnerGrid != NULL);
	ASSERT (m_ClipboardFormatType == CF_Rows);
	
	if (GetRangeCount () == 0)
	{
		return FALSE; // no data
	}

	// Copied rows are already removed if called from Paste or dragged from another app
	BOOL bNoRemove = idDragFrom.IsNull ();

	//---------------------
	// Calculate new offset
	//---------------------
	idDragFrom.SetNull ();
	if (bInsertAfter)
	{
		idDropTo.m_nRow++;
	}
	
	CBCGPGridItemID idTo = GetDropOffset (idDragFrom, idDropTo);
	ASSERT (idTo.m_nRow >= 0);
	ASSERT (idTo.m_nColumn >= 0);

	//----------------
	// Mark selection:	(save ranges to remove selection later)
	//----------------
	CleanUpImplementationData ();
	if (bNoRemove)
	{
		m_arrCutRanges.SetSize (0);
	}
	else
	{
		m_arrCutRanges.SetSize (GetRangeCount ());
		
		for (int i = 0; i < GetRangeCount (); i++)
		{
			CBCGPGridRange rangeOrder;
			if (!GetRange (i, rangeOrder))
			{
				return FALSE;
			}
			
			
			rangeOrder.m_nTop += m_idRangesOffset.m_nRow; 
			rangeOrder.m_nBottom += m_idRangesOffset.m_nRow;
			m_arrCutRanges [i] = (CMarkedGridRange) rangeOrder;
			
			if (rangeOrder.m_nTop < idDropTo.m_nRow &&
				rangeOrder.m_nBottom >= idDropTo.m_nRow)
			{
				//idDropTo = rangeOrder.m_nTop;
				return FALSE; // can't insert inside range
			}
		}
	}

	//-------------
	// Drop ranges:
	//-------------
	for (int i = 0; i < GetRangeCount (); i++)
	{
		CBCGPGridRange rangeOrder;
		if (!GetRange (i, rangeOrder))
		{
			return FALSE;
		}

		if (rangeOrder.m_nTop < 0 || rangeOrder.m_nBottom < rangeOrder.m_nTop)
		{
			return FALSE;
		}

		const int nRowOffset = -rangeOrder.m_nTop + idTo.m_nRow + (int)m_lstNewRows.GetCount ();
		rangeOrder.m_nTop += nRowOffset;
		rangeOrder.m_nBottom += nRowOffset;

		//------------
		// Drop range:
		//------------
		UINT	nDataSize = 0;
		BYTE*	pData = GetRangeData (i, nDataSize);
		
		if (pData == NULL || nDataSize <= 0)
		{
			return FALSE;
		}
		
		CMemFile f(pData, nDataSize);
		
		CArchive archive (&f, CArchive::load);
		if (!ReadRowsFromArchive (archive, rangeOrder))
		{
			return FALSE;
		}
		archive.Close ();
	}

 	if (!m_bSkipData)
 	{
		//---------------------------
		// Remove previous selection:
		//---------------------------
		CBCGPGridItemID id;
		m_pOwnerGrid->SetCurSel (id, SM_NONE, FALSE);

 		//-------------------------
 		// Insert new rows to grid:
 		//-------------------------
 		InsertNewSelection (idTo.m_nRow, m_lstNewRows);

		if (bMove)
		{
			//---------------------
			// Remove marked items (previous selection):
			//---------------------
			if (!RemovePreviosSelection ())
			{
				return FALSE; // can't clear non empty items 
			}
		}

		UpdateSelectionRect (idTo);
		m_pOwnerGrid->AdjustLayout ();

		//-------------------
		// Set new selection:
		//-------------------
		CBCGPGridRange rangeSel = m_InsertRange;
		if (rangeSel.IsValid ())
		{
			CBCGPGridItemID idFirst (rangeSel.m_nTop);
			CBCGPGridItemID idSecond (rangeSel.m_nBottom);
			
			m_pOwnerGrid->SetCurSel (idFirst, SM_FIRST_CLICK | SM_SINGE_SEL_GROUP, FALSE);
			m_pOwnerGrid->SetCurSel (idSecond, SM_SECOND_CLICK | SM_CONTINUE_SEL_GROUP, TRUE);
		}
	}

 	CleanUpImplementationData ();

	return TRUE;
}