зеркало из https://github.com/mozilla/pjs.git
More table editing work: convert Excel spreadsheet to internal table format for more flexible paste options
This commit is contained in:
Родитель
f7c322de3f
Коммит
856a8dc5c8
|
@ -1024,6 +1024,11 @@ public:
|
|||
// Uses m_ColumnLayoutData and m_RowLayoutData
|
||||
void FixupColumnsAndRows();
|
||||
|
||||
// Add empty cells to each row so table looks rectangular
|
||||
// (each row has same number of "virtual" cells,
|
||||
// compensating for effects of COLSPAN and ROWSPAN
|
||||
void NormalizeCellsPerRow();
|
||||
|
||||
private:
|
||||
ED_Color m_backgroundColor;
|
||||
char* m_pBackgroundImage;
|
||||
|
@ -1175,12 +1180,12 @@ public:
|
|||
CEditTableCellElement(CEditElement *pParent, PA_Tag *pTag, int16 csid);
|
||||
CEditTableCellElement(IStreamIn *pStreamIn, CEditBuffer *pBuffer);
|
||||
virtual ~CEditTableCellElement();
|
||||
|
||||
virtual XP_Bool IsTableCell();
|
||||
static CEditTableCellElement* Cast(CEditElement* pElement) {
|
||||
return pElement && pElement->IsTableCell() ? (CEditTableCellElement*) pElement : 0; }
|
||||
virtual EEditElementType GetElementType();
|
||||
virtual ED_Alignment GetDefaultAlignment();
|
||||
void Unlink();
|
||||
|
||||
XP_Bool IsTableData();
|
||||
|
||||
|
@ -1267,6 +1272,8 @@ public:
|
|||
|
||||
int32 GetX() { return m_X; }
|
||||
int32 GetY() { return m_Y; }
|
||||
void SetX(int32 x) { m_X = x; }
|
||||
void SetY(int32 y) { m_Y = y; }
|
||||
intn GetRow() { return m_iRow; }
|
||||
int32 GetWidth() { return m_iWidthPixels; }
|
||||
int32 GetHeight() { return m_iHeightPixels; }
|
||||
|
|
|
@ -13040,21 +13040,22 @@ NORMAL_PASTE:
|
|||
// Delete table or cells in original location if moving within the doc
|
||||
if( m_bDeleteTableAfterPasting )
|
||||
{
|
||||
// The only way to end up here is if we are
|
||||
// pasting as a new table
|
||||
XP_ASSERT(m_pSelectedEdTable);
|
||||
if( m_pSelectedEdTable )
|
||||
{
|
||||
// Delete the entire table.
|
||||
// FALSE = don't reposition insert point
|
||||
m_pSelectedEdTable->Delete(FALSE);
|
||||
}
|
||||
#if 0
|
||||
else if( m_SelectedEdCells.Size() )
|
||||
{
|
||||
// We must save and restore current insert point
|
||||
// because DeleteSelectedCells will move it
|
||||
// to the table whose cells are deleted
|
||||
CEditInsertPoint ip;
|
||||
GetInsertPoint(ip);
|
||||
DeleteSelectedCells();
|
||||
SetInsertPoint(ip);
|
||||
}
|
||||
#endif
|
||||
m_bDeleteTableAfterPasting = FALSE;
|
||||
}
|
||||
|
||||
|
@ -13120,6 +13121,85 @@ BAD_CLIPBOARD:
|
|||
|
||||
#define EDT_PASTE_ROW(t) (t == ED_PASTE_ROW_ABOVE || t == ED_PASTE_ROW_BELOW)
|
||||
#define EDT_PASTE_COLUMN(t) (t == ED_PASTE_COLUMN_BEFORE || t == ED_PASTE_COLUMN_AFTER)
|
||||
#define END_OF_TABLE(pEle) (pEle == NULL || pEle->type == LO_LINEFEED)
|
||||
|
||||
// Returns TRUE if there is another row to process
|
||||
// (pLoEle points to first cell on next row, and iRowY is updated)
|
||||
static XP_Bool edt_SetSpecialSelectRow(MWContext *pMWContext, LO_Element*& pLoEle, int32 iCellsInRow,
|
||||
int32 iFirstColX, int32& iRowY )
|
||||
{
|
||||
// Find first LO cell at appropriate column in each row to be marked
|
||||
while(TRUE)
|
||||
{
|
||||
if( pLoEle && pLoEle->type == LO_CELL && pLoEle->lo_cell.x >= iFirstColX )
|
||||
break;
|
||||
pLoEle = pLoEle->lo_any.next;
|
||||
}
|
||||
if(END_OF_TABLE(pLoEle))
|
||||
return FALSE;
|
||||
|
||||
XP_ASSERT(pLoEle && pLoEle->type == LO_CELL & iRowY == pLoEle->lo_cell.y );
|
||||
|
||||
for( intn i = 0; i< iCellsInRow; i++ )
|
||||
{
|
||||
if(END_OF_TABLE(pLoEle))
|
||||
return FALSE;
|
||||
LO_CellStruct *pLoCell = (LO_CellStruct*)pLoEle;
|
||||
// Check if cell is in proper row
|
||||
if( pLoCell->y != iRowY )
|
||||
// We are in another row - get out
|
||||
break;
|
||||
|
||||
// Mark cell with special selection
|
||||
pLoCell->ele_attrmask |= LO_ELE_SELECTED_SPECIAL;
|
||||
FE_DisplayEntireTableOrCell(pMWContext, pLoEle);
|
||||
|
||||
// Set flag in Editor's cell elements
|
||||
CEditTableCellElement *pEdCell =
|
||||
(CEditTableCellElement*)edt_GetTableElementFromLO_Element(pLoEle, LO_CELL);
|
||||
if( pEdCell )
|
||||
pEdCell->SetSpecialSelected(TRUE);
|
||||
#ifdef DEBUG
|
||||
else
|
||||
XP_ASSERT(FALSE);
|
||||
#endif
|
||||
|
||||
// Move to next table cell
|
||||
pLoEle = pLoEle->lo_any.next;
|
||||
while(!END_OF_TABLE(pLoEle))
|
||||
{
|
||||
if( pLoEle->type == LO_CELL )
|
||||
break;
|
||||
pLoEle = pLoEle->lo_any.next;
|
||||
}
|
||||
}
|
||||
// Check if done because no more cells
|
||||
if(END_OF_TABLE(pLoEle))
|
||||
return FALSE;
|
||||
|
||||
// We are done marking cells in this row
|
||||
// move to next row unless already there
|
||||
if( pLoEle->type == LO_CELL && pLoEle->lo_cell.y == iRowY )
|
||||
{
|
||||
pLoEle = pLoEle->lo_any.next;
|
||||
while(!END_OF_TABLE(pLoEle))
|
||||
{
|
||||
if( pLoEle->type == LO_CELL && pLoEle->lo_cell.y != iRowY )
|
||||
break;
|
||||
pLoEle = pLoEle->lo_any.next;
|
||||
}
|
||||
}
|
||||
if(END_OF_TABLE(pLoEle))
|
||||
return FALSE;
|
||||
|
||||
// If here, pLoEle should be first cell in next row to mark
|
||||
XP_ASSERT(pLoEle && pLoEle->type == LO_CELL);
|
||||
|
||||
// Set top of next row
|
||||
iRowY = pLoEle->lo_cell.y;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void CEditBuffer::PasteTable( CEditTableCellElement *pCell, CEditTableElement *pSourceTable, ED_PasteType iPasteType )
|
||||
{
|
||||
|
@ -13136,32 +13216,67 @@ void CEditBuffer::PasteTable( CEditTableCellElement *pCell, CEditTableElement *p
|
|||
XP_Bool bAfterCurrentCell = (iPasteType == ED_PASTE_COLUMN_AFTER ||
|
||||
iPasteType == ED_PASTE_ROW_BELOW );
|
||||
|
||||
// Note: These values counts COLSPAN and ROWSPAN,
|
||||
// so this is number of "virtual" columns or rows
|
||||
// [Be sure pasting routines can handle missing cells]
|
||||
int32 X = pCell->GetX();
|
||||
int32 Y = pCell->GetY();
|
||||
int32 iNewX = X + (bAfterCurrentCell ? pCell->GetFullWidth() : 0); // GetFullWidth is used in edtcmd.cpp routines
|
||||
int32 iNewX = X + (bAfterCurrentCell ? pCell->GetFullWidth() : 0);
|
||||
int32 iNewY = Y + (bAfterCurrentCell ? pCell->GetHeight() : 0);
|
||||
|
||||
// Should always be 0 initially - lets test it
|
||||
XP_ASSERT(m_pCellForInsertPoint == NULL);
|
||||
m_pCellForInsertPoint = NULL;
|
||||
|
||||
if( iPasteType == ED_PASTE_REPLACE_CELLS )
|
||||
// For now, ignore source layout when pasting over a user-selection
|
||||
// When drag/dropping, lets assume we predicted the destination layout correctly
|
||||
// TODO: ONLY IGNORE SOURCE LAYOUT FOR CERTAIN COPY TYPES?
|
||||
XP_Bool bIgnoreSourceLayout = (m_pDragTableData == NULL);
|
||||
|
||||
if( iPasteType == ED_PASTE_REPLACE_CELLS ||
|
||||
(pCell->IsSelected() && iPasteType == ED_PASTE_NORMAL) )
|
||||
{
|
||||
if( !m_pDragTableData )
|
||||
{
|
||||
if( m_SelectedEdCells.Size() > 0 )
|
||||
{
|
||||
// We are pasting over current selected cells only
|
||||
// Set all selected cells to the "special selection" mode,
|
||||
// which happens with DragNDrop as well
|
||||
// Set all selected cells to the "special selection" mode
|
||||
DisplaySpecialCellSelection();
|
||||
}
|
||||
// Second param is bIgnoreSourceLayout
|
||||
// For now, use that when pasting over a user-selection
|
||||
// When drag/dropping, lets assume we predicted the destination layout correctly
|
||||
// TODO: ONLY IGNORE SOURCE LAYOUT FOR CERTAIN COPY TYPES?
|
||||
bAllCellsPasted = pTable->ReplaceSpecialCells(pSourceTable, !m_pDragTableData,
|
||||
else
|
||||
{
|
||||
// Replace as if we were dragging -
|
||||
// start special selection with current cell
|
||||
// and mark cells according to pattern in the source table
|
||||
bIgnoreSourceLayout = FALSE;
|
||||
|
||||
CEditTableRowElement *pSourceRow = pSourceTable->GetFirstRow();
|
||||
LO_Element *pLoEle = (LO_Element*)GetLoCell((CEditElement*)pCell);
|
||||
if( !pLoEle || !pSourceRow )
|
||||
return;
|
||||
// This will get updated by edt_SetSpecialSelectRow
|
||||
int32 iRowY = pLoEle->lo_cell.y;
|
||||
while( pSourceRow )
|
||||
{
|
||||
// Count cells in each source row
|
||||
// We DON'T want to pay attention to COLSPAN and ROWSPAN
|
||||
int32 iCellsInRow = 0;
|
||||
CEditElement *pSourceCell = pSourceRow->GetChild();
|
||||
while( pSourceCell )
|
||||
{
|
||||
XP_ASSERT(pSourceCell->IsTableCell());
|
||||
iCellsInRow++;
|
||||
pSourceCell = pSourceCell->GetNextSibling();
|
||||
}
|
||||
// This code is shared with SetReplaceCellSelection(),
|
||||
|
||||
if( !edt_SetSpecialSelectRow(m_pContext, pLoEle, iCellsInRow,
|
||||
pLoEle->lo_cell.x, iRowY) )
|
||||
break;
|
||||
|
||||
pSourceRow = pSourceRow->GetNextRow();
|
||||
}
|
||||
}
|
||||
}
|
||||
bAllCellsPasted = pTable->ReplaceSpecialCells(pSourceTable, bIgnoreSourceLayout,
|
||||
&m_pCellForInsertPoint);
|
||||
}
|
||||
else if( EDT_PASTE_ROW(iPasteType) )
|
||||
|
@ -13314,48 +13429,85 @@ EDT_ClipboardResult CEditBuffer::PasteTextAsTable(char *pText, ED_PasteType iPas
|
|||
if( iRows == 0 || iCols == 0 )
|
||||
CountRowsAndColsInPasteText(pText, &iRows, &iCols);
|
||||
|
||||
if( iPasteType == ED_PASTE_NORMAL || iRows == 0 || iCols == 0 )
|
||||
if( iPasteType == ED_PASTE_IMAGE || (iRows <= 0 || iCols <= 0) )
|
||||
return EDT_COP_CLIPBOARD_BAD;
|
||||
|
||||
XP_Bool bNewTable = (iPasteType == ED_PASTE_NORMAL);
|
||||
|
||||
EDT_TableData *pData = bNewTable ? EDT_NewTableData() : GetTableData();
|
||||
|
||||
CEditTableElement *pDebugTable = NULL; // ******* DEBUG TEST ONLY
|
||||
|
||||
// TODO: REWRITE THIS -- BUILD A TABLE AND INSERT TEXT,
|
||||
// THEN CALL CEditBuffer::PasteTable()
|
||||
if( pData )
|
||||
// We really shouldn't be called with this, but we know what to do with it
|
||||
if( iPasteType == ED_PASTE_TEXT )
|
||||
{
|
||||
if( bNewTable )
|
||||
{
|
||||
pData->iRows = iRows;
|
||||
pData->iColumns = iCols;
|
||||
InsertTable(pData);
|
||||
EDT_FreeTableData(pData);
|
||||
// We assume InsertTable will put caret in first cell of table
|
||||
CEditInsertPoint ip;
|
||||
GetTableInsertPoint(ip);
|
||||
pDebugTable = ip.m_pElement->GetTableIgnoreSubdoc();
|
||||
// 2nd to last param = don't relayout, last param = we want to reduce
|
||||
return PasteText(pText, FALSE, FALSE, TRUE, TRUE);
|
||||
}
|
||||
CEditTableElement *pTable = m_pCurrent->GetTableIgnoreSubdoc();
|
||||
CEditInsertPoint ip;
|
||||
GetTableInsertPoint(ip);
|
||||
|
||||
int32 iRow = 0;
|
||||
|
||||
if( pTable )
|
||||
// Decide default behavior:
|
||||
if( iPasteType == ED_PASTE_NORMAL )
|
||||
{
|
||||
CEditTableCellElement* pNextCell = bNewTable ?
|
||||
pTable->GetFirstCell() : m_pCurrent->GetParentTableCell();
|
||||
if( IsInsertPointInTable() )
|
||||
{
|
||||
CEditTableCellElement *pCell = m_pCurrent->GetParentTableCell();
|
||||
// Replace selected cells if trying to paste over them
|
||||
if( pCell && pCell->IsSelected() )
|
||||
iPasteType = ED_PASTE_REPLACE_CELLS;
|
||||
else
|
||||
// Use shape of source to decide to paste row vs. column
|
||||
iPasteType = (iRows > iCols) ? ED_PASTE_ROW_ABOVE : ED_PASTE_COLUMN_BEFORE;
|
||||
}
|
||||
else
|
||||
iPasteType = ED_PASTE_TABLE;
|
||||
}
|
||||
XP_Bool bInsertFullTable = (iPasteType == ED_PASTE_TABLE );
|
||||
|
||||
// Create a new table
|
||||
// This will either be inserted whole or used as the
|
||||
// source table for row/column pasting into existing table
|
||||
CEditTableElement *pTable = NULL;
|
||||
|
||||
if( bInsertFullTable )
|
||||
{
|
||||
// Create table using default setting for new table
|
||||
EDT_TableData *pData = EDT_NewTableData();
|
||||
if( !pData )
|
||||
return EDT_COP_CLIPBOARD_BAD;
|
||||
pData->iColumns = iCols;
|
||||
pData->iRows = iRows;
|
||||
pTable = InsertTable(pData);
|
||||
EDT_FreeTableData(pData);
|
||||
}
|
||||
else
|
||||
{
|
||||
XP_ASSERT( IsInsertPointInTable());
|
||||
if( !IsInsertPointInTable() )
|
||||
return EDT_COP_CLIPBOARD_BAD;
|
||||
// Just a temporary table to hold text data
|
||||
pTable = new CEditTableElement( iCols, iRows);
|
||||
}
|
||||
|
||||
if( !pTable )
|
||||
return EDT_COP_CLIPBOARD_BAD;
|
||||
|
||||
// Set default text in each cell
|
||||
SetFillNewCellWithSpace();
|
||||
pTable->FinishedLoad(this);
|
||||
ClearFillNewCellWithSpace();
|
||||
|
||||
CEditTableCellElement* pFirstCell = pTable->GetFirstCell();
|
||||
XP_ASSERT(pFirstCell);
|
||||
CEditTableCellElement* pCell = pFirstCell;
|
||||
intn iRow = 0;
|
||||
intn iPrevRow = 0;
|
||||
// This is actually used as the X value for
|
||||
// each cell created. We know we have "normal"
|
||||
// array of cells so this allows CountColumns() to work when pasting
|
||||
int32 iCol = 0;
|
||||
|
||||
char *pCellText = pText;
|
||||
XP_Bool bDone = FALSE;
|
||||
XP_Bool bEndOfRow = FALSE;
|
||||
|
||||
while(!bDone)
|
||||
while(TRUE)
|
||||
{
|
||||
// Get one token of text from the string
|
||||
do
|
||||
{
|
||||
do {
|
||||
char current = *pText;
|
||||
if( current == 9)
|
||||
{
|
||||
|
@ -13387,55 +13539,66 @@ EDT_ClipboardResult CEditBuffer::PasteTextAsTable(char *pText, ED_PasteType iPas
|
|||
pText++;
|
||||
} while( pText );
|
||||
|
||||
// We fake X,Y coordinates for cells so
|
||||
// CountColumns() will work correctly when pasting
|
||||
pCell->SetX(iCol++);
|
||||
|
||||
if( pCellText && *pCellText )
|
||||
// 2nd to last param = don't relayout, last param = we want to reduce
|
||||
PasteText(pCellText, FALSE, FALSE, FALSE, TRUE);
|
||||
|
||||
intn iNextRow = iRow;
|
||||
|
||||
// Move insert point to next cell, caret at end of contents
|
||||
// If its in next row, iNextRow will be incremented
|
||||
if( NextTableCell(TRUE, TRUE, &iNextRow) )
|
||||
{
|
||||
// Get the existing empty text element in the table
|
||||
CEditTextElement *pText = pCell->GetFirstMostChild()->Text();
|
||||
pText->SetText(pCellText);
|
||||
}
|
||||
|
||||
if(bEndOfRow)
|
||||
{
|
||||
// Next item should go into next row
|
||||
iRow++;
|
||||
// If we have a short row (fewer tabs than maximum),
|
||||
// skip to first cell of next row
|
||||
XP_Bool bGetNext = TRUE;
|
||||
while( bGetNext && iRow != iNextRow )
|
||||
while( pCell && iRow == iPrevRow )
|
||||
{
|
||||
bGetNext = NextTableCell(TRUE, TRUE, &iNextRow);
|
||||
pCell = pCell->GetNextCellInTable(&iRow);
|
||||
if(pCell)
|
||||
pCell->SetX(iCol++);
|
||||
}
|
||||
bEndOfRow = FALSE;
|
||||
iPrevRow = iRow;
|
||||
iCol = 0;
|
||||
}
|
||||
else if( iRow != iNextRow )
|
||||
else
|
||||
{
|
||||
// Should never happen - we are in next row of new table,
|
||||
// but we're not at end of text "row"
|
||||
pCell = pCell->GetNextCellInTable(&iRow);
|
||||
if( iRow != iPrevRow )
|
||||
{
|
||||
// We are in next row, but there's still text in source
|
||||
// SHOULD NEVER HAPPEN if CountRowsAndColsInPasteText is working
|
||||
XP_ASSERT(FALSE);
|
||||
iPrevRow = iRow;
|
||||
iCol = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// The next cell item starts at next character
|
||||
pCellText = pText;
|
||||
|
||||
if( *pText == '\0' )
|
||||
bDone = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
//TODO: We should probably test if any text is left
|
||||
// here - there shouldn't be any
|
||||
bDone = TRUE;
|
||||
}
|
||||
} //while(!bDone)
|
||||
if( !pCell || *pText == '\0' )
|
||||
break;
|
||||
|
||||
// Return insert point to the first cell
|
||||
SetInsertPoint(ip);
|
||||
}
|
||||
//TODO: We should probably trigger the "Not all cells were pasted" message
|
||||
// if there's still source text left to paste
|
||||
|
||||
if( bInsertFullTable )
|
||||
{
|
||||
// Set insert point inside first cell in table
|
||||
SetTableInsertPoint(pFirstCell);
|
||||
// Relayout the entire table
|
||||
Relayout(pTable, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Insert rows or cols -- this will Relayout the table
|
||||
pCell = m_pCurrent->GetParentTableCell();
|
||||
PasteTable(pCell, pTable, iPasteType);
|
||||
}
|
||||
|
||||
return EDT_COP_OK;
|
||||
|
@ -15528,8 +15691,6 @@ void CEditBuffer::StartSpecialCellSelection(EDT_TableCellData *pCellData)
|
|||
DisplaySpecialCellSelection( pEdCell, pCellData );
|
||||
}
|
||||
|
||||
#define END_OF_TABLE(pEle) (pEle == NULL || pEle->type == LO_LINEFEED)
|
||||
|
||||
void CEditBuffer::SetReplaceCellSelection()
|
||||
{
|
||||
if( !m_pDragTableData || !m_pDragTableData->pDragOverCell || m_pDragTableData->iRows <= 0 || !m_pDragTableData->pCellsPerRow )
|
||||
|
@ -15549,120 +15710,17 @@ void CEditBuffer::SetReplaceCellSelection()
|
|||
// Reset replace cell
|
||||
edt_pPrevReplaceCellSelected = m_pDragTableData->pDragOverCell;
|
||||
|
||||
// Copy array so we can decrement values as we mark cells
|
||||
int32 *pSourceCellsLeftInRow = (int32*)XP_ALLOC(m_pDragTableData->iRows * sizeof(int32));
|
||||
XP_ASSERT(pSourceCellsLeftInRow);
|
||||
if(!pSourceCellsLeftInRow)
|
||||
return;
|
||||
intn i;
|
||||
for( i = 0; i < m_pDragTableData->iRows; i++)
|
||||
pSourceCellsLeftInRow[i] = m_pDragTableData->pCellsPerRow[i];
|
||||
LO_Element *pLoEle = m_pDragTableData->pDragOverCell;
|
||||
// This will get updated by edt_SetSpecialSelectRow for each row
|
||||
int32 iRowY = pLoEle->lo_cell.y;
|
||||
|
||||
LO_Element *pEle = m_pDragTableData->pDragOverCell;
|
||||
int32 iRowY = pEle->lo_cell.y;
|
||||
int32 iFirstColX = pEle->lo_cell.x;
|
||||
|
||||
intn iRow;
|
||||
for( iRow = 0; iRow < m_pDragTableData->iRows; iRow++ )
|
||||
for( intn iRow = 0; iRow < m_pDragTableData->iRows; iRow++ )
|
||||
{
|
||||
// Find first cell at appropriate column in each row to be marked
|
||||
while(TRUE)
|
||||
{
|
||||
if( pEle && pEle->type == LO_CELL && pEle->lo_cell.x >= iFirstColX )
|
||||
// Most of the code is shared with section in PasteTable() for replace cell logic
|
||||
if( !edt_SetSpecialSelectRow(m_pContext, pLoEle, m_pDragTableData->pCellsPerRow[iRow],
|
||||
pLoEle->lo_cell.x, iRowY) )
|
||||
break;
|
||||
pEle = pEle->lo_any.next;
|
||||
}
|
||||
if(END_OF_TABLE(pEle))
|
||||
break;
|
||||
|
||||
XP_ASSERT(pEle && pEle->type == LO_CELL & iRowY == pEle->lo_cell.y );
|
||||
|
||||
while(pSourceCellsLeftInRow[iRow])
|
||||
{
|
||||
if(END_OF_TABLE(pEle))
|
||||
break;
|
||||
LO_CellStruct *pLoCell = (LO_CellStruct*)pEle;
|
||||
// Check if cell is in proper row
|
||||
if( pLoCell->y != iRowY )
|
||||
// We are in another row - get out
|
||||
break;
|
||||
|
||||
#if 0
|
||||
// Because we decided to ignore the COLSPAN and ROWSPAN of the source
|
||||
// cells, and use that of the destination, we don't need to
|
||||
// get fancy here. The following matches geometry of source to
|
||||
// destination by considering COLSPAN and ROWSPAN
|
||||
|
||||
int32 iColSpan = lo_GetColSpan(pEle);
|
||||
int32 iRowSpan = lo_GetRowSpan(pEle);
|
||||
// Adjust for effect of rowspan on number of cells in following rows
|
||||
if( iRowSpan > 1 )
|
||||
{
|
||||
for( intn j = 1; j < iRowSpan; j++ )
|
||||
{
|
||||
if( iColSpan < pSourceCellsLeftInRow[j] )
|
||||
pSourceCellsLeftInRow[j] -= iColSpan;
|
||||
else
|
||||
pSourceCellsLeftInRow[j] = 0;
|
||||
}
|
||||
}
|
||||
// Reduce the count of cells left to mark
|
||||
if( iColSpan < pSourceCellsLeftInRow[iRow] )
|
||||
pSourceCellsLeftInRow[iRow] -= iColSpan;
|
||||
else
|
||||
pSourceCellsLeftInRow[iRow] = 0;
|
||||
#endif
|
||||
// Because we decided to ignore the COLSPAN
|
||||
pSourceCellsLeftInRow[iRow]--;
|
||||
|
||||
// Mark cell with special selection
|
||||
pLoCell->ele_attrmask |= LO_ELE_SELECTED_SPECIAL;
|
||||
FE_DisplayEntireTableOrCell(m_pContext, pEle);
|
||||
|
||||
// Set flag in Editor's cell elements
|
||||
CEditTableCellElement *pEdCell =
|
||||
(CEditTableCellElement*)edt_GetTableElementFromLO_Element(pEle, LO_CELL);
|
||||
if( pEdCell )
|
||||
pEdCell->SetSpecialSelected(TRUE);
|
||||
#ifdef DEBUG
|
||||
else
|
||||
XP_ASSERT(FALSE);
|
||||
#endif
|
||||
|
||||
// Move to next table cell
|
||||
pEle = pEle->lo_any.next;
|
||||
while(!END_OF_TABLE(pEle))
|
||||
{
|
||||
if( pEle->type == LO_CELL )
|
||||
break;
|
||||
pEle = pEle->lo_any.next;
|
||||
}
|
||||
}
|
||||
// Check if done because no more cells
|
||||
if(END_OF_TABLE(pEle))
|
||||
break;
|
||||
|
||||
// We are done marking cells in this row
|
||||
// move to next row unless already there
|
||||
if( pEle->type == LO_CELL && pEle->lo_cell.y == iRowY )
|
||||
{
|
||||
pEle = pEle->lo_any.next;
|
||||
while(!END_OF_TABLE(pEle))
|
||||
{
|
||||
if( pEle->type == LO_CELL && pEle->lo_cell.y != iRowY )
|
||||
break;
|
||||
pEle = pEle->lo_any.next;
|
||||
}
|
||||
}
|
||||
if(END_OF_TABLE(pEle))
|
||||
break;
|
||||
|
||||
// If here, pEle should be first cell in next row to mark
|
||||
XP_ASSERT(pEle && pEle->type == LO_CELL);
|
||||
// Get top of next row
|
||||
iRowY = pEle->lo_cell.y;
|
||||
}
|
||||
XP_FREE(pSourceCellsLeftInRow);
|
||||
}
|
||||
|
||||
void CEditBuffer::ClearSpecialCellSelection(LO_Element *pDragOverCell)
|
||||
|
|
|
@ -1055,7 +1055,13 @@ CDeleteTableRowCommand::CDeleteTableRowCommand(CEditBuffer* pBuffer, intn rows,
|
|||
pBuffer->m_pCellForInsertPoint = 0;
|
||||
pTable->DeleteRows(Y, rows, &pBuffer->m_pCellForInsertPoint);
|
||||
pTable->FinishedLoad(pBuffer);
|
||||
if( pBuffer->m_pCellForInsertPoint == NULL )
|
||||
{
|
||||
// Move to a safe location so Relayout() doesn't assert
|
||||
CEditElement *pLeaf = pTable->FindPreviousElement(&CEditElement::FindLeafAll, 0 );
|
||||
if( pLeaf )
|
||||
pBuffer->SetInsertPoint(pLeaf->Leaf(), 0, pBuffer->m_bCurrentStickyAfter);
|
||||
}
|
||||
pBuffer->Relayout(pTable, 0, NULL, RELAYOUT_NOCARET);
|
||||
}
|
||||
}
|
||||
|
@ -1129,7 +1135,13 @@ CDeleteTableColumnCommand::CDeleteTableColumnCommand(CEditBuffer* pBuffer, intn
|
|||
// We don't save the table to undo any more
|
||||
pTable->DeleteColumns(X, columns, &pBuffer->m_pCellForInsertPoint );
|
||||
pTable->FinishedLoad(pBuffer);
|
||||
if( pBuffer->m_pCellForInsertPoint == NULL )
|
||||
{
|
||||
// Move to a safe location so Relayout() doesn't assert
|
||||
CEditElement *pLeaf = pTable->FindPreviousElement(&CEditElement::FindLeafAll, 0 );
|
||||
if( pLeaf )
|
||||
pBuffer->SetInsertPoint(pLeaf->Leaf(), 0, pBuffer->m_bCurrentStickyAfter);
|
||||
}
|
||||
pBuffer->Relayout(pTable, 0, NULL, RELAYOUT_NOCARET);
|
||||
}
|
||||
}
|
||||
|
@ -1205,7 +1217,13 @@ CDeleteTableCellCommand::CDeleteTableCellCommand(CEditBuffer* pBuffer, intn colu
|
|||
pBuffer->m_pCellForInsertPoint = 0;
|
||||
pTableRow->DeleteCells(X, columns, &pBuffer->m_pCellForInsertPoint);
|
||||
pTable->FinishedLoad(pBuffer);
|
||||
if( pBuffer->m_pCellForInsertPoint == NULL )
|
||||
{
|
||||
// Move to a safe location so Relayout() doesn't assert
|
||||
CEditElement *pLeaf = pTable->FindPreviousElement(&CEditElement::FindLeafAll, 0 );
|
||||
if( pLeaf )
|
||||
pBuffer->SetInsertPoint(pLeaf->Leaf(), 0, pBuffer->m_bCurrentStickyAfter);
|
||||
}
|
||||
pBuffer->Relayout(pTable, 0, NULL, RELAYOUT_NOCARET);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2718,6 +2718,90 @@ void CEditTableElement::FixupColumnsAndRows()
|
|||
}
|
||||
}
|
||||
|
||||
void CEditTableElement::NormalizeCellsPerRow()
|
||||
{
|
||||
CEditTableCellElement *pFirstCell = GetFirstCell();
|
||||
CEditBuffer *pBuffer = GetEditBuffer();
|
||||
if( !pFirstCell || !pBuffer )
|
||||
return;
|
||||
|
||||
int32 iRows = CountRows();
|
||||
int32 iArraySize = iRows * sizeof(int32);
|
||||
int32 *pCellsPerRow = (int32*)XP_ALLOC(iArraySize);
|
||||
if( !pCellsPerRow )
|
||||
return;
|
||||
|
||||
XP_MEMSET( pCellsPerRow, 0, iArraySize );
|
||||
|
||||
CEditTableCellElement *pCell = pFirstCell;
|
||||
intn iRow = 0;
|
||||
intn iPrevRow = 0;
|
||||
int32 iCellsInRow = 0;
|
||||
|
||||
while( pCell )
|
||||
{
|
||||
intn iColSpan = pCell->GetColSpan();
|
||||
intn iRowSpan = pCell->GetRowSpan();
|
||||
|
||||
pCellsPerRow[iRow] += iColSpan;
|
||||
|
||||
// Fixup subsequent rows because of rowspan
|
||||
if( iRowSpan > 1 )
|
||||
{
|
||||
for( intn j = 1; j < iRowSpan; j++ )
|
||||
{
|
||||
// We may overrun our array if table is "bad"
|
||||
// because of a ROWSPAN value that exceeds actual
|
||||
// number of rows. Just skip attempts to access a value too high
|
||||
// since there is no row to use the "ExtraColumns" anyway.
|
||||
if( iRow+j < iRows )
|
||||
pCellsPerRow[iRow+j] += iColSpan;
|
||||
else
|
||||
// Fixup bad cell????
|
||||
;//pCell->SetRowSpan(iRows-1);
|
||||
}
|
||||
}
|
||||
pCell = pCell->GetNextCellInTable(&iRow);
|
||||
}
|
||||
|
||||
XP_ASSERT((iRow+1) == iRows); // Safety check
|
||||
|
||||
// Find the maximum cells per row
|
||||
intn iTotalRows = pCellsPerRow[0];
|
||||
intn i;
|
||||
|
||||
for( i = 1; i < iRows; i++ )
|
||||
{
|
||||
if( pCellsPerRow[i] > iTotalRows )
|
||||
iTotalRows = pCellsPerRow[i];
|
||||
}
|
||||
|
||||
pBuffer->SetFillNewCellWithSpace();
|
||||
CEditTableRowElement *pRow = GetFirstRow();
|
||||
|
||||
// Now go through rows and add cells as needed
|
||||
for( i = 0; i < iRows; i++ )
|
||||
{
|
||||
XP_ASSERT(pRow);
|
||||
if( !pRow )
|
||||
break;
|
||||
|
||||
intn iExtraCells = iTotalRows - pCellsPerRow[i];
|
||||
for( intn i = 0; i < iExtraCells; i++ )
|
||||
{
|
||||
CEditTableCellElement *pNewCell = new CEditTableCellElement();
|
||||
if( pNewCell )
|
||||
{
|
||||
// What could we set this to to make CountColumns() work?
|
||||
//pNewCell->SetX(????);
|
||||
pNewCell->InsertAsLastChild(pRow);
|
||||
pNewCell->FinishedLoad(pBuffer);
|
||||
}
|
||||
}
|
||||
pRow = pRow->GetNextRow();
|
||||
}
|
||||
pBuffer->ClearFillNewCellWithSpace();
|
||||
}
|
||||
|
||||
void CEditTableElement::InsertRows(int32 Y, int32 iNewY, intn number,
|
||||
CEditTableElement* pSourceTable, intn iStartColumn,
|
||||
|
@ -2748,28 +2832,29 @@ void CEditTableElement::InsertRows(int32 Y, int32 iNewY, intn number,
|
|||
CEditBuffer *pBuffer = GetEditBuffer();
|
||||
XP_ASSERT(pBuffer);
|
||||
CEditTableCellElement *pCellForInsertPoint = NULL;
|
||||
if( pSourceTable )
|
||||
pCellForInsertPoint = pSourceTable->GetFirstCell();
|
||||
int32 iCurrentColumns = GetColumns();
|
||||
int32 iTotalColumns = iCurrentColumns;
|
||||
// Set to the total to simplify test padding the rows near end of function
|
||||
int32 iSourceColumns = iTotalColumns;
|
||||
|
||||
if( pSourceTable && iStartColumn > 0 )
|
||||
if( pSourceTable )
|
||||
{
|
||||
iSourceColumns = pSourceTable->CountColumns();
|
||||
CEditTableRowElement *pSourceRow;
|
||||
// If inserted rows will require new columns,
|
||||
// figure that out now and add the necessary columns
|
||||
int32 iTotalColumns = iStartColumn + pSourceTable->CountColumns();
|
||||
if( iTotalColumns > GetColumns() )
|
||||
{
|
||||
CEditTableRowElement *pTableRow = GetFirstRow();
|
||||
while( pTableRow )
|
||||
{
|
||||
pTableRow->PadRowWithEmptyCells(iTotalColumns);
|
||||
pTableRow = (CEditTableRowElement*)pTableRow->GetNextSibling();
|
||||
}
|
||||
}
|
||||
// Figure the total number of columns in table after inserting
|
||||
iTotalColumns = max(iCurrentColumns, iStartColumn + pSourceTable->CountColumns());
|
||||
|
||||
// Set flag to autoinsert space into new cells according to pref
|
||||
if( iStartColumn > 0 )
|
||||
{
|
||||
// Set flag to autoinsert space into
|
||||
// the blank new cells we will insert here
|
||||
pBuffer->SetFillNewCellWithSpace();
|
||||
//Simplest way to handle this is to add blank cells to the source data
|
||||
CEditTableRowElement* pSourceRow = pSourceTable->GetFirstRow();
|
||||
|
||||
//Simplest way to handle offset insert column
|
||||
// is to add blank cells to the source data
|
||||
pSourceRow = pSourceTable->GetFirstRow();
|
||||
while(pSourceRow)
|
||||
{
|
||||
for( intn i = 0; i < iStartColumn; i++ )
|
||||
|
@ -2777,14 +2862,20 @@ void CEditTableElement::InsertRows(int32 Y, int32 iNewY, intn number,
|
|||
CEditTableCellElement *pNewCell = new CEditTableCellElement();
|
||||
if( pNewCell )
|
||||
{
|
||||
// Fake the X value so CountColumns will work
|
||||
pNewCell->SetX(iStartColumn - i);
|
||||
pNewCell->InsertAsFirstChild(pSourceRow);
|
||||
pNewCell->FinishedLoad(pBuffer);
|
||||
}
|
||||
}
|
||||
pSourceRow = (CEditTableRowElement*)pSourceRow->GetNextSibling();
|
||||
}
|
||||
// Clear this so we don't touch empty cells
|
||||
// from the paste source
|
||||
pBuffer->ClearFillNewCellWithSpace();
|
||||
}
|
||||
iSourceColumns += iStartColumn;
|
||||
}
|
||||
|
||||
CEditTableCellElement *pCell = GetFirstCellInRow(Y, FALSE );
|
||||
while( pCell )
|
||||
|
@ -2819,32 +2910,43 @@ void CEditTableElement::InsertRows(int32 Y, int32 iNewY, intn number,
|
|||
pCell = GetNextCellInRow();
|
||||
}
|
||||
|
||||
XP_ASSERT(iColumns == iCurrentColumns);
|
||||
|
||||
// Now insert the new rows (including iColumns new cells in each)
|
||||
for ( intn row = 0; row < number; row++ )
|
||||
{
|
||||
CEditTableRowElement* pNewRow;
|
||||
if ( pSourceTable ) {
|
||||
if ( pSourceTable )
|
||||
{
|
||||
pNewRow = pSourceTable->GetFirstRow();
|
||||
pNewRow->Unlink();
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
pNewRow = new CEditTableRowElement(iColumns);
|
||||
if( !pNewRow )
|
||||
break;
|
||||
|
||||
pBuffer->SetFillNewCellWithSpace();
|
||||
}
|
||||
// Set insert point to first cell in inserted rows
|
||||
if( !pCellForInsertPoint )
|
||||
pCellForInsertPoint = pNewRow->GetFirstCell();
|
||||
}
|
||||
|
||||
if( Y == iNewY )
|
||||
pNewRow->InsertBefore(pCurrentRow);
|
||||
else
|
||||
{
|
||||
pNewRow->InsertAfter(pCurrentRow);
|
||||
pCurrentRow = pNewRow;
|
||||
}
|
||||
|
||||
pNewRow->FinishedLoad(pBuffer);
|
||||
}
|
||||
pBuffer->ClearFillNewCellWithSpace();
|
||||
|
||||
// if( (iSourceColumns < iTotalColumns) ||
|
||||
// (iCurrentColumns < iTotalColumns) )
|
||||
|
||||
// Do this all the time?
|
||||
NormalizeCellsPerRow();
|
||||
|
||||
if( ppCellForInsertPoint && *ppCellForInsertPoint == NULL )
|
||||
*ppCellForInsertPoint = pCellForInsertPoint;
|
||||
|
@ -2954,7 +3056,8 @@ void CEditTableElement::InsertColumns(int32 X, int32 iNewX, intn number,
|
|||
if( pNextRow )
|
||||
{
|
||||
// Fill in rest of row with empty cells
|
||||
pNextRow->PadRowWithEmptyCells(iTotalColumns);
|
||||
// DOESN'T WORK WITH ROW NOT ALREADY LAYED OUT
|
||||
//pNextRow->PadRowWithEmptyCells(iTotalColumns);
|
||||
// Be sure any empty cells have required empty text elements
|
||||
pNextRow->FinishedLoad(pBuffer);
|
||||
}
|
||||
|
@ -2963,6 +3066,7 @@ void CEditTableElement::InsertColumns(int32 X, int32 iNewX, intn number,
|
|||
}
|
||||
}
|
||||
}
|
||||
NormalizeCellsPerRow();
|
||||
|
||||
INSERT_COLUMNS_END:
|
||||
if( ppCellForInsertPoint && *ppCellForInsertPoint == NULL )
|
||||
|
@ -3072,7 +3176,6 @@ XP_Bool CEditTableElement::ReplaceSpecialCells(CEditTableElement *pSourceTable,
|
|||
pSourceCell->Unlink();
|
||||
pSourceCell->InsertAfter(pReplaceCell);
|
||||
// then delete the replace cell
|
||||
pReplaceCell->Unlink();
|
||||
delete pReplaceCell;
|
||||
|
||||
// Use size data from the cell we replaced
|
||||
|
@ -4525,6 +4628,8 @@ intn CEditTableRowElement::AppendRow( CEditTableRowElement *pAppendRow, XP_Bool
|
|||
return iColumnsAppended;
|
||||
}
|
||||
|
||||
// This only works for table rows already layed out
|
||||
// (has gone through CEditBuffer::FixupTableData() )
|
||||
void CEditTableRowElement::PadRowWithEmptyCells( intn iColumns )
|
||||
{
|
||||
CEditTableElement *pTable = (CEditTableElement*)GetParent();
|
||||
|
@ -5057,6 +5162,16 @@ CEditTableCellElement::CEditTableCellElement(IStreamIn *pStreamIn, CEditBuffer *
|
|||
PA_FreeTag( pTag );
|
||||
}
|
||||
|
||||
// We should never call Unlink for a table cell we are about
|
||||
// to delete - it will get unlinked automatically.
|
||||
// But in case someone does, we must unselect the cell here
|
||||
// else it will fail to find the EditBuffer in the destructor
|
||||
void CEditTableCellElement::Unlink(){
|
||||
if( IsSelected() && GetEditBuffer() )
|
||||
GetEditBuffer()->SelectCell(FALSE, NULL, this);
|
||||
CEditElement::Unlink();
|
||||
}
|
||||
|
||||
CEditTableCellElement::~CEditTableCellElement(){
|
||||
// Be sure any cell deleted is not selected
|
||||
if( IsSelected() && GetEditBuffer() )
|
||||
|
@ -6092,7 +6207,12 @@ void CEditTableCellElement::SwitchLinkage(CEditTableRowElement *pParentRow)
|
|||
// Switches back to saved parent and next pointers
|
||||
void CEditTableCellElement::RestoreLinkage()
|
||||
{
|
||||
Unlink();
|
||||
// Important! Can't call our CEditTableCellElement::Unlink()
|
||||
// because it will remove cell from selection list
|
||||
// and the main purpose for using this is to
|
||||
// restore selected cells temporarily moved
|
||||
// for copying to clipboard
|
||||
CEditElement::Unlink();
|
||||
SetParent(m_pSaveParent);
|
||||
SetNextSibling(m_pSaveNext);
|
||||
CEditElement *pParent = GetParent();
|
||||
|
|
|
@ -773,9 +773,9 @@ lo_DisplayElement(MWContext *context, LO_Element *tptr,
|
|||
if (((LO_CellStruct*)tptr)->cell_inflow_layer)
|
||||
break;
|
||||
|
||||
lo_DisplayCell(context, (LO_CellStruct *)tptr);
|
||||
lo_DisplayCellContents(context, (LO_CellStruct *)tptr,
|
||||
base_x, base_y, x, y, width, height);
|
||||
lo_DisplayCell(context, (LO_CellStruct *)tptr);
|
||||
break;
|
||||
|
||||
case LO_SUBDOC:
|
||||
|
|
Загрузка…
Ссылка в новой задаче