mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 19:35:51 +00:00
Fixed lots of Composer bugs. Implemented delete/copy accross table cell boundaries
This commit is contained in:
parent
9d308ed6ba
commit
d26815794e
@ -858,6 +858,9 @@ public:
|
||||
return pChild.IsTableRow() || pChild.IsCaption();
|
||||
}
|
||||
virtual void FinishedLoad( CEditBuffer* pBuffer );
|
||||
// Move current caption contents to just after or before the table.
|
||||
// Used primarily when all table contents are about to be deleted
|
||||
XP_Bool MoveCaptionOutsideTable(XP_Bool bAfter);
|
||||
void AdjustCaption();
|
||||
virtual PA_Tag* TagOpen(int iEditOffset);
|
||||
PA_Tag* InternalTagOpen(int iEditOffset, XP_Bool bPrinting);
|
||||
@ -879,6 +882,10 @@ public:
|
||||
// void DeleteRows(int32 Y, intn number, CEditTableElement* pUndoContainer = NULL);
|
||||
void DeleteRows(int32 Y, intn number, CEditTableCellElement **ppCellForInsertPoint = NULL);
|
||||
void DeleteColumns(int32 X, intn number, CEditTableCellElement **ppCellForInsertPoint = NULL);
|
||||
// Returns TRUE if the entire table was deleted
|
||||
// Also returns last leaf in the row just above
|
||||
// the first row deleted (use to locate cursor for backspacing through cells)
|
||||
XP_Bool DeleteEmptyRows(CEditLeafElement **ppPreviousLeaf = 0);
|
||||
|
||||
// Not used much - index based
|
||||
CEditTableRowElement* FindRow(intn number);
|
||||
@ -937,6 +944,8 @@ public:
|
||||
CEditCaptionElement* GetCaption();
|
||||
void SetCaption(CEditCaptionElement*);
|
||||
void DeleteCaption();
|
||||
void DeleteCaptionAbove();
|
||||
void DeleteCaptionBelow();
|
||||
|
||||
void SetData( EDT_TableData *pData );
|
||||
EDT_TableData* GetData();
|
||||
@ -1113,6 +1122,8 @@ public:
|
||||
virtual void FinishedLoad( CEditBuffer* pBuffer );
|
||||
|
||||
intn GetCells();
|
||||
XP_Bool AllCellsInRowAreEmpty();
|
||||
|
||||
// Use actual cell X and Y for Insert and Delete logic
|
||||
// Return the cell where we should place the insert point after Relayout
|
||||
void InsertCells(int32 X, int32 newX, intn number, CEditTableRowElement* pSource = NULL,
|
||||
@ -2691,13 +2702,13 @@ class CDeleteTableRowCommand
|
||||
: public CEditCommand
|
||||
{
|
||||
public:
|
||||
CDeleteTableRowCommand(CEditBuffer* buffer, intn rows, intn id = kDeleteTableRowCommandID);
|
||||
CDeleteTableRowCommand(CEditBuffer* buffer, intn rows, XP_Bool *pTableDeleted = 0, intn id = kDeleteTableRowCommandID);
|
||||
virtual ~CDeleteTableRowCommand();
|
||||
virtual void Do();
|
||||
// virtual void Undo();
|
||||
// virtual void Redo();
|
||||
private:
|
||||
XP_Bool m_bDeletedWholeTable;
|
||||
// XP_Bool m_bDeletedWholeTable;
|
||||
intn m_row;
|
||||
intn m_rows;
|
||||
CEditTableElement m_table; // Holds deleted rows
|
||||
@ -2728,13 +2739,13 @@ class CDeleteTableColumnCommand
|
||||
: public CEditCommand
|
||||
{
|
||||
public:
|
||||
CDeleteTableColumnCommand(CEditBuffer* buffer, intn rows, intn id = kDeleteTableColumnCommandID);
|
||||
CDeleteTableColumnCommand(CEditBuffer* buffer, intn rows, XP_Bool *pTableDeleted = 0, intn id = kDeleteTableColumnCommandID);
|
||||
virtual ~CDeleteTableColumnCommand();
|
||||
virtual void Do();
|
||||
// virtual void Undo();
|
||||
// virtual void Redo();
|
||||
private:
|
||||
XP_Bool m_bDeletedWholeTable;
|
||||
// XP_Bool m_bDeletedWholeTable;
|
||||
intn m_column;
|
||||
intn m_columns;
|
||||
CEditTableElement m_table; // Holds deleted columns
|
||||
@ -2763,13 +2774,13 @@ class CDeleteTableCellCommand
|
||||
: public CEditCommand
|
||||
{
|
||||
public:
|
||||
CDeleteTableCellCommand(CEditBuffer* buffer, intn rows, intn id = kDeleteTableCellCommandID);
|
||||
CDeleteTableCellCommand(CEditBuffer* buffer, intn rows, XP_Bool *pTableDeleted = 0, intn id = kDeleteTableCellCommandID);
|
||||
virtual ~CDeleteTableCellCommand();
|
||||
virtual void Do();
|
||||
// virtual void Undo();
|
||||
// virtual void Redo();
|
||||
private:
|
||||
XP_Bool m_bDeletedWholeTable;
|
||||
// XP_Bool m_bDeletedWholeTable;
|
||||
intn m_column;
|
||||
intn m_columns;
|
||||
CEditTableRowElement m_tableRow; // Holds deleted cells
|
||||
@ -3041,7 +3052,6 @@ public:
|
||||
CEditLeafElement *m_pCurrent;
|
||||
ElementOffset m_iCurrentOffset;
|
||||
XP_Bool m_bCurrentStickyAfter;
|
||||
|
||||
CEditElement* m_pCreationCursor;
|
||||
|
||||
ED_Color m_colorText;
|
||||
@ -3080,6 +3090,8 @@ public:
|
||||
// are blocked.
|
||||
XP_Bool m_bSelecting;
|
||||
XP_Bool m_bNoRelayout; // maybe should be a counter
|
||||
XP_Bool m_bDontClearTableSelection;
|
||||
|
||||
// Any operation changing table (insert and delete operations)
|
||||
// can set this so next Relayout call knows where to place caret
|
||||
CEditTableCellElement *m_pCellForInsertPoint;
|
||||
@ -3526,7 +3538,11 @@ public:
|
||||
void FixupInsertPoint(CEditInsertPoint& ip);
|
||||
EDT_ClipboardResult DeleteSelection(XP_Bool bCopyAppendAttributes = TRUE);
|
||||
EDT_ClipboardResult DeleteSelection(CEditSelection& selection, XP_Bool bCopyAppendAttributes = TRUE);
|
||||
void DeleteBetweenPoints( CEditLeafElement* pBegin, CEditLeafElement* pEnd, XP_Bool bCopyAppendAttributes = TRUE );
|
||||
// If stream is empty, we are deleting, else copy element data to the stream for the clipboard
|
||||
EDT_ClipboardResult DeleteOrCopyAcrossCellBorders(CEditSelection& selection, CStreamOutMemory& stream);
|
||||
// Should be used ONLY by DeleteOrCopyAcrossCellBorders
|
||||
void DeleteOrCopyWithinTable(CEditTableElement *pTable, CEditLeafElement *pBegin, CEditLeafElement *pEnd, CStreamOutMemory& stream);
|
||||
void DeleteBetweenElements( CEditLeafElement* pBegin, CEditLeafElement* pEnd, XP_Bool bCopyAppendAttributes = TRUE );
|
||||
void PositionCaret( int32 x, int32 y);
|
||||
|
||||
// Show where we can drop during dragNdrop. Handles tables as well
|
||||
@ -3591,7 +3607,7 @@ public:
|
||||
void SetInsertPoint(CPersistentEditInsertPoint& insertPoint);
|
||||
|
||||
void GetInsertPoint( CEditLeafElement** ppLeaf, ElementOffset *pOffset, XP_Bool * pbStickyAfter);
|
||||
XP_Bool GetPropertyPoint( CEditLeafElement** ppLeaf, ElementOffset *pOffset);
|
||||
XP_Bool GetPropertyPoint( CEditLeafElement** ppLeaf, ElementOffset *pOffset = 0);
|
||||
CEditElement *GetSelectedElement();
|
||||
void SelectCurrentElement();
|
||||
void ClearSelection( XP_Bool bResyncInsertPoint = TRUE, XP_Bool bKeepLeft = FALSE );
|
||||
@ -3627,10 +3643,13 @@ public:
|
||||
XP_Bool GetDirtyFlag();
|
||||
void DocumentStored();
|
||||
|
||||
EDT_ClipboardResult CanCut(XP_Bool bStrictChecking);
|
||||
EDT_ClipboardResult CanCut(CEditSelection& selection, XP_Bool bStrictChecking);
|
||||
EDT_ClipboardResult CanCopy(XP_Bool bStrictChecking);
|
||||
EDT_ClipboardResult CanCopy(CEditSelection& selection, XP_Bool bStrictChecking);
|
||||
// When bCheckForCellBoundary is TRUE, then we return EDT_COP_SELECTION_CROSSES_TABLE_DATA_CELL
|
||||
// when selection crosses a cell boundary. This is used internally to know when to handle this case.
|
||||
// Calls from UI should use FALSE, which will return EDT_OK if we cross cell boundary
|
||||
EDT_ClipboardResult CanCut(XP_Bool bStrictChecking, XP_Bool bCheckForCellBoundary = FALSE);
|
||||
EDT_ClipboardResult CanCut(CEditSelection& selection, XP_Bool bStrictChecking, XP_Bool bCheckForCellBoundary = FALSE);
|
||||
EDT_ClipboardResult CanCopy(XP_Bool bStrictChecking, XP_Bool bCheckForCellBoundary = FALSE);
|
||||
EDT_ClipboardResult CanCopy(CEditSelection& selection, XP_Bool bStrictChecking, XP_Bool bCheckForCellBoundary = FALSE);
|
||||
EDT_ClipboardResult CanPaste(XP_Bool bStrictChecking);
|
||||
EDT_ClipboardResult CanPaste(CEditSelection& selection, XP_Bool bStrictChecking);
|
||||
|
||||
@ -3722,7 +3741,11 @@ public:
|
||||
EDT_ClipboardResult CopySelection( char **ppText, int32* pTextLen,
|
||||
char **ppHtml, int32* pHtmlLen);
|
||||
|
||||
XP_Bool CopyBetweenPoints( CEditElement *pBegin,
|
||||
// Next 2 are used only for copying across table cell boundaries. iCopyType is assumed to be ED_COPY_NORMAL.
|
||||
void CopySelectionAcrossCellBoundary(CEditSelection& selection, char **ppHtml, int32* pHtmlLen);
|
||||
void AppendCopyBetweenElements( CEditLeafElement *pBegin, CEditLeafElement *pEnd, CStreamOutMemory& stream );
|
||||
|
||||
XP_Bool CopyBetweenElements( CEditElement *pBegin,
|
||||
CEditElement *pEnd, char **ppText, int32* pTextLen,
|
||||
char **ppHtml, int32* pHtmlLen );
|
||||
XP_Bool CopySelectionContents( CEditSelection& selection,
|
||||
@ -3730,6 +3753,8 @@ public:
|
||||
//cmanske: Added flags param to pass info about copied table elements
|
||||
XP_Bool CopySelectionContents( CEditSelection& selection,
|
||||
IStreamOut& stream, ED_CopyType iCopyType = ED_COPY_NORMAL );
|
||||
|
||||
|
||||
int32 GetClipboardSignature();
|
||||
int32 GetClipboardVersion();
|
||||
EDT_ClipboardResult CutSelection( char **ppText, int32* pTextLen,
|
||||
@ -4408,6 +4433,8 @@ void edt_AddTag( PA_Tag*& pStart, PA_Tag*& pEnd, TagType t, XP_Bool bIsEnd,
|
||||
|
||||
void edt_CopyTableCellData( EDT_TableCellData *pDestData, EDT_TableCellData *pSourceData );
|
||||
|
||||
void edt_ForceTableSelection(MWContext *pMWContext, LO_TableStruct *pLoTable);
|
||||
|
||||
void edt_InitBitArrays();
|
||||
|
||||
// Given an absolute URL, return the path portion of it, allocated with XP_STRDUP.
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1038,7 +1038,7 @@ void CInsertTableRowCommand::Do() {
|
||||
|
||||
|
||||
// CDeleteTableRowCommand
|
||||
CDeleteTableRowCommand::CDeleteTableRowCommand(CEditBuffer* pBuffer, intn rows, intn id)
|
||||
CDeleteTableRowCommand::CDeleteTableRowCommand(CEditBuffer* pBuffer, intn rows, XP_Bool *pTableDeleted, intn id)
|
||||
: CEditCommand(pBuffer, id),
|
||||
m_table(0,0)
|
||||
{
|
||||
@ -1053,20 +1053,38 @@ CDeleteTableRowCommand::CDeleteTableRowCommand(CEditBuffer* pBuffer, intn rows,
|
||||
if ( pTable )
|
||||
{
|
||||
int32 Y = pTableCell->GetY();
|
||||
//TODO: FIGURE THIS OUT
|
||||
m_bDeletedWholeTable = FALSE; //m_row == 0 && m_rows >= pTable->GetRows();
|
||||
|
||||
pBuffer->m_pCellForInsertPoint = 0;
|
||||
// Get elements before and after the table
|
||||
CEditElement *pLeafBefore = pTable->PreviousLeaf();
|
||||
XP_ASSERT(pLeafBefore);
|
||||
CEditElement *pLeafAfter = pTable->GetLastMostChild();
|
||||
if( pLeafAfter )
|
||||
pLeafAfter = pLeafAfter->NextLeaf();
|
||||
|
||||
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);
|
||||
if( pLeafBefore )
|
||||
pBuffer->SetInsertPoint(pLeafBefore->Leaf(), 0, pBuffer->m_bCurrentStickyAfter);
|
||||
}
|
||||
pBuffer->Relayout(pTable, 0, NULL, RELAYOUT_NOCARET);
|
||||
// Check if all rows were deleted
|
||||
if( pTable->CountRows() == 0 )
|
||||
{
|
||||
// Move any caption contents so they will display
|
||||
pTable->MoveCaptionOutsideTable(pLeafBefore == 0);
|
||||
// Delete the table
|
||||
pTable->Unlink();
|
||||
delete pTable;
|
||||
if( pTableDeleted )
|
||||
*pTableDeleted = TRUE;
|
||||
}
|
||||
else if( pTableDeleted )
|
||||
*pTableDeleted = FALSE;
|
||||
|
||||
pBuffer->Relayout(pLeafBefore, 0, pLeafAfter, RELAYOUT_NOCARET);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1118,7 +1136,7 @@ void CInsertTableColumnCommand::Do() {
|
||||
}
|
||||
|
||||
// CDeleteTableColumnCommand
|
||||
CDeleteTableColumnCommand::CDeleteTableColumnCommand(CEditBuffer* pBuffer, intn columns, intn id)
|
||||
CDeleteTableColumnCommand::CDeleteTableColumnCommand(CEditBuffer* pBuffer, intn columns, XP_Bool *pTableDeleted, intn id)
|
||||
: CEditCommand(pBuffer, id),
|
||||
m_table(0,0)
|
||||
{
|
||||
@ -1132,21 +1150,39 @@ CDeleteTableColumnCommand::CDeleteTableColumnCommand(CEditBuffer* pBuffer, intn
|
||||
CEditTableElement* pTable = pTableCell->GetTable();
|
||||
if ( pTable )
|
||||
{
|
||||
//TODO: FIGURE THIS OUT
|
||||
m_bDeletedWholeTable = FALSE; //m_column == 0 && m_columns >= pTable->GetColumns();
|
||||
int32 X = pTableCell->GetX();
|
||||
pBuffer->m_pCellForInsertPoint = 0;
|
||||
|
||||
CEditElement *pLeafBefore = pTable->PreviousLeaf();
|
||||
XP_ASSERT(pLeafBefore);
|
||||
CEditElement *pLeafAfter = pTable->GetLastMostChild();
|
||||
if( pLeafAfter )
|
||||
pLeafAfter = pLeafAfter->NextLeaf();
|
||||
|
||||
// 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);
|
||||
if( pLeafBefore )
|
||||
pBuffer->SetInsertPoint(pLeafBefore->Leaf(), 0, pBuffer->m_bCurrentStickyAfter);
|
||||
}
|
||||
pBuffer->Relayout(pTable, 0, NULL, RELAYOUT_NOCARET);
|
||||
// Check if all rows were deleted
|
||||
if( pTable->CountRows() == 0 )
|
||||
{
|
||||
// Move any caption contents so they will display
|
||||
pTable->MoveCaptionOutsideTable(pLeafBefore == 0);
|
||||
// Delete the table
|
||||
pTable->Unlink();
|
||||
delete pTable;
|
||||
if( pTableDeleted )
|
||||
*pTableDeleted = TRUE;
|
||||
}
|
||||
else if( pTableDeleted )
|
||||
*pTableDeleted = FALSE;
|
||||
|
||||
pBuffer->Relayout(pLeafBefore, 0, pLeafAfter, RELAYOUT_NOCARET);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1200,7 +1236,7 @@ void CInsertTableCellCommand::Do() {
|
||||
|
||||
|
||||
// CDeleteTableCellCommand
|
||||
CDeleteTableCellCommand::CDeleteTableCellCommand(CEditBuffer* pBuffer, intn columns, intn id)
|
||||
CDeleteTableCellCommand::CDeleteTableCellCommand(CEditBuffer* pBuffer, intn columns, XP_Bool *pTableDeleted, intn id)
|
||||
: CEditCommand(pBuffer, id)
|
||||
{
|
||||
// m_columns = columns;
|
||||
@ -1214,13 +1250,18 @@ CDeleteTableCellCommand::CDeleteTableCellCommand(CEditBuffer* pBuffer, intn colu
|
||||
CEditTableElement* pTable = pTableCell->GetTableIgnoreSubdoc();
|
||||
if ( pTable && pTableRow )
|
||||
{
|
||||
// TODO: FIGURE THIS OUT
|
||||
m_bDeletedWholeTable = FALSE; // m_column == 0 && m_columns >= pTableRow->GetCells();
|
||||
|
||||
int32 X = pTableCell->GetX();
|
||||
pBuffer->m_pCellForInsertPoint = 0;
|
||||
|
||||
CEditElement *pLeafBefore = pTable->PreviousLeaf();
|
||||
XP_ASSERT(pLeafBefore);
|
||||
CEditElement *pLeafAfter = pTable->GetLastMostChild();
|
||||
if( pLeafAfter )
|
||||
pLeafAfter = pLeafAfter->NextLeaf();
|
||||
|
||||
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
|
||||
@ -1228,7 +1269,21 @@ CDeleteTableCellCommand::CDeleteTableCellCommand(CEditBuffer* pBuffer, intn colu
|
||||
if( pLeaf )
|
||||
pBuffer->SetInsertPoint(pLeaf->Leaf(), 0, pBuffer->m_bCurrentStickyAfter);
|
||||
}
|
||||
pBuffer->Relayout(pTable, 0, NULL, RELAYOUT_NOCARET);
|
||||
// Check if all rows were deleted
|
||||
if( pTable->CountRows() == 0 )
|
||||
{
|
||||
// Move any caption contents so they will display
|
||||
pTable->MoveCaptionOutsideTable(pLeafBefore == 0);
|
||||
// Delete the table
|
||||
pTable->Unlink();
|
||||
delete pTable;
|
||||
if( pTableDeleted )
|
||||
*pTableDeleted = TRUE;
|
||||
}
|
||||
else if( pTableDeleted )
|
||||
*pTableDeleted = FALSE;
|
||||
|
||||
pBuffer->Relayout(pLeafBefore, 0, pLeafAfter, RELAYOUT_NOCARET);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1863,7 +1863,7 @@ void CEditSubDocElement::FinishedLoad( CEditBuffer* pBuffer ){
|
||||
// Subdocs have to have children.
|
||||
// Put an empty paragraph into any empty subdoc.
|
||||
pChild = CEditContainerElement::NewDefaultContainer( this,
|
||||
GetDefaultAlignment() );
|
||||
IsCaption() ? ED_ALIGN_CENTER : GetDefaultAlignment() );
|
||||
// Creating it inserts it.
|
||||
(void) new CEditTextElement(pChild, 0);
|
||||
}
|
||||
@ -3142,10 +3142,12 @@ XP_Bool CEditTableElement::ReplaceSpecialCells(CEditTableElement *pSourceTable,
|
||||
|
||||
if( iReplaceRow != iPrevReplaceRow )
|
||||
{
|
||||
// We are on the next row
|
||||
// We are on the next row to be replaced
|
||||
iPrevReplaceRow = iReplaceRow;
|
||||
// If cell layout of source and destination matches,
|
||||
// we should get to the next source row at the same time
|
||||
// we should get to the next source row at the same time,
|
||||
// (which means iSourceRow should be 1 > than iPrevSourceRow)
|
||||
// if iSourceRow wasn't increased, there's still source cells on the previous row
|
||||
if( iSourceRow == iPrevSourceRow )
|
||||
{
|
||||
XP_TRACE(("CEditTableElement::ReplaceSpecialCells: More Source cells are left to paste."));
|
||||
@ -3168,7 +3170,6 @@ XP_Bool CEditTableElement::ReplaceSpecialCells(CEditTableElement *pSourceTable,
|
||||
// We ran out of source cells on the desired row,
|
||||
// but we still have cells to replace
|
||||
XP_TRACE(("CEditTableElement::ReplaceSpecialCells: Not enough SOURCE cells to paste in this row."));
|
||||
iPrevSourceRow = iSourceRow;
|
||||
|
||||
if( !bIgnoreSourceLayout )
|
||||
{
|
||||
@ -3182,19 +3183,24 @@ XP_Bool CEditTableElement::ReplaceSpecialCells(CEditTableElement *pSourceTable,
|
||||
pReplaceCell = pReplaceCell->GetNextCellInTable(&iReplaceRow);
|
||||
}
|
||||
|
||||
// then find the next special selected cell
|
||||
// Skip to the next special selected cell
|
||||
while( pReplaceCell && !pReplaceCell->IsSpecialSelected() )
|
||||
pReplaceCell = pReplaceCell->GetNextCellInTable(&iReplaceRow);
|
||||
if( !pReplaceCell )
|
||||
break;
|
||||
// We are now at beginning of both a replace row and a source row
|
||||
// We are now at the right place in the next replace row
|
||||
iPrevReplaceRow = iReplaceRow;
|
||||
}
|
||||
}
|
||||
// Be sure to do this here (not in above block)
|
||||
// since we don't ever go there if cell layout
|
||||
// of source and destination matches
|
||||
iPrevSourceRow = iSourceRow;
|
||||
|
||||
// Must get these now before we move cells around
|
||||
pNextSourceCell = pSourceCell->GetNextCellInTable(&iSourceRow);
|
||||
pNextReplaceCell = pReplaceCell->GetNextCellInTable(&iReplaceRow);
|
||||
|
||||
// Skip to a special-selected cell
|
||||
while( pNextReplaceCell && !pNextReplaceCell->IsSpecialSelected() )
|
||||
pNextReplaceCell = pNextReplaceCell->GetNextCellInTable(&iReplaceRow);
|
||||
@ -3405,6 +3411,67 @@ void CEditTableElement::DeleteColumns(int32 X, intn number, CEditTableCellElemen
|
||||
*ppCellForInsertPoint = pCellForInsertPoint;
|
||||
}
|
||||
|
||||
// Returns TRUE if any row was deleted
|
||||
// Return the last cell in row above the first deleted row
|
||||
// if first row wasn't deleted
|
||||
XP_Bool CEditTableElement::DeleteEmptyRows(CEditLeafElement **ppPreviousLeaf)
|
||||
{
|
||||
int32 iRowsInTable = m_iRows;
|
||||
CEditTableRowElement *pRow = GetFirstRow();
|
||||
CEditTableRowElement *pPrevRow = 0;
|
||||
int32 iCount = 0;
|
||||
int32 iIndex = 0;
|
||||
int32 iFirstEmptyRowY = -1;
|
||||
CEditTableCellElement *pCellForInsertPoint = NULL;
|
||||
// Clear this now in case we don't find a valid leaf to use
|
||||
if( ppPreviousLeaf )
|
||||
*ppPreviousLeaf = 0;
|
||||
|
||||
// Count number of completely empty rows
|
||||
while( pRow )
|
||||
{
|
||||
if( pRow->AllCellsInRowAreEmpty() )
|
||||
{
|
||||
if( iFirstEmptyRowY == -1 )
|
||||
iFirstEmptyRowY = GetRowY(iIndex);
|
||||
iCount++;
|
||||
|
||||
if( iCount == 1 && pPrevRow && ppPreviousLeaf )
|
||||
{
|
||||
// We are in the first row we will delete and it isn't the first row of table
|
||||
// Get the last cell in the previous row
|
||||
CEditTableCellElement *pCell = pPrevRow->GetFirstCell();
|
||||
CEditTableCellElement *pNextCell;
|
||||
while( pCell && (pNextCell = GetNextCellInRow(pCell)) != 0 )
|
||||
pCell = pNextCell;
|
||||
|
||||
// Return last leaf in that cell
|
||||
if( pCell )
|
||||
{
|
||||
CEditElement *pLast = pCell->GetLastMostChild();
|
||||
while( pLast && (!pLast->IsLeaf() || pLast->Leaf()->GetLen() == 0) )
|
||||
pLast = pLast->GetPreviousSibling();
|
||||
if( pLast && pLast->IsLeaf() )
|
||||
*ppPreviousLeaf = pLast->Leaf();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pPrevRow = pRow;
|
||||
}
|
||||
|
||||
iIndex++;
|
||||
pRow = pRow->GetNextRow();
|
||||
}
|
||||
if( iCount > 0 )
|
||||
{
|
||||
DeleteRows(iFirstEmptyRowY, iCount);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// This is the old version - just finds row based on counting,
|
||||
// no ROWSPAN effect needed
|
||||
CEditTableRowElement* CEditTableElement::FindRow(intn number)
|
||||
@ -3462,6 +3529,25 @@ void CEditTableElement::DeleteCaption(){
|
||||
delete pOldCaption;
|
||||
}
|
||||
|
||||
void CEditTableElement::DeleteCaptionAbove()
|
||||
{
|
||||
CEditCaptionElement* pCaption = GetCaption();
|
||||
// A caption "above" the table is always the first
|
||||
// child of the table
|
||||
if( pCaption && pCaption == GetChild() )
|
||||
delete pCaption;
|
||||
}
|
||||
|
||||
void CEditTableElement::DeleteCaptionBelow()
|
||||
{
|
||||
CEditCaptionElement* pCaption = GetCaption();
|
||||
// A caption "below" the table is always the
|
||||
// last of the table. Its simpler to just check
|
||||
// if its not the first child
|
||||
if( pCaption && pCaption != GetChild() )
|
||||
delete pCaption;
|
||||
}
|
||||
|
||||
void CEditTableElement::FinishedLoad( CEditBuffer* pBuffer ){
|
||||
// From experimentation, we know that the 2.0 navigator dumps
|
||||
// tags that aren't in td, tr, or caption cells into the doc
|
||||
@ -3569,6 +3655,69 @@ void CEditTableElement::FinishedLoad( CEditBuffer* pBuffer ){
|
||||
EnsureSelectableSiblings(pBuffer);
|
||||
}
|
||||
|
||||
XP_Bool CEditTableElement::MoveCaptionOutsideTable(XP_Bool bAfter)
|
||||
{
|
||||
CEditCaptionElement *pCaption = GetCaption();
|
||||
XP_Bool bReturn = FALSE;
|
||||
|
||||
if ( pCaption )
|
||||
{
|
||||
CEditContainerElement *pContainer = (CEditContainerElement*)pCaption->GetChild();
|
||||
// Skip over the division element used for alignment
|
||||
// (Alternate method is to start at first leaf and find its container,
|
||||
// but that would miss lists, so lets try to start from top down)
|
||||
if( pContainer && pContainer->IsDivision() )
|
||||
pContainer = (CEditContainerElement*)pContainer->GetChild();
|
||||
|
||||
if( !pContainer || !pContainer->IsContainer() ||
|
||||
(pContainer->IsEmpty() && pContainer->GetNextSibling() == 0) )
|
||||
return FALSE;
|
||||
|
||||
CEditElement *pLastChild = GetLastMostChild();
|
||||
CEditLeafElement *pBefore = bAfter ? 0 : PreviousLeaf();
|
||||
CEditLeafElement *pAfter = (bAfter && pLastChild) ? pLastChild->NextLeaf() : 0;
|
||||
CEditContainerElement *pOutsideContainer;
|
||||
// Save container after current so all are moved
|
||||
CEditElement *pNextContainer = pContainer->GetNextSibling();
|
||||
|
||||
if( pBefore )
|
||||
{
|
||||
pOutsideContainer = pBefore->FindContainer();
|
||||
if( pOutsideContainer )
|
||||
{
|
||||
// Move the first container found
|
||||
pContainer->Unlink();
|
||||
pContainer->InsertAfter(pOutsideContainer);
|
||||
bReturn = TRUE;
|
||||
}
|
||||
}
|
||||
else if( pAfter )
|
||||
{
|
||||
pOutsideContainer = pAfter->FindContainer();
|
||||
if( pOutsideContainer )
|
||||
{
|
||||
pContainer->Unlink();
|
||||
pContainer->InsertBefore(pOutsideContainer);
|
||||
bReturn = TRUE;
|
||||
}
|
||||
}
|
||||
if( bReturn && pNextContainer != 0 )
|
||||
{
|
||||
// Move any other containers following the one just moved
|
||||
CEditElement *pInsertAfter = pContainer;
|
||||
while( pNextContainer )
|
||||
{
|
||||
pContainer = (CEditContainerElement*)pNextContainer;
|
||||
pNextContainer = pContainer->GetNextSibling();
|
||||
pContainer->Unlink();
|
||||
pContainer->InsertAfter(pInsertAfter);
|
||||
pInsertAfter = pContainer;
|
||||
}
|
||||
}
|
||||
}
|
||||
return bReturn;
|
||||
}
|
||||
|
||||
void CEditTableElement::AdjustCaption() {
|
||||
CEditCaptionElement* pCaption = GetCaption();
|
||||
if ( pCaption ) {
|
||||
@ -4420,6 +4569,25 @@ intn CEditTableRowElement::GetCells()
|
||||
return cells;
|
||||
}
|
||||
|
||||
XP_Bool CEditTableRowElement::AllCellsInRowAreEmpty()
|
||||
{
|
||||
CEditTableCellElement *pCell = GetFirstCell();
|
||||
if( !pCell || !pCell->IsTableCell() ) // Unlikely
|
||||
{
|
||||
XP_ASSERT(FALSE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
while( pCell && pCell->IsTableCell() )
|
||||
{
|
||||
if( !pCell->IsEmpty() )
|
||||
return FALSE;
|
||||
|
||||
pCell = (CEditTableCellElement*)(pCell->GetNextSibling());
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void CEditTableRowElement::FinishedLoad( CEditBuffer* pBuffer ){
|
||||
// Wrap anything that's not a table cell in a table cell.
|
||||
CEditTableCellElement* pCell = NULL;
|
||||
@ -6148,9 +6316,14 @@ CEditTableCellElement* CEditTableCellElement::GetNextCellInTable(intn *pRowCount
|
||||
// Get the first child cell of the next row
|
||||
if( GetParent() && GetParent()->GetNextSibling() )
|
||||
pNextCell = GetParent()->GetNextSibling()->GetChild();
|
||||
#ifdef DEBUG
|
||||
if( pNextCell ) XP_ASSERT(pNextCell->IsTableCell());
|
||||
#endif
|
||||
|
||||
// If the next child is not a cell,
|
||||
// we hit a table caption at the end of the table
|
||||
// (its the sibling after the last row in the table)
|
||||
// so there's no more cells
|
||||
if( pNextCell && !pNextCell->IsTableCell() )
|
||||
return 0;
|
||||
|
||||
// Tell caller we wrapped to the next row
|
||||
if( pRowCounter && pNextCell )
|
||||
(*pRowCounter)++;
|
||||
@ -7689,16 +7862,30 @@ void CEditContainerElement::PrintOpen( CPrintState *pPrintState ){
|
||||
CEditContainerElement* pPrevContainer=GetPreviousNonEmptyContainer();
|
||||
if (pPrevContainer && pPrevContainer->GetType()!=P_NSDT)
|
||||
pPrevContainer=NULL;//all bets are off
|
||||
if (( GetAlignment() == ED_ALIGN_RIGHT && ! IsEmpty()) && ( !pPrevContainer || (pPrevContainer->GetAlignment() != ED_ALIGN_RIGHT ) )){
|
||||
|
||||
// We must set this explicitly for text in TableCaptions
|
||||
// Hopefully, we will change ED_ALIGN_LEFT to ED_ALIGN_DEFAULT for regular paragraphs
|
||||
// so we don't clutter HTML with extra <DIV> alignment tags
|
||||
if (( GetAlignment() == ED_ALIGN_LEFT && ! IsEmpty()) && ( !pPrevContainer ||
|
||||
(pPrevContainer->GetAlignment() != ED_ALIGN_LEFT) ))
|
||||
{
|
||||
pPrintState->m_pOut->Printf( "\n");
|
||||
pPrintState->m_iCharPos = pPrintState->m_pOut->Printf( "<DIV ALIGN=left>");
|
||||
|
||||
}
|
||||
else if (( GetAlignment() == ED_ALIGN_RIGHT && ! IsEmpty()) && ( !pPrevContainer || (pPrevContainer->GetAlignment() != ED_ALIGN_RIGHT ) ))
|
||||
{
|
||||
pPrintState->m_pOut->Printf( "\n");
|
||||
pPrintState->m_iCharPos = pPrintState->m_pOut->Printf( "<DIV ALIGN=right>");
|
||||
|
||||
}
|
||||
else if (( GetAlignment() == ED_ALIGN_ABSCENTER && !IsEmpty()) && ( !pPrevContainer || (pPrevContainer->GetAlignment() != ED_ALIGN_ABSCENTER ) )){
|
||||
else if (( GetAlignment() == ED_ALIGN_ABSCENTER && !IsEmpty()) && ( !pPrevContainer || (pPrevContainer->GetAlignment() != ED_ALIGN_ABSCENTER ) ))
|
||||
{
|
||||
pPrintState->m_pOut->Printf( "\n");
|
||||
pPrintState->m_iCharPos = pPrintState->m_pOut->Printf( "<CENTER>");
|
||||
}
|
||||
if( !IsImplicitBreak() && ! bHasExtraData){
|
||||
if( !IsImplicitBreak() && ! bHasExtraData)
|
||||
{
|
||||
switch( ppState ){
|
||||
default:
|
||||
case 0:
|
||||
@ -7812,21 +7999,29 @@ void CEditContainerElement::PrintEnd( CPrintState *pPrintState ){
|
||||
}
|
||||
}
|
||||
// Keep empty paragraphs from being eaten
|
||||
if ( IsEmpty() && ppState == 0) {
|
||||
if ( IsEmpty() && ppState == 0)
|
||||
{
|
||||
char* space = " ";
|
||||
pPrintState->m_pOut->Printf( space );
|
||||
pPrintState->m_iCharPos += XP_STRLEN(space);
|
||||
}
|
||||
if( (GetAlignment() == ED_ALIGN_RIGHT && !IsEmpty() )&& (!pNextContainer || pNextContainer->GetType() != P_NSDT || !CompareAlignments(pNextContainer->GetAlignment(),GetAlignment())) ) {
|
||||
ED_Alignment align = GetAlignment();
|
||||
if( !IsEmpty() && (align == ED_ALIGN_RIGHT || align == ED_ALIGN_LEFT) &&
|
||||
(!pNextContainer || pNextContainer->GetType() != P_NSDT ||
|
||||
!CompareAlignments(pNextContainer->GetAlignment(), align)) )
|
||||
{
|
||||
pPrintState->m_pOut->Printf( "</DIV>");
|
||||
bNeedReturn = TRUE;
|
||||
}
|
||||
else if(( GetAlignment() == ED_ALIGN_ABSCENTER && !IsEmpty() ) && (!pNextContainer || pNextContainer->GetType() != P_NSDT || !CompareAlignments(pNextContainer->GetAlignment(),GetAlignment())) ) {
|
||||
else if(( GetAlignment() == ED_ALIGN_ABSCENTER && !IsEmpty() ) &&
|
||||
(!pNextContainer || pNextContainer->GetType() != P_NSDT || !CompareAlignments(pNextContainer->GetAlignment(), align)) )
|
||||
{
|
||||
pPrintState->m_pOut->Printf( "</CENTER>");
|
||||
bNeedReturn = TRUE;
|
||||
}
|
||||
|
||||
if ( bNeedReturn ) {
|
||||
if ( bNeedReturn )
|
||||
{
|
||||
pPrintState->m_iCharPos = 0;
|
||||
pPrintState->m_pOut->Printf( "\n");
|
||||
}
|
||||
@ -9760,7 +9955,10 @@ void CEditTextElement::PrintRange( CPrintState *ps, int32 start, int32 end ){
|
||||
}
|
||||
else {
|
||||
if ( end > len ) {
|
||||
XP_ASSERT(FALSE);
|
||||
// This is getting annoying - XP_TRACE instead,
|
||||
// since we survive it just fine
|
||||
XP_TRACE(("PrintRange error: end = %d len = %d\n", end, len));
|
||||
//XP_ASSERT(FALSE);
|
||||
#ifdef DEBUG_akkana
|
||||
printf("end = %d len = %d\n", end, len);
|
||||
#endif
|
||||
|
@ -4290,6 +4290,7 @@ XP_Bool CSizingObject::Create(CEditBuffer *pBuffer,
|
||||
|
||||
pElement = lo_GetFirstAndLastCellsInTable(m_pBuffer->m_pContext, m_pLoElement, &pLastElement);
|
||||
if( pElement )
|
||||
{
|
||||
do {
|
||||
if( pElement && pElement->lo_any.type == LO_CELL &&
|
||||
(pElement->lo_cell.x + pElement->lo_cell.width) == iRightEdge &&
|
||||
@ -4298,10 +4299,12 @@ XP_Bool CSizingObject::Create(CEditBuffer *pBuffer,
|
||||
m_pLoElement = pElement;
|
||||
break;
|
||||
}
|
||||
if( pElement != pLastElement )
|
||||
pElement = pElement->lo_any.next;
|
||||
}
|
||||
while( pElement != pLastElement );
|
||||
}
|
||||
}
|
||||
if( m_iStyle == ED_SIZE_BOTTOM && lo_GetRowSpan(m_pLoElement) > 1 )
|
||||
{
|
||||
int32 iBottomEdge = m_pLoElement->lo_cell.y + m_pLoElement->lo_cell.height;
|
||||
@ -4309,6 +4312,7 @@ XP_Bool CSizingObject::Create(CEditBuffer *pBuffer,
|
||||
if( !pElement )
|
||||
pElement = lo_GetFirstAndLastCellsInTable(m_pBuffer->m_pContext, m_pLoElement, &pLastElement);
|
||||
if( pElement )
|
||||
{
|
||||
do {
|
||||
if( pElement && pElement->lo_any.type == LO_CELL &&
|
||||
(pElement->lo_cell.y + pElement->lo_cell.height) == iBottomEdge &&
|
||||
@ -4317,11 +4321,13 @@ XP_Bool CSizingObject::Create(CEditBuffer *pBuffer,
|
||||
m_pLoElement = pElement;
|
||||
break;
|
||||
}
|
||||
if( pElement != pLastElement )
|
||||
pElement = pElement->lo_any.next;
|
||||
}
|
||||
while( pElement != pLastElement );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LO_Any *pAny = &(m_pLoElement->lo_any);
|
||||
int32 iSelectX = pAny->x + pAny->x_offset;
|
||||
@ -4787,6 +4793,14 @@ XP_Bool CSizingObject::GetSizingRect(int32 xVal, int32 yVal, XP_Bool bModifierKe
|
||||
// Convert to % format
|
||||
iWidth = (iWidth * 100) / m_iParentWidth;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Tables are problematic. We use full cell width, including padding and borders,
|
||||
// because it much easier to calculate percent mode values,
|
||||
// but the HTML WIDTH and HEIGHT params only measure CONTENT area
|
||||
// Should we display the same content size value when resizing?
|
||||
// (That's what user sees in the Width and Height values in the property dialogs)
|
||||
}
|
||||
|
||||
// "Width = x"
|
||||
PR_snprintf(pMsg, 128, XP_GetString(XP_EDT_WIDTH_EQUALS), iWidth);
|
||||
@ -4795,7 +4809,7 @@ XP_Bool CSizingObject::GetSizingRect(int32 xVal, int32 yVal, XP_Bool bModifierKe
|
||||
strcat(pMsg, XP_GetString(m_iWidthMsgID));
|
||||
|
||||
// The % of original [width] and/or [height] string
|
||||
// Current logic assumes constaining aspect ratio when sizing corners,
|
||||
// Current logic assumes constraining aspect ratio when sizing corners,
|
||||
// so separate Width, Height percentages are not shown
|
||||
XP_STRCPY(pPercentOfWhat, XP_GetString(XP_EDT_WIDTH));
|
||||
}
|
||||
@ -4896,7 +4910,7 @@ void CSizingObject::ResizeObject()
|
||||
EraseAddRowsOrCols();
|
||||
int32 iWidth=0, iWidthPixels=0, iHeightPixels=0, iHeight=0;
|
||||
|
||||
// Get the element being sized (except table or cell - obtained below)
|
||||
// Get the element being sized
|
||||
CEditLeafElement *pElement = (CEditLeafElement*)(m_pLoElement->lo_any.edit_element);
|
||||
|
||||
if( !(m_iStyle == ED_SIZE_ADD_ROWS || m_iStyle == ED_SIZE_ADD_COLS) )
|
||||
@ -6274,4 +6288,50 @@ void EDT_EncryptReset( MWContext *pContext ){
|
||||
pEditBuffer->m_bEncrypt = PR_FALSE;
|
||||
}
|
||||
|
||||
XP_Bool EDT_AdjustTableRectForCaption(LO_TableStruct *pTable, XP_Rect *pRect)
|
||||
{
|
||||
if( !pTable || !pRect )
|
||||
return FALSE;
|
||||
|
||||
// If table has a caption, we want highlighting to surround the caption as well
|
||||
LO_Element *pElement = (LO_Element*)pTable;
|
||||
// Find the first cell
|
||||
while( pElement && pElement->type != LO_CELL )
|
||||
pElement = pElement->lo_any.next;
|
||||
if( pElement )
|
||||
{
|
||||
XP_Bool bCaptionBeforeTable = pElement->lo_cell.isCaption;
|
||||
XP_Bool bCaptionAfterTable = FALSE;
|
||||
if( !bCaptionBeforeTable )
|
||||
{
|
||||
// Search for a caption at the end
|
||||
do {
|
||||
if( pElement && pElement->type == LO_CELL &&
|
||||
pElement->lo_cell.isCaption )
|
||||
{
|
||||
bCaptionAfterTable = TRUE;
|
||||
break;
|
||||
}
|
||||
pElement = pElement->lo_any.next;
|
||||
}
|
||||
while( pElement && pElement->type != LO_LINEFEED );
|
||||
|
||||
}
|
||||
if( bCaptionBeforeTable || bCaptionAfterTable )
|
||||
{
|
||||
// This is the full height, including caption
|
||||
int32 iHeight = pTable->line_height + pTable->border_bottom_width + pTable->inter_cell_space;
|
||||
|
||||
// Adjust top or bottom to include caption area
|
||||
if( bCaptionBeforeTable )
|
||||
pRect->top = pRect->bottom - iHeight;
|
||||
else
|
||||
pRect->bottom = pRect->top + iHeight;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#endif // EDITOR
|
||||
|
@ -5209,6 +5209,8 @@ lo_GetLineEnds(MWContext *context, lo_DocState *state,
|
||||
int32 line, LO_Element** retBegin, LO_Element** retEnd)
|
||||
{
|
||||
LO_Element **line_array;
|
||||
LO_Element *begin = 0;
|
||||
LO_Element *end = 0;
|
||||
|
||||
*retBegin = NULL;
|
||||
*retEnd = NULL;
|
||||
@ -5236,11 +5238,11 @@ lo_GetLineEnds(MWContext *context, lo_DocState *state,
|
||||
XP_LOCK_BLOCK(larray_array, XP_Block *, state->larray_array);
|
||||
state->line_array = larray_array[a_indx];
|
||||
XP_LOCK_BLOCK(line_array, LO_Element **, state->line_array);
|
||||
*retBegin = line_array[a_line];
|
||||
begin = line_array[a_line];
|
||||
|
||||
if (line >= (state->line_num - 2))
|
||||
{
|
||||
*retEnd = NULL;
|
||||
end = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -5250,11 +5252,11 @@ lo_GetLineEnds(MWContext *context, lo_DocState *state,
|
||||
state->line_array = larray_array[a_indx + 1];
|
||||
XP_LOCK_BLOCK(line_array, LO_Element **,
|
||||
state->line_array);
|
||||
*retEnd = line_array[0];
|
||||
end = line_array[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
*retEnd = line_array[a_line + 1];
|
||||
end = line_array[a_line + 1];
|
||||
}
|
||||
}
|
||||
XP_UNLOCK_BLOCK(state->line_array);
|
||||
@ -5263,18 +5265,36 @@ lo_GetLineEnds(MWContext *context, lo_DocState *state,
|
||||
#else
|
||||
{
|
||||
XP_LOCK_BLOCK(line_array, LO_Element **, state->line_array);
|
||||
*retBegin = line_array[line];
|
||||
begin = line_array[line];
|
||||
if (line == (state->line_num - 2))
|
||||
{
|
||||
*retEnd = NULL;
|
||||
end = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
*retEnd = line_array[line + 1];
|
||||
end = line_array[line + 1];
|
||||
}
|
||||
XP_UNLOCK_BLOCK(state->line_array);
|
||||
}
|
||||
#endif /* XP_WIN16 */
|
||||
/* Be sure we aren't pointing to internal dummy elements */
|
||||
if( begin )
|
||||
{
|
||||
while( begin && lo_IsDummyLayoutElement(begin) )
|
||||
begin = begin->lo_any.next;
|
||||
*retBegin = begin;
|
||||
}
|
||||
if( end )
|
||||
{
|
||||
while( end && lo_IsDummyLayoutElement(end) )
|
||||
{
|
||||
if( end->lo_any.prev )
|
||||
end = end->lo_any.prev;
|
||||
else
|
||||
end = end->lo_any.next;
|
||||
}
|
||||
*retEnd = end;
|
||||
}
|
||||
}
|
||||
|
||||
Bool lo_IsDummyLayoutElement(LO_Element *ele)
|
||||
@ -5413,8 +5433,14 @@ XP_TRACE(("lo_PointToLine says line %d\n", line));
|
||||
y2 = tptr->lo_any.y + tptr->lo_any.y_offset +
|
||||
t_height;
|
||||
}
|
||||
if ((y >= tptr->lo_any.y)&&(y < y2)&&
|
||||
(x >= tptr->lo_any.x)&&
|
||||
if ((y >= tptr->lo_any.y)&&(y < y2))
|
||||
{
|
||||
if (tptr->type == LO_TABLE)
|
||||
{
|
||||
/* Save to return if no other elements are found */
|
||||
tptrTable = tptr;
|
||||
}
|
||||
if((x >= tptr->lo_any.x)&&
|
||||
(x < (x1 + t_width)))
|
||||
{
|
||||
|
||||
@ -5444,11 +5470,7 @@ XP_TRACE(("lo_PointToLine says line %d\n", line));
|
||||
else
|
||||
{
|
||||
in_table = TRUE;
|
||||
/*
|
||||
* Save the table element
|
||||
* to return if no other element is found
|
||||
*/
|
||||
tptrTable = tptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
tptr = tptr->lo_any.next;
|
||||
@ -5551,6 +5573,16 @@ XP_TRACE(("lo_PointToLine says line %d\n", line));
|
||||
*ret_x = x;
|
||||
*ret_y = y;
|
||||
|
||||
/* cmanske: Return table if no other element is found (we are before a table)
|
||||
* or the element is a non-editable linefeed (we are after a table),
|
||||
* and return this only if we are outside the table boundary
|
||||
*/
|
||||
if( EDT_IS_EDITOR(context) && tptrTable && !in_table &&
|
||||
(tptr == 0 || (tptr->type == LO_LINEFEED && tptr->lo_linefeed.break_type == LO_LINEFEED_BREAK_SOFT)) )
|
||||
{
|
||||
tptr = tptrTable;
|
||||
}
|
||||
|
||||
return(tptr);
|
||||
}
|
||||
|
||||
|
@ -1694,4 +1694,8 @@ int32 lo_GetCellPadding(LO_Element *pCellElement);
|
||||
lo_DocState * lo_CreateStateForCellLayout(MWContext *context, LO_CellStruct *cell);
|
||||
void lo_RebuildCell(MWContext *context, lo_DocState *state, LO_CellStruct *cell);
|
||||
|
||||
/* Even though this is an EDT function, this avoids having to place this in EDT.H
|
||||
* It is only called by lo_ProcessClick() in laysel.c */
|
||||
void edt_ForceTableSelection(MWContext *pMWContext, LO_TableStruct *pLoTable);
|
||||
|
||||
#endif /* _Layout_h_ */
|
||||
|
@ -1907,6 +1907,10 @@ lo_IsHardBreak2(MWContext *context, LO_Element* element, int32 position)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* cmanske This is really misnamed for an Editor context.
|
||||
It extends selection to the end of any line (i.e., soft break or no break),
|
||||
not just to a hard break
|
||||
*/
|
||||
PRIVATE
|
||||
Bool
|
||||
lo_ExtendToIncludeHardBreak(MWContext* context, lo_DocState *state, LO_Selection* selection)
|
||||
@ -1935,6 +1939,31 @@ lo_ExtendToIncludeHardBreak(MWContext* context, lo_DocState *state, LO_Selection
|
||||
result = TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Find a soft linefeed or end of text on the line
|
||||
This allows the selection of a "line" to work inside
|
||||
a table cell
|
||||
*/
|
||||
LO_Element* tptr = end->element;
|
||||
do {
|
||||
if( tptr->type == LO_LINEFEED || !tptr->lo_any.next )
|
||||
break;
|
||||
tptr = tptr->lo_any.next;
|
||||
}
|
||||
while( tptr->type != LO_LINEFEED );
|
||||
|
||||
XP_ASSERT(tptr);
|
||||
end->element = tptr;
|
||||
if( tptr->type == LO_LINEFEED )
|
||||
{
|
||||
end->position = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
end->position = lo_GetLastCharEndPosition(end->element);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
@ -4270,8 +4299,9 @@ lo_GetLastCharEndPosition(LO_Element* eptr)
|
||||
|
||||
void lo_HitLine(MWContext *context, lo_DocState *state, int32 x, int32 y, Bool requireCaret,
|
||||
LO_HitResult* result);
|
||||
/* cmanske: added y param for snapping to closest cell in the editor */
|
||||
void lo_HitLine2(MWContext *context, lo_DocState *state, LO_Element* element, int32 position,
|
||||
int32 x, LO_HitResult* result);
|
||||
int32 x, int32 y, LO_HitResult* result);
|
||||
Bool lo_PositionIsOffEndOfLine(LO_HitElementResult* elementResult);
|
||||
|
||||
void lo_FullHitElement(MWContext *context, lo_DocState* state, int32 x, int32 y,
|
||||
@ -4370,7 +4400,7 @@ void lo_FullHitElement(MWContext *context, lo_DocState* state, int32 x, int32 y,
|
||||
Bool requireCaret,
|
||||
LO_Element* eptr, int32 ret_x, int32 ret_y, LO_HitResult* result)
|
||||
{
|
||||
if ( eptr->type != LO_LINEFEED ) {
|
||||
if ( eptr->type != LO_LINEFEED && eptr->type != LO_TABLE ) {
|
||||
/* Seek forward to find an editable element */
|
||||
if ( ! lo_EnsureEditableSearchNext(context, state, &eptr) )
|
||||
{
|
||||
@ -4397,7 +4427,7 @@ void lo_FullHitElement(MWContext *context, lo_DocState* state, int32 x, int32 y,
|
||||
* that bites us if we use lo_HitLine. So rather than starting the
|
||||
* search from the beginning, we start from the linefeed.
|
||||
*/
|
||||
lo_HitLine2(context, state, eptr, 0, x, result);
|
||||
lo_HitLine2(context, state, eptr, 0, x, y, result);
|
||||
}
|
||||
}
|
||||
|
||||
@ -4561,11 +4591,13 @@ Bool lo_OnlyBulletsBetween(LO_Element *begin,LO_Element *end)
|
||||
#endif
|
||||
|
||||
void lo_HitLine2(MWContext *context, lo_DocState *state, LO_Element* element,
|
||||
int32 position, int32 x, LO_HitResult* result)
|
||||
int32 position, int32 x, int32 y, LO_HitResult* result)
|
||||
{
|
||||
LO_Element* begin;
|
||||
LO_Element* end;
|
||||
|
||||
#ifdef EDITOR
|
||||
LO_Element* tptr;
|
||||
#endif
|
||||
result->type = LO_HIT_UNKNOWN;
|
||||
|
||||
end = element;
|
||||
@ -4580,7 +4612,115 @@ void lo_HitLine2(MWContext *context, lo_DocState *state, LO_Element* element,
|
||||
}
|
||||
if ( ! end )
|
||||
return;
|
||||
#ifdef EDITOR
|
||||
if( EDT_IS_EDITOR(context) && end->type == LO_TABLE )
|
||||
{
|
||||
tptr = end;
|
||||
if( x > end->lo_table.x )
|
||||
{
|
||||
/* We are after the table
|
||||
* Find the last cell in a row that spans the y value
|
||||
* Begin at the end of the table
|
||||
*/
|
||||
|
||||
while( tptr->lo_any.next && tptr->lo_any.next->type != LO_LINEFEED )
|
||||
tptr = tptr->lo_any.next;
|
||||
|
||||
do {
|
||||
if( tptr->type == LO_CELL )
|
||||
{
|
||||
/* Find a cell that is in same (last) column
|
||||
* and the y location is within the row of that cell.
|
||||
*/
|
||||
if( y >= tptr->lo_cell.y )
|
||||
{
|
||||
end = tptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
tptr = tptr->lo_any.prev;
|
||||
}
|
||||
while( tptr && tptr->type != LO_TABLE ); /* Stop when we hit beginning of the table */
|
||||
|
||||
/* Find the last element in the cell */
|
||||
begin = end->lo_cell.cell_list;
|
||||
if( begin == 0 )
|
||||
return;
|
||||
|
||||
while( begin->lo_any.next )
|
||||
begin = begin->lo_any.next;
|
||||
|
||||
/* Back up to find an editable element */
|
||||
if ( ! lo_EnsureEditableSearchPrev(context, state, &begin) )
|
||||
return;
|
||||
|
||||
result->lo_hitLine.region = LO_HIT_LINE_REGION_AFTER;
|
||||
result->lo_hitLine.selection.begin.position = lo_GetMaximumInsertPointPosition(begin);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We are before the table
|
||||
* Find the cell that spans the y value
|
||||
* Start at beginning cell of table
|
||||
*/
|
||||
while( tptr->type != LO_CELL )
|
||||
{
|
||||
tptr = tptr->lo_any.next;
|
||||
if( tptr == 0 || tptr->type == LO_LINEFEED )
|
||||
/* No cells in table? */
|
||||
goto LO_HIT_CONTINUE;
|
||||
|
||||
if( tptr->type == LO_CELL )
|
||||
break;
|
||||
}
|
||||
|
||||
do {
|
||||
if( tptr->type == LO_CELL )
|
||||
{
|
||||
/* Find a cell that is in the first column
|
||||
* and the y location is within the row of that cell.
|
||||
*/
|
||||
if( y < (tptr->lo_cell.y + tptr->lo_cell.height + tptr->lo_cell.inter_cell_space) )
|
||||
{
|
||||
end = tptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
tptr = tptr->lo_any.next;
|
||||
}
|
||||
while( tptr && tptr->type != LO_LINEFEED ); /* Stop when we hit end of the table */
|
||||
|
||||
/* Find the first element in the cell */
|
||||
begin = end->lo_cell.cell_list;
|
||||
if( begin == 0 )
|
||||
return;
|
||||
|
||||
/* Find an editable element */
|
||||
if ( ! lo_EnsureEditableSearchNext(context, state, &begin) )
|
||||
return;
|
||||
|
||||
result->lo_hitLine.region = LO_HIT_LINE_REGION_BEFORE;
|
||||
result->lo_hitLine.selection.begin.position = 0;
|
||||
}
|
||||
if( end->type == LO_CELL )
|
||||
{
|
||||
/* New hit type: For single click after the table,
|
||||
* this is the same as LO_HIT_LINE,
|
||||
* and it will position caret at end of the line
|
||||
* For double-click, it signals processing same as single click
|
||||
* For single or double click before the table, it will select the table
|
||||
*/
|
||||
result->lo_hitLine.type = LO_HIT_TABLE_LINE;
|
||||
|
||||
/* Set the result data - make begin and end the same */
|
||||
result->lo_hitLine.selection.begin.element = begin;
|
||||
result->lo_hitLine.selection.end.element = begin;
|
||||
result->lo_hitLine.selection.end.position = result->lo_hitLine.selection.begin.position;
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
LO_HIT_CONTINUE:
|
||||
/* Search forward to find the end of line */
|
||||
for ( ;
|
||||
end;
|
||||
@ -4653,7 +4793,7 @@ void lo_HitLine2(MWContext *context, lo_DocState *state, LO_Element* element,
|
||||
* Select the previous line.
|
||||
*/
|
||||
if ( lo_EnsureEditableSearchPrev(context, state, & begin) ){
|
||||
lo_HitLine2(context, state, begin, 0, 0, result);
|
||||
lo_HitLine2(context, state, begin, 0, 0, 0, result);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -4805,8 +4945,7 @@ void LO_Hit(MWContext *context, int32 x, int32 y, Bool requireCaret,
|
||||
|
||||
#ifdef DEBUG
|
||||
{
|
||||
/* const char* kTypes[] = { "LO_HIT_UNKNOWN", "LO_HIT_LINE", "LO_HIT_ELEMENT"};*/
|
||||
XP_ASSERT ( result->type >= LO_HIT_UNKNOWN && result->type <= LO_HIT_ELEMENT );
|
||||
XP_ASSERT ( result->type >= LO_HIT_UNKNOWN && result->type <= LO_HIT_TABLE_LINE );
|
||||
}
|
||||
|
||||
#if 0
|
||||
@ -4901,6 +5040,26 @@ Bool lo_ProcessClick(MWContext *context, lo_TopState *top_state, lo_DocState *st
|
||||
{
|
||||
switch ( result->type )
|
||||
{
|
||||
case LO_HIT_TABLE_LINE:
|
||||
{
|
||||
if( result->lo_hitLine.region == LO_HIT_LINE_REGION_BEFORE )
|
||||
{
|
||||
/* Click before a table
|
||||
* Analogous to clicking before a line selects the line,
|
||||
* clicking before a table selects the entire table
|
||||
*/
|
||||
LO_TableStruct *table = lo_GetParentTable(context, result->lo_hitLine.selection.end.element);
|
||||
if( table )
|
||||
{
|
||||
edt_ForceTableSelection(context, table);
|
||||
}
|
||||
}
|
||||
/* Set insert point to the the supplied element
|
||||
(we trust it was already set to an editable element) */
|
||||
lo_SetInsertPoint(context, top_state, result->lo_hitLine.selection.begin.element,
|
||||
result->lo_hitLine.selection.begin.position, layer);
|
||||
break;
|
||||
}
|
||||
case LO_HIT_LINE:
|
||||
{
|
||||
switch ( result->lo_hitLine.region )
|
||||
@ -4917,7 +5076,6 @@ Bool lo_ProcessClick(MWContext *context, lo_TopState *top_state, lo_DocState *st
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Select the line */
|
||||
lo_ExtendToIncludeHardBreak(context, state, & result->lo_hitLine.selection);
|
||||
lo_SetSelection(context, & result->lo_hitLine.selection, FALSE);
|
||||
return TRUE;
|
||||
@ -4948,10 +5106,30 @@ Bool lo_ProcessClick(MWContext *context, lo_TopState *top_state, lo_DocState *st
|
||||
{
|
||||
case LO_HIT_ELEMENT_REGION_BEFORE:
|
||||
{
|
||||
|
||||
if( requireCaret || lo_GetParentTable(context, eptr) == 0 )
|
||||
{
|
||||
/* Not in a table cell or we need a caret
|
||||
Just set insert point at beginning of element
|
||||
*/
|
||||
lo_SetInsertPoint(context, top_state, eptr, position,
|
||||
layer);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Inside a cell: Select the line
|
||||
For some reason (unknown to cmanske)
|
||||
the lo_hitLine.selection.end element is not
|
||||
filled in correctly -- just use the beginning element
|
||||
*/
|
||||
result->lo_hitLine.selection.end = result->lo_hitLine.selection.begin;
|
||||
lo_ExtendToIncludeHardBreak(context, state, & result->lo_hitLine.selection);
|
||||
lo_SetSelection(context, & result->lo_hitLine.selection, FALSE);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case LO_HIT_ELEMENT_REGION_MIDDLE:
|
||||
{
|
||||
@ -5006,7 +5184,7 @@ LO_Element * lo_PositionDropCaret(MWContext *pContext, int32 x, int32 y, int32 *
|
||||
|
||||
LO_Hit(pContext, x, y, FALSE /*requireCaret*/, &result, 0);
|
||||
|
||||
/* This was copied from lo_ProcessClick above
|
||||
/* This was copied from lo_ProcessClick above and modified
|
||||
* We want to execute most of the same logic to locate the caret position
|
||||
* without calling lo_SetInsertPoint, which sets the regular caret
|
||||
* and is incompatable with a selection
|
||||
@ -5014,6 +5192,13 @@ LO_Element * lo_PositionDropCaret(MWContext *pContext, int32 x, int32 y, int32 *
|
||||
|
||||
switch ( result.type )
|
||||
{
|
||||
case LO_HIT_TABLE_LINE:
|
||||
if( result.lo_hitLine.region == LO_HIT_LINE_REGION_BEFORE
|
||||
|| result.lo_hitLine.region == LO_HIT_LINE_REGION_AFTER )
|
||||
{
|
||||
eptr = result.lo_hitLine.selection.begin.element;
|
||||
position = result.lo_hitLine.selection.begin.position;
|
||||
}
|
||||
case LO_HIT_LINE:
|
||||
switch ( result.lo_hitLine.region )
|
||||
{
|
||||
@ -5741,7 +5926,8 @@ lo_FindLineEdge(MWContext* context, lo_DocState *state, LO_Position* where, LO_P
|
||||
}
|
||||
else {
|
||||
LO_HitResult result;
|
||||
lo_HitLine2(context, state, where->element, where->position, where->element->lo_any.x, &result);
|
||||
lo_HitLine2(context, state, where->element, where->position,
|
||||
where->element->lo_any.x, where->element->lo_any.y, &result);
|
||||
if ( result.type != LO_HIT_LINE )
|
||||
{
|
||||
XP_ASSERT(FALSE);
|
||||
@ -5980,6 +6166,13 @@ Bool lo_ProcessDoubleClick(MWContext *context, lo_TopState *top_state, lo_DocSta
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
#ifdef EDITOR
|
||||
case LO_HIT_TABLE_LINE:
|
||||
/* Double click before or after a line is the same as single click */
|
||||
lo_ProcessClick(context, top_state, state, result, FALSE, layer);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -341,6 +341,16 @@ void CStreamOutMemory::Write( char *pSrc, int32 iCount ){
|
||||
m_pBuffer[m_bufferEnd] = '\0';
|
||||
}
|
||||
|
||||
// Poke an int directly into the stream
|
||||
// Used to write header params that we can't know while building a stream
|
||||
void CStreamOutMemory::WriteIntAtIndex( int32 iValue, int32 iIndex )
|
||||
{
|
||||
if( iIndex < m_bufferEnd )
|
||||
{
|
||||
XP_HUGE_MEMCPY( &m_pBuffer[iIndex], (char*)&iValue, sizeof(int32) );
|
||||
}
|
||||
}
|
||||
|
||||
// class CConvertCSIDStreamOut
|
||||
|
||||
CConvertCSIDStreamOut::CConvertCSIDStreamOut(int16 oldCSID, int16 newCSID, IStreamOut* pStream){
|
||||
|
@ -100,6 +100,9 @@ public:
|
||||
virtual void Write( char *pBuffer, int32 iCount );
|
||||
XP_HUGE_CHAR_PTR GetText(){ return m_pBuffer; }
|
||||
int32 GetLen(){ return m_bufferEnd; }
|
||||
|
||||
// For poking values into a stream at specific locations
|
||||
void WriteIntAtIndex( int32 iValue, int32 iIndex );
|
||||
};
|
||||
|
||||
// Convert character set encodings while streaming out.
|
||||
|
Loading…
Reference in New Issue
Block a user