Composer work: Check for valid charset in metatag, paste character style, split table cell, optimization for table cell layout (not turned on), remove P_MENU, P_DIRECTORY support for UIs

This commit is contained in:
cmanske%netscape.com 1998-09-02 14:21:41 +00:00
Родитель b3671f82b9
Коммит bb022be61f
10 изменённых файлов: 854 добавлений и 97 удалений

Просмотреть файл

@ -1036,8 +1036,14 @@ intn EDT_ProcessTag(void *data_object, PA_Tag *tag, intn status){
parseRet = pDocData->edit_buffer->ParseTag( pDocData, tag, status );
}
if( parseRet != OK_IGNORE ){
//Braindead: Any value except NOT_OK will continue parsing
// 9/1/98 OK_STOP is not currently used at all
// NOT_OK is used to abort while parsing the Content-Type metatag
// because charset is bad
if( parseRet == NOT_OK )
return NOT_OK;
if( parseRet != OK_IGNORE ){
#if 0
//
// Check to see if the tag went away. Text without an Edit Element
@ -1061,7 +1067,7 @@ intn EDT_ProcessTag(void *data_object, PA_Tag *tag, intn status){
}
else{
PA_FreeTag(tag);
return 1;
return OK_CONTINUE;
}
}
@ -1492,9 +1498,16 @@ void EDT_SetTableAlign( MWContext *pContext, ED_Alignment eAlign ){
void EDT_MorphContainer( MWContext *pContext, TagType t ){
GET_WRITABLE_EDIT_BUF_OR_RETURN(pContext, pEditBuffer);
pEditBuffer->BeginBatchChanges(kParagraphAlignCommandID);
// These are no longer supported
if( t == P_DIRECTORY ||
t == P_MENU )
{
t = P_UNUM_LIST;
}
if( t == P_BLOCKQUOTE ||
t == P_DIRECTORY ||
t == P_MENU ||
t == P_UNUM_LIST ||
t == P_NUM_LIST ||
t == P_DESC_LIST){
pEditBuffer->MorphListContainer( t );
} else {
@ -1898,10 +1911,9 @@ void EDT_ConvertTableToText(MWContext *pMWContext)
}
/* Save the character and paragraph style of selection or at caret */
/* TODO: REMOVE AFTER CONFIRMING ITS NOT BEING USED ON ALL PLATFORMS */
void EDT_CopyStyle(MWContext *pMWContext)
{
GET_EDIT_BUF_OR_RETURN(pMWContext, pEditBuffer);
pEditBuffer->CopyStyle();
}
/* TRUE if no mouse actions taken since last EDT_CopyStyle call */

Просмотреть файл

@ -1263,7 +1263,8 @@ public:
void SetSpecialSelected(XP_Bool bSelected) { m_bSpecialSelected = bSelected; }
// Move contents of supplied cell into this cell
void MergeCells(CEditTableCellElement* pCell);
// If merging results in a row deletion, iNewRowSpan is adjusted
void MergeCells(CEditTableCellElement* pCell, int32& iNewRowSpan);
void SplitCell();
// Delete all contents, leaving just the minimum empty text element
@ -3368,10 +3369,7 @@ public:
// Convert the table into text - unravel existing paragraphs in cells
void ConvertTableToText();
// Save the character and paragraph style of selection or at caret
void CopyStyle();
// This is TRUE after EDT_CopyStyle is called, until the next left mouse up call
// This is TRUE after any HTML is copied
XP_Bool CanPasteStyle() { return (m_pCopyStyleCharacterData != NULL); }
// Apply the style to selection or at caret. Use bApplyStyle = FALSE to cancel
@ -3497,9 +3495,11 @@ public:
void SetMetaData( EDT_MetaData *pMetaData );
void DeleteMetaData( EDT_MetaData *pMetaData );
static void FreeMetaData( EDT_MetaData *pMetaData );
void ParseMetaTag( PA_Tag *pTag );
void ParseMetaTag( PA_Tag *pTag, intn& retVal );
void PrintMetaData( CPrintState *pPrintState );
void PrintMetaData( CPrintState *pPrintState, int index );
// Return FALSE only if we are closing down
XP_Bool CheckCharset( EDT_MetaData *pData,int16 win_csid );
EDT_HorizRuleData* GetHorizRuleData();
void SetHorizRuleData( EDT_HorizRuleData* pData );
@ -3986,6 +3986,8 @@ public:
void ChangeEncoding(int16 csid);
void SetEncoding(int16 csid);
void SetEncoding(char *pCharset);
XP_Bool HasEncoding();
// Used for QA only - Ctrl+Alt+Shift+N accelerator for automated testing

Просмотреть файл

@ -23,7 +23,8 @@
#include "prefapi.h"
#include "intl_csi.h"
#define CONTENT_TYPE "Content-Type"
#define CONTENT_TYPE "Content-Type"
#define PARAM_CHARSET "charset"
// Maximum length of "positional text" - see GetPositionalText().
#ifdef XP_WIN16
@ -568,6 +569,11 @@ intn CEditBuffer::ParseTag(pa_DocData *pData, PA_Tag* pTag, intn status){
NormalizeEOLsInTag(pTag);
// 8/31/98: List types no longer supported
// (they were always displayed the same as P_UNUM_LIST anyway)
if( pTag->type == P_MENU || P_DIRECTORY )
pTag->type == P_UNUM_LIST;
/* P_STRIKE is a synonym for P_STRIKEOUT. Since pre-3.0 versions of
* Navigator don't recognize P_STRIKE ( "<S>" ), we switch it to
* P_STRIKEOUT ( "<STRIKE>" ). Also, it would complicate the
@ -1187,7 +1193,7 @@ intn CEditBuffer::ParseOpenTag(pa_DocData *pData, PA_Tag* pTag, intn status){
break;
case P_META:
ParseMetaTag( pTag );
ParseMetaTag( pTag, retVal );
break;
case P_BASE:
@ -2123,7 +2129,7 @@ void CEditBuffer::Reflow( CEditElement* pStartElement,
}
#endif
XP_Bool bInTableCell = pStartElement ? (pStartElement->GetTableIgnoreSubdoc() != NULL) : FALSE;
CEditTableCellElement *pCell = FALSE;
// laying out from the beginning of the document
if( pNewStartElement == 0 ){
@ -2156,23 +2162,39 @@ void CEditBuffer::Reflow( CEditElement* pStartElement,
// Note: If here, we must have a pStartElement and associated LO_Element
XP_ASSERT(pStartElement && pLayoutElement);
// Find the first element on this line and get the current line number
pLoStartLine = FirstElementOnLine( pLayoutElement, &iLineNum );
//
// Position the tag cursor at this position
//
pLoStartLine = FirstElementOnLine( pLayoutElement, &iLineNum );
pEdStart = pLoStartLine->lo_any.edit_element;
iOffset = pLoStartLine->lo_any.edit_offset;
// If we are entirely within one cell, then use new cell reflow
// ****** TODO: FINISH THIS WORK BEFORE ACTIVATING
//pCell = pStartElement->GetTableCellIgnoreSubdoc();
if( pCell && pCell == pEndElement->GetTableCellIgnoreSubdoc() )
{
// Start with first element in the cell
pEdStart = pCell->GetFirstMostChild()->Leaf();
XP_ASSERT(pEdStart);
iOffset = 0;
}
else
{
// Clear this - we use it below to tell how to reflow
pCell = NULL;
// Find the first element on this line and get the current line number
pLoStartLine = FirstElementOnLine( pLayoutElement, &iLineNum );
//
// Position the tag cursor at this position
//
pLoStartLine = FirstElementOnLine( pLayoutElement, &iLineNum );
pEdStart = pLoStartLine->lo_any.edit_element;
iOffset = pLoStartLine->lo_any.edit_offset;
}
}
// Create a new cursor.
// Create a new cursor and reflow
CEditTagCursor cursor(this, pEdStart, iOffset, pEndElement);
//CEditTagCursor *pCursor = new CEditTagCursor(this, m_pRoot, iOffset);
LO_EditorReflow(m_pContext, &cursor, iLineNum, iOffset);
if( pCell )
lo_EditorCellReflow(m_pContext, &cursor, GetLoCell(pCell));
else
lo_EditorReflow(m_pContext, &cursor, iLineNum, iOffset);
#if defined( DEBUG_shannon )
XP_TRACE(("\n\nEDITOR REFLOW"));
@ -4245,7 +4267,9 @@ void CEditBuffer::MorphContainer( TagType t )
TagType tList = pList->GetType();
// Assure that list-type items are only contained in their proper parents.
// If not the right type, terminate the list
if( ((tList == P_UNUM_LIST || tList == P_NUM_LIST || tList == P_MENU || tList == P_DIRECTORY) &&
// We should never see P_MENU or P_DIRECTORY any more
// (translated into P_UNUM_LIST in ::ParseTag() )
if( ((tList == P_UNUM_LIST || tList == P_NUM_LIST /*|| tList == P_MENU || tList == P_DIRECTORY*/) &&
t != P_LIST_ITEM) ||
(tList == P_DESC_LIST && !(t == P_DESC_TITLE || t == P_DESC_TEXT)) )
{
@ -5872,16 +5896,8 @@ void CEditBuffer::ConvertTableToText()
}
}
// Save the character and paragraph style of selection or at caret
void CEditBuffer::CopyStyle()
{
if( m_pCopyStyleCharacterData )
EDT_FreeCharacterData(m_pCopyStyleCharacterData);
m_pCopyStyleCharacterData = GetCharacterData();
}
// Apply the style to selection or at caret. Use bApplyStyle = FALSE to cancel
// Apply the style to selection or at caret.
// Use bApplyStyle = FALSE to delete the saved style data
void CEditBuffer::PasteStyle(XP_Bool bApplyStyle)
{
if( m_pCopyStyleCharacterData )
@ -5890,8 +5906,11 @@ void CEditBuffer::PasteStyle(XP_Bool bApplyStyle)
{
SetCharacterData(m_pCopyStyleCharacterData);
}
EDT_FreeCharacterData(m_pCopyStyleCharacterData);
m_pCopyStyleCharacterData = NULL;
else
{
EDT_FreeCharacterData(m_pCopyStyleCharacterData);
m_pCopyStyleCharacterData = NULL;
}
}
}
@ -6160,38 +6179,209 @@ void CEditBuffer::FreeMetaData( EDT_MetaData *pData ){
}
}
void CEditBuffer::ParseMetaTag( PA_Tag *pTag ){
void CEditBuffer::ParseMetaTag( PA_Tag *pTag, intn& retVal )
{
XP_Bool bHttpEquiv = TRUE;
char *pName;
char *pContent;
INTL_CharSetInfo c = LO_GetDocumentCharacterSetInfo(m_pContext);
int16 win_csid = INTL_GetCSIWinCSID(c);
retVal = OK_CONTINUE;
pContent = edt_FetchParamString( pTag, PARAM_CONTENT, win_csid );
pName = edt_FetchParamString( pTag, PARAM_HTTP_EQUIV, win_csid );
// if we didn't get http-equiv, try for name=
if( pName == 0 ){
if( pName == 0 )
{
bHttpEquiv = FALSE;
pName = edt_FetchParamString( pTag, PARAM_NAME, win_csid );
}
// if we got one or the other, add it to the list of meta tags.
if( pName ){
if( pName )
{
EDT_MetaData *pData = MakeMetaData( bHttpEquiv, pName, pContent );
// We want to allow multiple entries with the same NAME,
// as long as CONTENT is different. So setting these the same
// will make FindMetaData() match CONTENT as well as NAME
// when deciding to replace and existing meta entry
pData->pPrevContent = pData->pContent;
SetMetaData( pData );
FreeMetaData( pData );
// Check our charset string for validity
// (We may close done the buffer in this routine)
if( CheckCharset(pData, win_csid) )
{
// We want to allow multiple entries with the same NAME,
// as long as CONTENT is different. So setting these the same
// will make FindMetaData() match CONTENT as well as NAME
// when deciding to replace and existing meta entry
pData->pPrevContent = pData->pContent;
SetMetaData( pData );
FreeMetaData( pData );
}
else
{
// Signal to stop parsing
// This alone seems to be enough to abort parsing,
// the net stream, and close the window!
retVal = NOT_OK;
}
}
if( pName ) XP_FREE( pName );
if( pContent ) XP_FREE( pContent );
}
static void edt_ReplaceCharset(EDT_MetaData *pData, char *pNewCharset)
{
// Find the string "charset" in the content string
char *pCharset = XP_STRSTR(pData->pContent, PARAM_CHARSET);
if( !pCharset )
{
CHARSET_ERROR:
XP_ASSERT(0);
return;
}
// Find the '=' after "charset"
char *pEqual = XP_STRCHR(pCharset, '=');
if( !pEqual )
goto CHARSET_ERROR;
char *tptr = pEqual+1;
// Terminate here -- this is where we will append the new string
*tptr = '\0';
tptr++;
// Skip over whitespace before chaset name
while (XP_IS_SPACE(*tptr))
tptr++;
//Then find end of old charset string
// This assumes charset string can have no spaces in it
while( *tptr && !XP_IS_SPACE(*tptr) && *tptr != '\"' && *tptr != '>')
tptr++;
// Copy this to append at the end,
// (this allows other params after charset to be retained)
char *pEnd = NULL;
if( *tptr )
pEnd = XP_STRDUP(tptr);
// Rebuild complete "Content=" string
// This avoids realloc if new and old string are the same size
pData->pContent = PR_sprintf_append(pData->pContent, pNewCharset);
if( pEnd )
{
pData->pContent = PR_sprintf_append(pData->pContent, pEnd);
XP_FREE(pEnd);
}
}
// Return FALSE only if we are closing down
XP_Bool CEditBuffer::CheckCharset( EDT_MetaData *pData, int16 win_csid )
{
XP_Bool bRetVal = TRUE;
int16 default_csid = FE_DefaultDocCharSetID(m_pContext);
if( CS_USRDEF2 != default_csid &&
CS_USER_DEFINED_ENCODING != default_csid &&
pData && pData->bHttpEquiv && pData->pName && pData->pContent &&
0 == XP_STRCASECMP(pData->pName, CONTENT_TYPE) )
{
// Example of a charset meta tag:
//<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
// Create a simple tag so we can use tag-parsing to extract charset
// PA_FetchParamValue (called from edt_FetchParamString)
// needs a terminal '>' to work
int iLen = XP_STRLEN(pData->pContent);
char *pContent = (char*)XP_ALLOC(iLen+1);
if( !pContent )
return FALSE; //Abort if not enough memory?
XP_STRCPY(pContent, pData->pContent);
pContent[iLen] = '>';
iLen++;
pContent[iLen] = '\0';
PA_Tag *pTag = XP_NEW( PA_Tag );
XP_BZERO( pTag, sizeof( PA_Tag ) );
pTag->data_len = iLen;
pTag->data_str = XP_STRDUP(pContent);
char *pCharset = edt_FetchParamString(pTag, PARAM_CHARSET, win_csid );
PA_FREE(pTag);
if( pCharset )
{
int iBufLen = 255;
char buf[256];
char *pMsg = NULL;
//ftang: Implement this!
// if(CS_UNKNOWN == INTL_NameToCharSetID(pCharset))
if(FALSE)
{
// Get the default charset
//INTL_CharSetIDToName(default_csid, &pDefaultCharset);
// Above uses presized buffer, but calls following, so this is safer:
// (Don't free this string!)
char *pDefaultCharset = (char *)INTL_CsidToCharsetNamePt(default_csid);
if( pDefaultCharset )
{
// Build a very wordy message box with the default and current
// charset strings inserted
PR_snprintf(buf, iBufLen, XP_GetString(XP_EDT_CHARSET_LABEL), pCharset);
pMsg = PR_sprintf_append(pMsg, buf);
pMsg = PR_sprintf_append(pMsg, XP_GetString(XP_EDT_CHARSET_CANT_EDIT));
PR_snprintf(buf, iBufLen, XP_GetString(XP_EDT_CURRENT_CHARSET), pDefaultCharset);
pMsg = PR_sprintf_append(pMsg, buf);
PR_snprintf(buf, iBufLen, XP_GetString(XP_EDT_CHARSET_EDIT_REPLACE), pDefaultCharset);
pMsg = PR_sprintf_append(pMsg, buf);
pMsg = PR_sprintf_append(pMsg, XP_GetString(XP_EDT_CHARSET_EDIT_CANCEL));
// If user chooses "Cancel", then we should abort editing
bRetVal = FE_Confirm(m_pContext, pMsg);
if( bRetVal )
{
// Change to the default charset
edt_ReplaceCharset(pData, pDefaultCharset);
}
}
else
bRetVal = FALSE; //Abort if no default charset?
}
else
{
//ftang: Implement this! If this should NOT be freed,
// then please remove the XP_FREEIF below
//pNewCharset = INTL_CharsetCorrection(pCharset);
char *pCorrectCharset = XP_STRDUP(pCharset);
// ftang: If this should be XP_STRCMP instead, please change it
if( pCorrectCharset && 0 != XP_STRCASECMP(pCorrectCharset, pCharset) )
{
// See if user wants to replace charset with the "correct" string
// In either case, we continue editing
PR_snprintf(buf, iBufLen, XP_GetString(XP_EDT_CHARSET_LABEL), pCharset);
pMsg = PR_sprintf_append(pMsg, buf);
PR_snprintf(buf, iBufLen, XP_GetString(XP_EDT_CURRENT_CHARSET), pCorrectCharset);
pMsg = PR_sprintf_append(pMsg, buf);
PR_snprintf(buf, iBufLen, XP_GetString(XP_EDT_CHARSET_EDIT_REPLACE), pCorrectCharset);
pMsg = PR_sprintf_append(pMsg, buf);
PR_snprintf(buf, iBufLen, XP_GetString(XP_EDT_CHARSET_EDIT_NOREPLACE), pCharset);
pMsg = PR_sprintf_append(pMsg, buf);
if( FE_Confirm(m_pContext, pMsg) )
{
// Change to the "correct" charset
edt_ReplaceCharset(pData, pCorrectCharset);
}
}
XP_FREEIF(pCorrectCharset);
}
XP_FREE(pCharset);
}
}
return bRetVal;
}
// Image
@ -6798,7 +6988,7 @@ void CEditBuffer::MergeTableCells()
EDT_FreeTableCellData(pNextCellData);
}
// Move all contents of Next cell into First cell and delete Next cell
pFirstCell->MergeCells(pNextCell);
pFirstCell->MergeCells(pNextCell, pFirstCellData->iRowSpan);
}
} else {
// We are merging with just the next cell to the right
@ -6809,7 +6999,7 @@ void CEditBuffer::MergeTableCells()
pFirstCellData->iColSpan += pNextCellData->iColSpan;
EDT_FreeTableCellData(pNextCellData);
}
pFirstCell->MergeCells( pNextCell );
pFirstCell->MergeCells(pNextCell, pFirstCellData->iRowSpan);
}
// Set the COLSPAN and ROWSPAN data for the merged cell
pFirstCell->SetData(pFirstCellData);
@ -6832,13 +7022,19 @@ void CEditBuffer::MergeTableCells()
*/
void CEditBuffer::SplitTableCell()
{
// Set beginning of UNDO block
BeginBatchChanges(kGroupOfChangesCommandID);
CEditInsertPoint ip;
GetTableInsertPoint(ip);
CEditTableElement* pTable = ip.m_pElement->GetTableIgnoreSubdoc();
CEditTableCellElement* pCell = ip.m_pElement->GetTableCellIgnoreSubdoc();
if( !pCell )
if( pTable == NULL || pCell == NULL )
return;
pCell->SplitCell();
Relayout(pTable, 0, pTable);
EndBatchChanges();
}
@ -13952,6 +14148,17 @@ EDT_ClipboardResult CEditBuffer::CopySelection( char **ppText, int32* pTextLen,
// Get normal selection
GetSelection(selection);
iCopyType = ED_COPY_NORMAL;
// Copy character attributes only if start of selection is text
// This can be "pasted" onto a selection or at the caret
if( selection.m_start.m_pElement->IsText() )
{
if( m_pCopyStyleCharacterData )
EDT_FreeCharacterData(m_pCopyStyleCharacterData);
// Save attributes of start element only
m_pCopyStyleCharacterData = selection.m_start.m_pElement->Text()->GetData();
}
}
// Build the HTML stream from the selection
if( !selection.IsEmpty() )
@ -17043,17 +17250,31 @@ void CEditBuffer::ChangeEncoding(int16 csid) {
// See RFC 2070, "Internationalization of the Hypertext Markup Language"
// http://ds.internic.net/rfc/rfc2070.txt
// <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=ISO-2022-JP">
void CEditBuffer::SetEncoding(int16 csid) {
char contentValue[200];
char charSet[100];
void CEditBuffer::SetEncoding(int16 csid)
{
int16 plainCSID = csid & ~CS_AUTO;
INTL_CharSetIDToName(plainCSID, charSet);
XP_SPRINTF(contentValue, "text/html; charset=%.100s", charSet);
// This is better than INTL_CharSetIDToName, which needs presized buffer;
// (Don't free this string!)
char *charSet = (char *)INTL_CsidToCharsetNamePt(plainCSID);
SetEncoding(charSet);
}
EDT_MetaData *pData = MakeMetaData( TRUE, CONTENT_TYPE, contentValue);
void CEditBuffer::SetEncoding(char *pCharset)
{
char pContent[128];
if( pCharset && *pCharset )
{
XP_SPRINTF(pContent, "text/html; charset=%.100s", pCharset);
SetMetaData( pData );
FreeMetaData( pData );
EDT_MetaData *pData = MakeMetaData( TRUE, CONTENT_TYPE, pContent);
if( pData )
{
SetMetaData( pData );
FreeMetaData( pData );
}
else
XP_ASSERT(0);
}
}
XP_Bool CEditBuffer::HasEncoding() {

Просмотреть файл

@ -6239,29 +6239,94 @@ void CEditTableCellElement::SplitCell()
pBuffer->SetFillNewCellWithSpace();
CEditTableCellElement *pNewCell;
for( intn iRow = 0; iRow < m_iRowSpan; iRow++ )
int32 iNewRows = m_iRowSpan - 1;
int32 iNewCells = m_iColSpan - 1;
intn iNextRow = m_iRow + 1;
CEditTableRowElement *pCurrentRow = (CEditTableRowElement*)GetParent();
XP_ASSERT(pCurrentRow && pCurrentRow->IsTableRow());
CEditTableRowElement *pRow = pCurrentRow;
// Copy current cell's color and background image to all new cells
EDT_TableCellData *pData = GetData();
EDT_TableCellData *pNewData = NewData();
XP_ASSERT(pData && pNewData);
if( !pData || !pNewData )
return;
pData->mask = CF_BACK_COLOR | CF_BACK_IMAGE;
edt_CopyTableCellData(pNewData, pData);
// Insert new cells in the current row if needed
for( int i = 0; i < iNewCells; i++ )
{
for( intn iCol = 0; iCol < m_iColSpan; iCol++ )
pNewCell = new CEditTableCellElement;
pNewCell->InsertAfter(this);
pNewCell->FinishedLoad(pBuffer);
// Set background attributes
pNewCell->SetData(pNewData);
}
// Insert new cells in following rows
for( int iRow = 0; iRow < iNewRows; iRow++ )
{
// Get the next existing row
if( pRow )
pRow = (CEditTableRowElement*)pRow->GetNextSibling();
if( pRow )
{
pNewCell = new CEditTableCellElement;
pNewCell->InsertAfter(this);
pNewCell->FinishedLoad(pBuffer);
// Starting with first cell in row, find the cell
// just after "this" cell's column
CEditTableCellElement *pCell = (CEditTableCellElement*)pRow->GetChild();
while( pCell && pCell->GetX() <= m_X )
pCell = (CEditTableCellElement*)pCell->GetNextSibling();
// Insert new cells before the one we found
for( int i = 0; i < m_iColSpan; i++ )
{
pNewCell = new CEditTableCellElement;
if( pCell )
pNewCell->InsertBefore(pCell);
else
// Row has no cells! (Table is messed up)
pNewCell->InsertAsFirstChild(pRow);
pNewCell->FinishedLoad(pBuffer);
// Set background attributes
pNewCell->SetData(pNewData);
}
}
else
{
// If no row, table is messed up.
// But we can fix it by simply inserting a new row
CEditTableRowElement *pNewRow = new CEditTableRowElement(m_iColSpan);
if( pNewRow == NULL )
break;
pNewRow->InsertAfter(pCurrentRow);
pCurrentRow = pNewRow;
pRow->FinishedLoad(pBuffer);
// Set background attributes in cells created with the row
CEditTableCellElement *pNewRowCell = (CEditTableCellElement*)pRow->GetChild();
while( pNewRowCell )
{
pNewRowCell->SetData(pNewData);
pNewRowCell = (CEditTableCellElement*)pNewRowCell->GetNextSibling();
}
}
}
// Now reset values in current cell
EDT_TableCellData *pData = GetData();
if( pData )
{
pData->iColSpan = 1;
pData->iRowSpan = 1;
SetData(pData);
EDT_FreeTableCellData(pData);
}
pData->iColSpan = 1;
pData->iRowSpan = 1;
SetData(pData);
EDT_FreeTableCellData(pData);
EDT_FreeTableCellData(pNewData);
pBuffer->ClearFillNewCellWithSpace();
}
// Move all contents of supplied cell into this cell
void CEditTableCellElement::MergeCells(CEditTableCellElement* pCell)
void CEditTableCellElement::MergeCells(CEditTableCellElement* pCell, int32& iNewRowSpan)
{
if( !pCell || pCell == this )
return;
@ -6317,7 +6382,19 @@ void CEditTableCellElement::MergeCells(CEditTableCellElement* pCell)
// Clear pointer to children just moved
pCell->SetChild(0);
}
delete pCell;
CEditElement *pNext = pCell->GetNextSibling();
CEditElement *pPrev = pCell->GetPreviousSibling();
if( pCell->GetNextSibling() == NULL && pCell->GetPreviousSibling() == NULL )
{
// pCell is the only cell in this row, so delete the row
delete pCell->GetParent();
// Because we removed a row, the ROWSPAN is now 1 less
iNewRowSpan--;
}
else
{
delete pCell;
}
}
void CEditTableCellElement::DeleteContents(XP_Bool bMarkAsDeleted)

Просмотреть файл

@ -6193,31 +6193,34 @@ void EDT_SetRefresh( MWContext* pContext, XP_Bool bRefreshOn ){
}
// Warning this deletes (and recreates) the CEditBuffer.
// Warning this deletes (and recreates) the CEditBuffer if we ChangeEncoding
XP_Bool EDT_SetEncoding(MWContext* pContext, int16 csid){
GET_EDIT_BUF_OR_RETURN(pContext, pEditBuffer) FALSE;
ED_CharsetEncode bDoIt;
// if ( pEditBuffer->HasEncoding() ) {
ED_CharsetEncode result;
char* pMessage = XP_GetString(XP_EDT_I18N_HAS_CHARSET);
if ( pMessage ) {
bDoIt = FE_EncodingDialog(pContext);
result = FE_EncodingDialog(pContext);
}
else {
XP_ASSERT(0);
}
switch (bDoIt)
switch (result)
{
case ED_ENDCODE_CHANGE_CHARSET:
// Change encoding and translate document
pEditBuffer->ChangeEncoding(csid);
return TRUE;
case ED_ENCODE_CHANGE_METATAG:
// Change encoding and but don't translate document
XP_ASSERT(0); // Not implemented yet
// Set charset param in Content-Type metatag, but don't translate document
pEditBuffer->SetEncoding(csid);
return FALSE;
case ED_ENCODE_CANCEL:
return FALSE;
default:
XP_ASSERT(0);
return FALSE;

Просмотреть файл

@ -990,6 +990,130 @@ void lo_CreateCellFromSubDoc( MWContext *context, lo_DocState *state,
}
}
/*
** New functions used by the editor to improve the performance of typing in tables
**/
/* Creates and returns a new lo_DocState for an existing LO_CELL layout element to get
relaid out on. Sets the dimensions of the lo_DocState structure to those
of the LO_CELL element. */
lo_DocState * lo_CreateStateForCellLayout(MWContext *context, LO_CellStruct *cell)
{
lo_DocState *new_doc = NULL;
if (context && cell)
{
new_doc = lo_NewLayout( context, cell->width, cell->height, 0, 0, NULL );
}
return new_doc;
}
/* This function is identical to lo_ShiftCell() except that it does not move
the cell's layers */
static void
lo_OffsetCellContents(LO_CellStruct *cell, int32 dx, int32 dy)
{
LO_Element *eptr;
if (cell == NULL)
return;
eptr = cell->cell_list;
while (eptr != NULL)
{
eptr->lo_any.x += dx;
eptr->lo_any.y += dy;
if (eptr->type == LO_CELL)
{
/*
* This would cause an infinite loop.
*/
if ((LO_CellStruct *)eptr == cell)
{
XP_ASSERT(FALSE);
break;
}
lo_OffsetCellContents((LO_CellStruct *)eptr, dx, dy);
}
lo_MoveElementLayers( eptr );
eptr = eptr->lo_any.next;
}
eptr = cell->cell_float_list;
while (eptr != NULL)
{
eptr->lo_any.x += dx;
eptr->lo_any.y += dy;
if (eptr->type == LO_CELL)
{
lo_OffsetCellContents((LO_CellStruct *)eptr, dx, dy);
}
lo_MoveElementLayers( eptr );
eptr = eptr->lo_any.next;
}
}
/* Populates the LO_CELL element with the freshly generated contents of the
lo_DocState structure. Assumes that the layout elements on the lo_DocState
are hooked up to their peer editor elements in the editor content model.
Recycles the old layout elements contained in the LO_CELL element. */
void lo_RebuildCell(MWContext *context, lo_DocState *state, LO_CellStruct *cell)
{
/*** Recycle old contents of the cell ***/
if (!cell)
return;
/* If cell list exists, cell_list_end must exist too */
XP_ASSERT((cell->cell_list && cell->cell_list_end) ||
(!cell->cell_list && !cell->cell_list_end));
if (cell->cell_list && cell->cell_list_end)
{
XP_ASSERT(cell->cell_list_end->lo_any.next == NULL);
lo_RecycleElements(context, state, cell->cell_list);
}
if (cell->cell_float_list)
lo_RecycleElements(context, state, cell->cell_float_list);
cell->cell_list = NULL;
cell->cell_float_list = NULL;
cell->cell_list_end = NULL;
/*** Copy pointers to new content from the doc state to the cell ***/
/* If line array exists, end_last_line must exist too */
XP_ASSERT((state->line_array[0] && state->end_last_line) ||
(!state->line_array[0] && !state->end_last_line));
/* Ensure that the line list on the doc state has been flushed to
the line array */
XP_ASSERT(state->line_list == NULL);
if (state->line_array[0] && state->end_last_line)
{
XP_ASSERT(state->end_last_line->lo_any.next == NULL);
cell->cell_list = state->line_array[0];
cell->cell_list_end = state->end_last_line;
state->line_array[0] = NULL;
state->end_last_line = NULL;
}
if (state->float_list)
{
cell->cell_float_list = state->float_list;
state->float_list = NULL;
}
/*** Offset new content of the cell relative to the cell's position ***/
lo_OffsetCellContents( cell, cell->x, cell->y );
}
#ifdef TEST_16BIT
#undef XP_WIN16
#endif /* TEST_16BIT */

Просмотреть файл

@ -773,7 +773,7 @@ lo_DisplayElement(MWContext *context, LO_Element *tptr,
if (((LO_CellStruct*)tptr)->cell_inflow_layer)
break;
/* cmanske: reversed order so cell selection highlighing
/* cmanske: reversed order so cell selection highlighting
shows up over text in the cell */
lo_DisplayCellContents(context, (LO_CellStruct *)tptr,
base_x, base_y, x, y, width, height);

Просмотреть файл

@ -734,9 +734,11 @@ void lo_MergeElements( MWContext *context, lo_DocState *old_state, int32 iStartL
#endif /* DEBUG */
}
PRIVATE
LO_RelayoutData* lo_NewRelayoutData( MWContext* context, ED_TagCursor* pCursor,
int32 iStartLine, int iStartEditOffset )
int32 iStartLine, int iStartEditOffset, lo_DocState *new_state )
{
int32 doc_id;
LO_RelayoutData *pRd;
@ -765,9 +767,14 @@ LO_RelayoutData* lo_NewRelayoutData( MWContext* context, ED_TagCursor* pCursor,
pRd->iStartLine = iStartLine;
pRd->iStartEditOffset = iStartEditOffset;
pRd->new_state = lo_NewLayout( context, pRd->old_state->win_width,
pRd->old_state->win_height, pRd->old_state->win_left,
pRd->old_state->win_top, pRd->old_state );
/* new state was supplied */
if( new_state )
pRd->new_state = new_state;
else
pRd->new_state = lo_NewLayout( context, pRd->old_state->win_width,
pRd->old_state->win_height, pRd->old_state->win_left,
pRd->old_state->win_top, pRd->old_state );
pRd->new_state->display_blocked = TRUE;
pRd->new_state->edit_relayout_display_blocked = TRUE;
@ -862,7 +869,310 @@ LO_Element *lo_strip_mquotes(LO_Element **elist)
return mquotes;
}
void LO_EditorReflow(MWContext *context, ED_TagCursor *pCursor,
void lo_EditorCellReflow(MWContext *context, ED_TagCursor *pCursor, LO_CellStruct *pCell)
{
PA_Tag *pTag;
PA_Tag *pNextTag = 0;
LO_Element *eptr;
LO_Element **line_array;
int32 changedY, changedHeight;
LO_RelayoutData* pRd;
Bool bFoundBreak, bBreakIsEndTag;
int32 iEndLine = -1;
LO_Element *leadingMquotes = NULL;
int32 x = pCell->x + 1;
int32 y = pCell->y + 1;
lo_DocState *new_state;
int iStartEditOffset = 0;
int32 iStartLine;
if( !context || !pCursor || !pCell )
return;
LO_FirstElementOnLine(context, x, y, &iStartLine);
context->is_editor |= EDT_RELAYOUT_FLAG; /* Relayout flag */
/* Create a new doc state to layout into */
new_state = lo_CreateStateForCellLayout(context, pCell);
pRd = lo_NewRelayoutData( context, pCursor, iStartLine, iStartEditOffset, new_state );
/*************************************************************/
/* This block was copied from lo_Relayout
TODO: When things work, extract common code into a separate function */
/* save the floating element list for later deletion. */
if( pRd->old_state->float_list != 0 )
{
lo_relayout_recycle(context, pRd->new_state, pRd->old_state->float_list);
pRd->old_state->float_list = NULL;
}
while( (pTag = pNextTag) != 0
|| (pTag = EDT_TagCursorGetNextState(pCursor)) != 0 )
{
lo_LayoutTag(pRd->context, pRd->new_state, pTag);
pNextTag = pTag->next;
PA_FreeTag(pTag);
}
/* What the heck is this doing? */
eptr = NULL;
XP_LOCK_BLOCK(line_array, LO_Element **, pRd->new_state->line_array);
eptr = line_array[0];
if (eptr != NULL )
{
lo_relayout_recycle(context, pRd->new_state, eptr);
}
XP_UNLOCK_BLOCK(pRd->old_state->line_array);
/*
Get list of any mailing quote bullets, removing them from line_list.
These are the only elements that we want to preserve.
lo_strip_mquotes deals properly with a NULL input.
Note that this can change the value of pRd->new_state->line_list.
*/
leadingMquotes = lo_strip_mquotes(&pRd->new_state->line_list);
if ( pRd->new_state->line_list ) {
lo_relayout_recycle(context, pRd->new_state, pRd->new_state->line_list);
}
/* Only leave the leading mquote bullets, if any. */
pRd->new_state->line_list = leadingMquotes;
pRd->new_state->line_num = 1;
/* while there are tags to parse... */
bFoundBreak = FALSE;
pNextTag = NULL;
while( !bFoundBreak )
{
if( pNextTag == NULL )
{
pTag = EDT_TagCursorGetNext(pRd->pTagCursor);
}
else
{
pTag = pNextTag;
}
if( pTag == NULL ){
break;
}
pRd->new_state->display_blocked = TRUE;
pNextTag = pTag->next;
if( iStartEditOffset && pTag->type == P_TEXT )
{
pRd->new_state->edit_current_offset = iStartEditOffset;
pRd->new_state->edit_force_offset = TRUE;
lo_LayoutTag(pRd->context, pRd->new_state, pTag);
iStartEditOffset = 0;
pRd->new_state->edit_force_offset = FALSE;
PA_FreeTag(pTag);
}
else
{
/* lo_LayoutTag(pRd->context, pRd->new_state, pTag);*/
/* Matches code at end of LO_ProcessTag */
lo_DocState *state = pRd->new_state;
lo_DocState *orig_state;
lo_DocState *up_state;
PA_Tag* tag = pTag;
/*
* Divert all tags to the current sub-document if there is one.
*/
up_state = NULL;
orig_state = state;
/* Note: we always display tables, so we ignore bDisplayTables now */
while (state->sub_state != NULL)
{
lo_DocState *new_state;
up_state = state;
new_state = state->sub_state;
state = new_state;
}
/* orig_state->top_state->layout_status = status; */
{
lo_DocState *tmp_state;
Bool may_save;
if ((state->is_a_subdoc == SUBDOC_CELL)||
(state->is_a_subdoc == SUBDOC_CAPTION))
{
may_save = TRUE;
}
else
{
may_save = FALSE;
}
/* Some table routines reach out to find the top doc state.
* So we replace it for the duration of this call.
*/
pRd->top_state->doc_state = pRd->new_state;
state->edit_relayout_display_blocked = TRUE;
state->display_blocked = TRUE;
lo_LayoutTag(context, state, tag);
pRd->top_state->doc_state = pRd->old_state;
tmp_state = lo_CurrentSubState(orig_state);
if (may_save != FALSE)
{
/*
* That tag popped us up one state level. If this new
* state is still a subdoc, save the tag there.
*/
if (tmp_state == up_state)
{
if ((tmp_state->is_a_subdoc == SUBDOC_CELL)||
(tmp_state->is_a_subdoc == SUBDOC_CAPTION))
{
lo_SaveSubdocTags(context, tmp_state, tag);
}
else
{
PA_FreeTag(tag);
}
}
/*
* Else that tag put us in a new subdoc on the same
* level. It needs to be saved one level up,
* if the parent is also a subdoc.
*/
else if ((up_state != NULL)&&
(tmp_state == up_state->sub_state)&&
(tmp_state != state))
{
if ((up_state->is_a_subdoc == SUBDOC_CELL)||
(up_state->is_a_subdoc == SUBDOC_CAPTION))
{
lo_SaveSubdocTags(context, up_state, tag);
}
else
{
PA_FreeTag(tag);
}
}
/*
* Else we are still in the same subdoc
*/
else if (tmp_state == state)
{
lo_SaveSubdocTags(context, state, tag);
}
/*
* Else that tag started a new, nested subdoc.
* Add the starting tag to the parent.
*/
else if (tmp_state == state->sub_state)
{
lo_SaveSubdocTags(context, state, tag);
/*
* Since we have extended the parent chain,
* we need to reset the child to the new
* parent end-chain.
*/
if ((tmp_state->is_a_subdoc == SUBDOC_CELL)||
(tmp_state->is_a_subdoc == SUBDOC_CAPTION))
{
tmp_state->subdoc_tags =
state->subdoc_tags_end;
}
}
/*
* This can never happen.
*/
else
{
PA_FreeTag(tag);
}
state = tmp_state;
}
else
{
PA_FreeTag(tag);
}
}
}
/* pNextTag = pTag->next;
PA_FreeTag(pTag);
*/ if( pNextTag == 0 ){
bFoundBreak = EDT_TagCursorAtBreak( pRd->pTagCursor, &bBreakIsEndTag );
}
}
if( bFoundBreak )
{
if( bBreakIsEndTag ){
pTag = EDT_TagCursorGetNext(pRd->pTagCursor);
lo_LayoutTag(pRd->context, pRd->new_state, pTag);
iEndLine = EDT_TagCursorCurrentLine( pRd->pTagCursor );
}
else {
iEndLine = EDT_TagCursorCurrentLine( pRd->pTagCursor );
pTag = EDT_TagCursorGetNext(pRd->pTagCursor);
if ( pTag->type == P_TABLE ) {
lo_CloseOutLayout( pRd->context, pRd->new_state);
}
else {
lo_LayoutTag(pRd->context, pRd->new_state, pTag);
}
}
EDT_DeleteTagChain(pTag);
/* don't close layout. We just flushed this line to the proper
* height, there is a start of a new tag in the buffer.
*/
}
else {
lo_CloseOutLayout( pRd->context, pRd->new_state);
}
if( iEndLine == -1 ){
iEndLine = pRd->old_state->line_num-1;
}
/* Go up the liststack, closing out any mquotes. */
{
lo_ListStack *lptr;
lptr = pRd->new_state->list_stack;
while (lptr->type != P_UNKNOWN && lptr->next != NULL)
{
if (lptr->quote_type == QUOTE_MQUOTE)
{
lo_add_leading_bullets(context,pRd->new_state,
lptr->mquote_line_num - 1,
pRd->new_state->line_num - 2,
lptr->mquote_x);
}
lptr = lptr->next;
}
}
/**************************************************************/
lo_RebuildCell(context, new_state, pCell);
/* TODO -- RESET POINTERS SO NEW TAGS ARE NOT DELETED AND DELETE new_state */
/* For now, assume same Y and height doesn't change */
changedY = pCell->y;
/* Note: using -1 for this will redraw to the end of the window */
changedHeight = pCell->line_height;
context->is_editor &= ~EDT_RELAYOUT_FLAG;
FE_DocumentChanged( context, changedY, changedHeight );
}
void lo_EditorReflow(MWContext *context, ED_TagCursor *pCursor,
int32 iStartLine, int iStartEditOffset)
{
PA_Tag *pTag;
@ -880,7 +1190,7 @@ void LO_EditorReflow(MWContext *context, ED_TagCursor *pCursor,
LO_Element ** old_line_array;
context->is_editor |= EDT_RELAYOUT_FLAG; /* Relayout flag */
pRd = lo_NewRelayoutData( context, pCursor, iStartLine, iStartEditOffset );
pRd = lo_NewRelayoutData( context, pCursor, iStartLine, iStartEditOffset, 0 );
/* save the floating element list for later deletion. */
if( pRd->old_state->float_list != 0 )
@ -1077,7 +1387,7 @@ void LO_Relayout(MWContext *context, ED_TagCursor *pCursor,
int32 iEndLine = -1;
LO_Element *leadingMquotes = NULL;
context->is_editor |= EDT_RELAYOUT_FLAG; /* Relayout flag */
pRd = lo_NewRelayoutData( context, pCursor, iStartLine, iStartEditOffset );
pRd = lo_NewRelayoutData( context, pCursor, iStartLine, iStartEditOffset, 0 );
/* We need to keep images loaded during relayout. Images are reference counted.
* When the total number of layout elements that use an image drops to zero,

Просмотреть файл

@ -1570,12 +1570,17 @@ lo_ScriptEvalExitFn(void * data, char * str, size_t len, char * wysiwyg_url,
char * base_href, Bool valid);
extern Bool
lo_ConvertMochaEntities(MWContext * context, lo_DocState *state, PA_Tag * tag);
lo_ConvertMochaEntities(MWContext * pContext, lo_DocState *state, PA_Tag * tag);
extern void
LO_EditorReflow(MWContext *context, ED_TagCursor *pCursor,
lo_EditorReflow(MWContext *pContext, ED_TagCursor *pCursor,
int32 iStartLine, int iStartEditOffset);
/* Reflow contents of a cell into a new docstate, then merge back into table */
extern void
lo_EditorCellReflow(MWContext *context, ED_TagCursor *pCursor, LO_CellStruct *pCell);
/********************** Image observers and observer lists. ******************/
/* The layout observer for an image request. */
extern void
@ -1679,4 +1684,7 @@ int32 lo_GetRowSpan(LO_Element *pCellElement);
int32 lo_GetColSpan(LO_Element *pCellElement);
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);
#endif /* _Layout_h_ */

Просмотреть файл

@ -341,7 +341,7 @@ void LO_Reflow(MWContext *context, lo_DocState * state, LO_Element *startElement
/* init this by hand as we don't want to create a new state */
relay_state.context = context;
relay_state.top_state = lo_FetchTopState(XP_DOCID(context));
relay_state.top_state = top_state; /*lo_FetchTopState(XP_DOCID(context));*/
relay_state.doc_state = state;
firstElement = TRUE;