Fixed lots of Composer bugs. Implemented delete/copy accross table cell boundaries

This commit is contained in:
cmanske%netscape.com 1998-09-28 22:51:10 +00:00
parent 9d308ed6ba
commit d26815794e
10 changed files with 1488 additions and 241 deletions

View File

@ -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);
@ -3720,16 +3739,22 @@ public:
void PasteTable( CEditTableCellElement *pCell, CEditTableElement *pSourceTable, ED_PasteType iPasteType );
EDT_ClipboardResult PasteHREF( char **ppHref, char **ppTitle, int iCount);
EDT_ClipboardResult CopySelection( char **ppText, int32* pTextLen,
char **ppHtml, int32* pHtmlLen);
char **ppHtml, int32* pHtmlLen);
XP_Bool CopyBetweenPoints( CEditElement *pBegin,
CEditElement *pEnd, char **ppText, int32* pTextLen,
char **ppHtml, int32* pHtmlLen );
// 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,
char **ppHtml, int32* pHtmlLen, ED_CopyType iCopyType = ED_COPY_NORMAL );
char **ppHtml, int32* pHtmlLen, ED_CopyType iCopyType = ED_COPY_NORMAL );
//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

View File

@ -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);
}
}
}

View File

@ -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 = "&nbsp;";
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

View File

@ -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,9 +4299,11 @@ XP_Bool CSizingObject::Create(CEditBuffer *pBuffer,
m_pLoElement = pElement;
break;
}
pElement = pElement->lo_any.next;
if( pElement != pLastElement )
pElement = pElement->lo_any.next;
}
while( pElement != pLastElement );
}
}
if( m_iStyle == ED_SIZE_BOTTOM && lo_GetRowSpan(m_pLoElement) > 1 )
{
@ -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,9 +4321,11 @@ XP_Bool CSizingObject::Create(CEditBuffer *pBuffer,
m_pLoElement = pElement;
break;
}
pElement = pElement->lo_any.next;
if( pElement != pLastElement )
pElement = pElement->lo_any.next;
}
while( pElement != pLastElement );
}
}
}
@ -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,8 +4910,8 @@ void CSizingObject::ResizeObject()
EraseAddRowsOrCols();
int32 iWidth=0, iWidthPixels=0, iHeightPixels=0, iHeight=0;
// Get the element being sized (except table or cell - obtained below)
CEditLeafElement *pElement = (CEditLeafElement*)(m_pLoElement->lo_any.edit_element);
// 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

View File

@ -5209,8 +5209,10 @@ lo_GetLineEnds(MWContext *context, lo_DocState *state,
int32 line, LO_Element** retBegin, LO_Element** retEnd)
{
LO_Element **line_array;
*retBegin = NULL;
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,44 +5433,46 @@ 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)&&
(x < (x1 + t_width)))
{
/*
* Tables are containers. Don't stop on them,
* look inside them.
*/
if (tptr->type != LO_TABLE)
{
/* Inflow layers look just like table cells, but we
always look inside them, as if the layout elements
were part of the line's list of element's. */
if (is_inflow_layer && into_ilayers) {
eptr = lo_XYToCellElement(context, state,
(LO_CellStruct *)tptr, x, y,
TRUE, into_cells, into_ilayers);
if (eptr) {
tptr = eptr;
break;
}
/* No matching element found inside cell, keep
looking on rest of line. */
} else
break;
}
else
{
in_table = TRUE;
/*
* Save the table element
* to return if no other element is found
*/
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)))
{
/*
* Tables are containers. Don't stop on them,
* look inside them.
*/
if (tptr->type != LO_TABLE)
{
/* Inflow layers look just like table cells, but we
always look inside them, as if the layout elements
were part of the line's list of element's. */
if (is_inflow_layer && into_ilayers) {
eptr = lo_XYToCellElement(context, state,
(LO_CellStruct *)tptr, x, y,
TRUE, into_cells, into_ilayers);
if (eptr) {
tptr = eptr;
break;
}
/* No matching element found inside cell, keep
looking on rest of line. */
} else
break;
}
else
{
in_table = TRUE;
}
}
}
tptr = tptr->lo_any.next;
}
if (tptr == end_ptr)
@ -5546,10 +5568,20 @@ XP_TRACE(("lo_PointToLine says line %d\n", line));
tptrCell = tptr;
tptr = lo_XYToCellElement(context, state,
(LO_CellStruct *)tptr, x, y, TRUE, into_cells, into_ilayers);
}
}
*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);
}

View File

@ -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_ */

View File

@ -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,9 +5106,29 @@ Bool lo_ProcessClick(MWContext *context, lo_TopState *top_state, lo_DocState *st
{
case LO_HIT_ELEMENT_REGION_BEFORE:
{
lo_SetInsertPoint(context, top_state, eptr, position,
layer);
return FALSE;
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;
}

View File

@ -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){

View File

@ -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.