diff options
Diffstat (limited to 'sc/source/filter/rtf')
-rw-r--r-- | sc/source/filter/rtf/eeimpars.cxx | 636 | ||||
-rw-r--r-- | sc/source/filter/rtf/expbase.cxx | 110 | ||||
-rw-r--r-- | sc/source/filter/rtf/makefile.mk | 59 | ||||
-rw-r--r-- | sc/source/filter/rtf/rtfexp.cxx | 305 | ||||
-rw-r--r-- | sc/source/filter/rtf/rtfimp.cxx | 75 | ||||
-rw-r--r-- | sc/source/filter/rtf/rtfparse.cxx | 420 |
6 files changed, 1605 insertions, 0 deletions
diff --git a/sc/source/filter/rtf/eeimpars.cxx b/sc/source/filter/rtf/eeimpars.cxx new file mode 100644 index 000000000000..86a347970ff6 --- /dev/null +++ b/sc/source/filter/rtf/eeimpars.cxx @@ -0,0 +1,636 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sc.hxx" + + + +//------------------------------------------------------------------------ + +#include "scitems.hxx" +#include <editeng/eeitem.hxx> + + +#include <editeng/adjitem.hxx> +#include <editeng/editobj.hxx> +#include <editeng/editview.hxx> +#include <editeng/escpitem.hxx> +#include <editeng/langitem.hxx> +#include <svx/svdograf.hxx> +#include <svx/svdpage.hxx> +#include <editeng/scripttypeitem.hxx> +#include <svtools/htmlcfg.hxx> +#include <sfx2/sfxhtml.hxx> +#include <svtools/parhtml.hxx> +#include <svl/zforlist.hxx> +#include <vcl/virdev.hxx> +#include <vcl/svapp.hxx> +#include <unotools/syslocale.hxx> +#include <unotools/charclass.hxx> + +#include "eeimport.hxx" +#include "global.hxx" +#include "document.hxx" +#include "editutil.hxx" +#include "stlsheet.hxx" +#include "docpool.hxx" +#include "attrib.hxx" +#include "patattr.hxx" +#include "cell.hxx" +#include "eeparser.hxx" +#include "drwlayer.hxx" +#include "rangenam.hxx" +#include "progress.hxx" + +#include "globstr.hrc" + +// in fuins1.cxx +extern void ScLimitSizeOnDrawPage( Size& rSize, Point& rPos, const Size& rPage ); + +//------------------------------------------------------------------------ + +ScEEImport::ScEEImport( ScDocument* pDocP, const ScRange& rRange ) : + maRange( rRange ), + mpDoc( pDocP ), + mpParser( NULL ), + mpRowHeights( new Table ) +{ + const ScPatternAttr* pPattern = mpDoc->GetPattern( + maRange.aStart.Col(), maRange.aStart.Row(), maRange.aStart.Tab() ); + mpEngine = new ScTabEditEngine( *pPattern, mpDoc->GetEditPool() ); + mpEngine->SetUpdateMode( FALSE ); + mpEngine->EnableUndo( FALSE ); +} + + +ScEEImport::~ScEEImport() +{ + // Reihenfolge wichtig, sonst knallt's irgendwann irgendwo in irgendeinem Dtor! + // Ist gewaehrleistet, da ScEEImport Basisklasse ist + delete mpEngine; // nach Parser! + delete mpRowHeights; +} + + +ULONG ScEEImport::Read( SvStream& rStream, const String& rBaseURL ) +{ + ULONG nErr = mpParser->Read( rStream, rBaseURL ); + + SCCOL nEndCol; + SCROW nEndRow; + mpParser->GetDimensions( nEndCol, nEndRow ); + if ( nEndCol != 0 ) + { + nEndCol += maRange.aStart.Col() - 1; + if ( nEndCol > MAXCOL ) + nEndCol = MAXCOL; + } + else + nEndCol = maRange.aStart.Col(); + if ( nEndRow != 0 ) + { + nEndRow += maRange.aStart.Row() - 1; + if ( nEndRow > MAXROW ) + nEndRow = MAXROW; + } + else + nEndRow = maRange.aStart.Row(); + maRange.aEnd.Set( nEndCol, nEndRow, maRange.aStart.Tab() ); + + return nErr; +} + + +void ScEEImport::WriteToDocument( BOOL bSizeColsRows, double nOutputFactor, SvNumberFormatter* pFormatter, bool bConvertDate ) +{ + ScProgress* pProgress = new ScProgress( mpDoc->GetDocumentShell(), + ScGlobal::GetRscString( STR_LOAD_DOC ), mpParser->Count() ); + ULONG nProgress = 0; + + SCCOL nStartCol, nEndCol; + SCROW nStartRow, nEndRow; + SCTAB nTab; + SCROW nOverlapRowMax, nLastMergedRow; + SCCOL nMergeColAdd; + nStartCol = maRange.aStart.Col(); + nStartRow = maRange.aStart.Row(); + nTab = maRange.aStart.Tab(); + nEndCol = maRange.aEnd.Col(); + nEndRow = maRange.aEnd.Row(); + nOverlapRowMax = 0; + nMergeColAdd = 0; + nLastMergedRow = SCROW_MAX; + BOOL bHasGraphics = FALSE; + ScEEParseEntry* pE; + if (!pFormatter) + pFormatter = mpDoc->GetFormatTable(); + bool bNumbersEnglishUS = false; + if (pFormatter->GetLanguage() == LANGUAGE_SYSTEM) + { + // Automatic language option selected. Check for the global 'use US English' option. + SvxHtmlOptions aOpt; + bNumbersEnglishUS = aOpt.IsNumbersEnglishUS(); + } + ScDocumentPool* pDocPool = mpDoc->GetPool(); + ScRangeName* pRangeNames = mpDoc->GetRangeName(); + for ( pE = mpParser->First(); pE; pE = mpParser->Next() ) + { + SCROW nRow = nStartRow + pE->nRow; + if ( nRow != nLastMergedRow ) + nMergeColAdd = 0; + SCCOL nCol = nStartCol + pE->nCol + nMergeColAdd; + // RowMerge feststellen, pures ColMerge und ColMerge der ersten + // MergeRow bereits beim parsen + if ( nRow <= nOverlapRowMax ) + { + while ( nCol <= MAXCOL && mpDoc->HasAttrib( nCol, nRow, nTab, + nCol, nRow, nTab, HASATTR_OVERLAPPED ) ) + { + nCol++; + nMergeColAdd++; + } + nLastMergedRow = nRow; + } + // fuer zweiten Durchlauf eintragen + pE->nCol = nCol; + pE->nRow = nRow; + if ( ValidCol(nCol) && ValidRow(nRow) ) + { + SfxItemSet aSet = mpEngine->GetAttribs( pE->aSel ); + // Default raus, wir setzen selber links/rechts je nachdem ob Text + // oder Zahl; EditView.GetAttribs liefert immer kompletten Set + // mit Defaults aufgefuellt + const SfxPoolItem& rItem = aSet.Get( EE_PARA_JUST ); + if ( ((const SvxAdjustItem&)rItem).GetAdjust() == SVX_ADJUST_LEFT ) + aSet.ClearItem( EE_PARA_JUST ); + + // Testen, ob einfacher String ohne gemischte Attribute + BOOL bSimple = ( pE->aSel.nStartPara == pE->aSel.nEndPara ); + for (USHORT nId = EE_CHAR_START; nId <= EE_CHAR_END && bSimple; nId++) + { + const SfxPoolItem* pItem = 0; + SfxItemState eState = aSet.GetItemState( nId, TRUE, &pItem ); + if (eState == SFX_ITEM_DONTCARE) + bSimple = FALSE; + else if (eState == SFX_ITEM_SET) + { + if ( nId == EE_CHAR_ESCAPEMENT ) // Hoch-/Tiefstellen immer ueber EE + { + if ( (SvxEscapement)((const SvxEscapementItem*)pItem)->GetEnumValue() + != SVX_ESCAPEMENT_OFF ) + bSimple = FALSE; + } + } + } + if ( bSimple ) + { // Feldbefehle enthalten? + SfxItemState eFieldState = aSet.GetItemState( EE_FEATURE_FIELD, FALSE ); + if ( eFieldState == SFX_ITEM_DONTCARE || eFieldState == SFX_ITEM_SET ) + bSimple = FALSE; + } + + // HTML + String aValStr, aNumStr; + double fVal; + sal_uInt32 nNumForm = 0; + LanguageType eNumLang = LANGUAGE_NONE; + if ( pE->pNumStr ) + { // SDNUM muss sein wenn SDVAL + aNumStr = *pE->pNumStr; + if ( pE->pValStr ) + aValStr = *pE->pValStr; + fVal = SfxHTMLParser::GetTableDataOptionsValNum( + nNumForm, eNumLang, aValStr, aNumStr, *pFormatter ); + } + + // Attribute setzen + ScPatternAttr aAttr( pDocPool ); + aAttr.GetFromEditItemSet( &aSet ); + SfxItemSet& rSet = aAttr.GetItemSet(); + if ( aNumStr.Len() ) + { + rSet.Put( SfxUInt32Item( ATTR_VALUE_FORMAT, nNumForm ) ); + rSet.Put( SvxLanguageItem( eNumLang, ATTR_LANGUAGE_FORMAT ) ); + } + const SfxItemSet& rESet = pE->aItemSet; + if ( rESet.Count() ) + { + const SfxPoolItem* pItem; + if ( rESet.GetItemState( ATTR_BACKGROUND, FALSE, &pItem) == SFX_ITEM_SET ) + rSet.Put( *pItem ); + if ( rESet.GetItemState( ATTR_BORDER, FALSE, &pItem) == SFX_ITEM_SET ) + rSet.Put( *pItem ); + if ( rESet.GetItemState( ATTR_SHADOW, FALSE, &pItem) == SFX_ITEM_SET ) + rSet.Put( *pItem ); + // HTML + if ( rESet.GetItemState( ATTR_HOR_JUSTIFY, FALSE, &pItem) == SFX_ITEM_SET ) + rSet.Put( *pItem ); + if ( rESet.GetItemState( ATTR_VER_JUSTIFY, FALSE, &pItem) == SFX_ITEM_SET ) + rSet.Put( *pItem ); + if ( rESet.GetItemState( ATTR_LINEBREAK, FALSE, &pItem) == SFX_ITEM_SET ) + rSet.Put( *pItem ); + if ( rESet.GetItemState( ATTR_FONT_COLOR, FALSE, &pItem) == SFX_ITEM_SET ) + rSet.Put( *pItem ); + if ( rESet.GetItemState( ATTR_FONT_UNDERLINE, FALSE, &pItem) == SFX_ITEM_SET ) + rSet.Put( *pItem ); + // HTML LATIN/CJK/CTL script type dependent + const SfxPoolItem* pFont; + if ( rESet.GetItemState( ATTR_FONT, FALSE, &pFont) != SFX_ITEM_SET ) + pFont = 0; + const SfxPoolItem* pHeight; + if ( rESet.GetItemState( ATTR_FONT_HEIGHT, FALSE, &pHeight) != SFX_ITEM_SET ) + pHeight = 0; + const SfxPoolItem* pWeight; + if ( rESet.GetItemState( ATTR_FONT_WEIGHT, FALSE, &pWeight) != SFX_ITEM_SET ) + pWeight = 0; + const SfxPoolItem* pPosture; + if ( rESet.GetItemState( ATTR_FONT_POSTURE, FALSE, &pPosture) != SFX_ITEM_SET ) + pPosture = 0; + if ( pFont || pHeight || pWeight || pPosture ) + { + String aStr( mpEngine->GetText( pE->aSel ) ); + BYTE nScriptType = mpDoc->GetStringScriptType( aStr ); + const BYTE nScripts[3] = { SCRIPTTYPE_LATIN, + SCRIPTTYPE_ASIAN, SCRIPTTYPE_COMPLEX }; + for ( BYTE i=0; i<3; ++i ) + { + if ( nScriptType & nScripts[i] ) + { + if ( pFont ) + rSet.Put( *pFont, ScGlobal::GetScriptedWhichID( + nScripts[i], ATTR_FONT )); + if ( pHeight ) + rSet.Put( *pHeight, ScGlobal::GetScriptedWhichID( + nScripts[i], ATTR_FONT_HEIGHT )); + if ( pWeight ) + rSet.Put( *pWeight, ScGlobal::GetScriptedWhichID( + nScripts[i], ATTR_FONT_WEIGHT )); + if ( pPosture ) + rSet.Put( *pPosture, ScGlobal::GetScriptedWhichID( + nScripts[i], ATTR_FONT_POSTURE )); + } + } + } + } + if ( pE->nColOverlap > 1 || pE->nRowOverlap > 1 ) + { // merged cells, mit SfxItemSet Put schneller als mit + // nachtraeglichem ScDocument DoMerge + ScMergeAttr aMerge( pE->nColOverlap, pE->nRowOverlap ); + rSet.Put( aMerge ); + SCROW nRO = 0; + if ( pE->nColOverlap > 1 ) + mpDoc->ApplyFlagsTab( nCol+1, nRow, + nCol + pE->nColOverlap - 1, nRow, nTab, + SC_MF_HOR ); + if ( pE->nRowOverlap > 1 ) + { + nRO = nRow + pE->nRowOverlap - 1; + mpDoc->ApplyFlagsTab( nCol, nRow+1, + nCol, nRO , nTab, + SC_MF_VER ); + if ( nRO > nOverlapRowMax ) + nOverlapRowMax = nRO; + } + if ( pE->nColOverlap > 1 && pE->nRowOverlap > 1 ) + mpDoc->ApplyFlagsTab( nCol+1, nRow+1, + nCol + pE->nColOverlap - 1, nRO, nTab, + SC_MF_HOR | SC_MF_VER ); + } + const ScStyleSheet* pStyleSheet = + mpDoc->GetPattern( nCol, nRow, nTab )->GetStyleSheet(); + aAttr.SetStyleSheet( (ScStyleSheet*)pStyleSheet ); + mpDoc->SetPattern( nCol, nRow, nTab, aAttr, TRUE ); + + // Daten eintragen + if (bSimple) + { + if ( aValStr.Len() ) + mpDoc->SetValue( nCol, nRow, nTab, fVal ); + else if ( !pE->aSel.HasRange() ) + { + // maybe ALT text of IMG or similar + mpDoc->SetString( nCol, nRow, nTab, pE->aAltText, pFormatter ); + // wenn SelRange komplett leer kann nachfolgender Text im gleichen Absatz liegen! + } + else + { + String aStr; + if( pE->bEntirePara ) + { + aStr = mpEngine->GetText( pE->aSel.nStartPara ); + } + else + { + aStr = mpEngine->GetText( pE->aSel ); + aStr.EraseLeadingAndTrailingChars(); + } + + // TODO: RTF import should follow the language tag, + // currently this follows the HTML options for both, HTML + // and RTF. + bool bEnUsRecognized = false; + if (bNumbersEnglishUS) + { + pFormatter->ChangeIntl( LANGUAGE_ENGLISH_US); + sal_uInt32 nIndex = pFormatter->GetStandardIndex( LANGUAGE_ENGLISH_US); + double fEnVal = 0.0; + if (pFormatter->IsNumberFormat( aStr, nIndex, fEnVal)) + { + bEnUsRecognized = true; + sal_uInt32 nNewIndex = + pFormatter->GetFormatForLanguageIfBuiltIn( + nIndex, LANGUAGE_SYSTEM); + DBG_ASSERT( nNewIndex != nIndex, "ScEEImport::WriteToDocument: NumbersEnglishUS not a built-in format?"); + pFormatter->GetInputLineString( fEnVal, nNewIndex, aStr); + } + pFormatter->ChangeIntl( LANGUAGE_SYSTEM); + } + + // #105460#, #i4180# String cells can't contain tabs or linebreaks + // -> replace with spaces + aStr.SearchAndReplaceAll( (sal_Unicode)'\t', (sal_Unicode)' ' ); + aStr.SearchAndReplaceAll( (sal_Unicode)'\n', (sal_Unicode)' ' ); + + if (bNumbersEnglishUS && !bEnUsRecognized) + mpDoc->PutCell( nCol, nRow, nTab, new ScStringCell( aStr)); + else + mpDoc->SetString( nCol, nRow, nTab, aStr, pFormatter, bConvertDate ); + } + } + else + { + EditTextObject* pObject = mpEngine->CreateTextObject( pE->aSel ); + mpDoc->PutCell( nCol, nRow, nTab, new ScEditCell( pObject, + mpDoc, mpEngine->GetEditTextObjectPool() ) ); + delete pObject; + } + if ( pE->pImageList ) + bHasGraphics |= GraphicSize( nCol, nRow, nTab, pE ); + if ( pE->pName ) + { // Anchor Name => RangeName + USHORT nIndex; + if ( !pRangeNames->SearchName( *pE->pName, nIndex ) ) + { + ScRangeData* pData = new ScRangeData( mpDoc, *pE->pName, + ScAddress( nCol, nRow, nTab ) ); + pRangeNames->Insert( pData ); + } + } + } + pProgress->SetStateOnPercent( ++nProgress ); + } + if ( bSizeColsRows ) + { + // Spaltenbreiten + Table* pColWidths = mpParser->GetColWidths(); + if ( pColWidths->Count() ) + { + nProgress = 0; + pProgress->SetState( nProgress, nEndCol - nStartCol + 1 ); + for ( SCCOL nCol = nStartCol; nCol <= nEndCol; nCol++ ) + { + USHORT nWidth = (USHORT)(ULONG) pColWidths->Get( nCol ); + if ( nWidth ) + mpDoc->SetColWidth( nCol, nTab, nWidth ); + pProgress->SetState( ++nProgress ); + } + } + DELETEZ( pProgress ); // SetOptimalHeight hat seinen eigenen ProgressBar + // Zeilenhoehen anpassen, Basis 100% Zoom + Fraction aZoom( 1, 1 ); + double nPPTX = ScGlobal::nScreenPPTX * (double) aZoom + / nOutputFactor; // Faktor ist Drucker zu Bildschirm + double nPPTY = ScGlobal::nScreenPPTY * (double) aZoom; + VirtualDevice aVirtDev; + mpDoc->SetOptimalHeight( 0, nEndRow, 0, + static_cast< USHORT >( ScGlobal::nLastRowHeightExtra ), &aVirtDev, + nPPTX, nPPTY, aZoom, aZoom, FALSE ); + if ( mpRowHeights->Count() ) + { + for ( SCROW nRow = nStartRow; nRow <= nEndRow; nRow++ ) + { + USHORT nHeight = (USHORT)(ULONG) mpRowHeights->Get( nRow ); + if ( nHeight > mpDoc->FastGetRowHeight( nRow, nTab ) ) + mpDoc->SetRowHeight( nRow, nTab, nHeight ); + } + } + } + if ( bHasGraphics ) + { // Grafiken einfuegen + for ( pE = mpParser->First(); pE; pE = mpParser->Next() ) + { + if ( pE->pImageList ) + { + SCCOL nCol = pE->nCol; + SCROW nRow = pE->nRow; + if ( ValidCol(nCol) && ValidRow(nRow) ) + InsertGraphic( nCol, nRow, nTab, pE ); + } + } + } + if ( pProgress ) + delete pProgress; +} + + +BOOL ScEEImport::GraphicSize( SCCOL nCol, SCROW nRow, SCTAB /*nTab*/, + ScEEParseEntry* pE ) +{ + ScHTMLImageList* pIL = pE->pImageList; + if ( !pIL || !pIL->Count() ) + return FALSE; + BOOL bHasGraphics = FALSE; + OutputDevice* pDefaultDev = Application::GetDefaultDevice(); + long nWidth, nHeight; + nWidth = nHeight = 0; + sal_Char nDir = nHorizontal; + for ( ScHTMLImage* pI = pIL->First(); pI; pI = pIL->Next() ) + { + if ( pI->pGraphic ) + bHasGraphics = TRUE; + Size aSizePix = pI->aSize; + aSizePix.Width() += 2 * pI->aSpace.X(); + aSizePix.Height() += 2 * pI->aSpace.Y(); + Size aLogicSize = pDefaultDev->PixelToLogic( aSizePix, MapMode( MAP_TWIP ) ); + if ( nDir & nHorizontal ) + nWidth += aLogicSize.Width(); + else if ( nWidth < aLogicSize.Width() ) + nWidth = aLogicSize.Width(); + if ( nDir & nVertical ) + nHeight += aLogicSize.Height(); + else if ( nHeight < aLogicSize.Height() ) + nHeight = aLogicSize.Height(); + nDir = pI->nDir; + } + // Spaltenbreiten + Table* pColWidths = mpParser->GetColWidths(); + long nThisWidth = (long) pColWidths->Get( nCol ); + long nColWidths = nThisWidth; + SCCOL nColSpanCol = nCol + pE->nColOverlap; + for ( SCCOL nC = nCol + 1; nC < nColSpanCol; nC++ ) + { + nColWidths += (long) pColWidths->Get( nC ); + } + if ( nWidth > nColWidths ) + { // Differenz nur in der ersten Spalte eintragen + if ( nThisWidth ) + pColWidths->Replace( nCol, (void*)(nWidth - nColWidths + nThisWidth) ); + else + pColWidths->Insert( nCol, (void*)(nWidth - nColWidths) ); + } + // Zeilenhoehen, Differenz auf alle betroffenen Zeilen verteilen + SCROW nRowSpan = pE->nRowOverlap; + nHeight /= nRowSpan; + if ( nHeight == 0 ) + nHeight = 1; // fuer eindeutigen Vergleich + for ( SCROW nR = nRow; nR < nRow + nRowSpan; nR++ ) + { + long nRowHeight = (long) mpRowHeights->Get( nR ); + if ( nHeight > nRowHeight ) + { + if ( nRowHeight ) + mpRowHeights->Replace( nR, (void*)nHeight ); + else + mpRowHeights->Insert( nR, (void*)nHeight ); + } + } + return bHasGraphics; +} + + +void ScEEImport::InsertGraphic( SCCOL nCol, SCROW nRow, SCTAB nTab, + ScEEParseEntry* pE ) +{ + ScHTMLImageList* pIL = pE->pImageList; + if ( !pIL || !pIL->Count() ) + return ; + ScDrawLayer* pModel = mpDoc->GetDrawLayer(); + if (!pModel) + { + mpDoc->InitDrawLayer(); + pModel = mpDoc->GetDrawLayer(); + } + SdrPage* pPage = pModel->GetPage( static_cast<sal_uInt16>(nTab) ); + OutputDevice* pDefaultDev = Application::GetDefaultDevice(); + + Point aCellInsertPos( + (long)((double) mpDoc->GetColOffset( nCol, nTab ) * HMM_PER_TWIPS), + (long)((double) mpDoc->GetRowOffset( nRow, nTab ) * HMM_PER_TWIPS) ); + + Point aInsertPos( aCellInsertPos ); + Point aSpace; + Size aLogicSize; + sal_Char nDir = nHorizontal; + for ( ScHTMLImage* pI = pIL->First(); pI; pI = pIL->Next() ) + { + if ( nDir & nHorizontal ) + { // horizontal + aInsertPos.X() += aLogicSize.Width(); + aInsertPos.X() += aSpace.X(); + aInsertPos.Y() = aCellInsertPos.Y(); + } + else + { // vertikal + aInsertPos.X() = aCellInsertPos.X(); + aInsertPos.Y() += aLogicSize.Height(); + aInsertPos.Y() += aSpace.Y(); + } + // Offset des Spacings drauf + aSpace = pDefaultDev->PixelToLogic( pI->aSpace, MapMode( MAP_100TH_MM ) ); + aInsertPos += aSpace; + + Size aSizePix = pI->aSize; + aLogicSize = pDefaultDev->PixelToLogic( aSizePix, MapMode( MAP_100TH_MM ) ); + // Groesse begrenzen + ::ScLimitSizeOnDrawPage( aLogicSize, aInsertPos, pPage->GetSize() ); + + if ( pI->pGraphic ) + { + Rectangle aRect ( aInsertPos, aLogicSize ); + SdrGrafObj* pObj = new SdrGrafObj( *pI->pGraphic, aRect ); + // #118522# calling SetGraphicLink here doesn't work + pObj->SetName( pI->aURL ); + + pPage->InsertObject( pObj ); + + // #118522# SetGraphicLink has to be used after inserting the object, + // otherwise an empty graphic is swapped in and the contact stuff crashes. + // See #i37444#. + pObj->SetGraphicLink( pI->aURL, pI->aFilterName ); + + pObj->SetLogicRect( aRect ); // erst nach InsertObject !!! + } + nDir = pI->nDir; + } +} + + +ScEEParser::ScEEParser( EditEngine* pEditP ) : + pEdit( pEditP ), + pPool( EditEngine::CreatePool() ), + pDocPool( new ScDocumentPool ), + pList( new ScEEParseList ), + pColWidths( new Table ), + nLastToken(0), + nColCnt(0), + nRowCnt(0), + nColMax(0), + nRowMax(0) +{ + // pPool wird spaeter bei RTFIMP_START dem SvxRTFParser untergejubelt + pPool->SetSecondaryPool( pDocPool ); + pPool->FreezeIdRanges(); + NewActEntry( NULL ); +} + + +ScEEParser::~ScEEParser() +{ + delete pActEntry; + delete pColWidths; + for ( ScEEParseEntry* pE = pList->First(); pE; pE = pList->Next() ) + delete pE; + delete pList; + + // Pool erst loeschen nachdem die Listen geloescht wurden + pPool->SetSecondaryPool( NULL ); + SfxItemPool::Free(pDocPool); + SfxItemPool::Free(pPool); +} + + +void ScEEParser::NewActEntry( ScEEParseEntry* pE ) +{ // neuer freifliegender pActEntry + pActEntry = new ScEEParseEntry( pPool ); + pActEntry->aSel.nStartPara = (pE ? pE->aSel.nEndPara + 1 : 0); + pActEntry->aSel.nStartPos = 0; +} + + + + diff --git a/sc/source/filter/rtf/expbase.cxx b/sc/source/filter/rtf/expbase.cxx new file mode 100644 index 000000000000..3188b4f920e7 --- /dev/null +++ b/sc/source/filter/rtf/expbase.cxx @@ -0,0 +1,110 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sc.hxx" + + + + +#include "expbase.hxx" +#include "document.hxx" +#include "editutil.hxx" + + +//------------------------------------------------------------------ + +#if defined(UNX) +const sal_Char __FAR_DATA ScExportBase::sNewLine = '\012'; +#else +const sal_Char __FAR_DATA ScExportBase::sNewLine[] = "\015\012"; +#endif + + +ScExportBase::ScExportBase( SvStream& rStrmP, ScDocument* pDocP, + const ScRange& rRangeP ) + : + rStrm( rStrmP ), + aRange( rRangeP ), + pDoc( pDocP ), + pFormatter( pDocP->GetFormatTable() ), + pEditEngine( NULL ) +{ +} + + +ScExportBase::~ScExportBase() +{ + delete pEditEngine; +} + + +BOOL ScExportBase::GetDataArea( SCTAB nTab, SCCOL& nStartCol, + SCROW& nStartRow, SCCOL& nEndCol, SCROW& nEndRow ) const +{ + pDoc->GetDataStart( nTab, nStartCol, nStartRow ); + pDoc->GetPrintArea( nTab, nEndCol, nEndRow, TRUE ); + return TrimDataArea( nTab, nStartCol, nStartRow, nEndCol, nEndRow ); +} + + +BOOL ScExportBase::TrimDataArea( SCTAB nTab, SCCOL& nStartCol, + SCROW& nStartRow, SCCOL& nEndCol, SCROW& nEndRow ) const +{ + while ( nStartCol <= nEndCol && + pDoc->GetColFlags( nStartCol, nTab ) & CR_HIDDEN ) + ++nStartCol; + while ( nStartCol <= nEndCol && + pDoc->GetColFlags( nEndCol, nTab ) & CR_HIDDEN ) + --nEndCol; + nStartRow = pDoc->GetRowFlagsArray( nTab).GetFirstForCondition( nStartRow, + nEndRow, CR_HIDDEN, 0); + nEndRow = pDoc->GetRowFlagsArray( nTab).GetLastForCondition( nStartRow, + nEndRow, CR_HIDDEN, 0); + return nStartCol <= nEndCol && nStartRow <= nEndRow && nEndRow != + ::std::numeric_limits<SCROW>::max(); +} + + +BOOL ScExportBase::IsEmptyTable( SCTAB nTab ) const +{ + if ( !pDoc->HasTable( nTab ) || !pDoc->IsVisible( nTab ) ) + return TRUE; + SCCOL nStartCol, nEndCol; + SCROW nStartRow, nEndRow; + return !GetDataArea( nTab, nStartCol, nStartRow, nEndCol, nEndRow ); +} + + +ScFieldEditEngine& ScExportBase::GetEditEngine() const +{ + if ( !pEditEngine ) + ((ScExportBase*)this)->pEditEngine = new ScFieldEditEngine( pDoc->GetEditPool() ); + return *pEditEngine; +} + + diff --git a/sc/source/filter/rtf/makefile.mk b/sc/source/filter/rtf/makefile.mk new file mode 100644 index 000000000000..a680751de620 --- /dev/null +++ b/sc/source/filter/rtf/makefile.mk @@ -0,0 +1,59 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ=..$/..$/.. + +PRJNAME=sc +TARGET=rtf + +AUTOSEG=true + +PROJECTPCH4DLL=TRUE +PROJECTPCH=filt_pch +PROJECTPCHSOURCE=..\pch\filt_pch + +VISIBILITY_HIDDEN=TRUE + +# --- Settings ----------------------------------------------------- + +.INCLUDE : scpre.mk +.INCLUDE : settings.mk +.INCLUDE : sc.mk + +# --- Files -------------------------------------------------------- + +SLOFILES = \ + $(SLO)$/eeimpars.obj \ + $(SLO)$/expbase.obj \ + $(SLO)$/rtfexp.obj \ + $(SLO)$/rtfimp.obj \ + $(SLO)$/rtfparse.obj + +# --- Tagets ------------------------------------------------------- + +.INCLUDE : target.mk + diff --git a/sc/source/filter/rtf/rtfexp.cxx b/sc/source/filter/rtf/rtfexp.cxx new file mode 100644 index 000000000000..c817fc2844eb --- /dev/null +++ b/sc/source/filter/rtf/rtfexp.cxx @@ -0,0 +1,305 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sc.hxx" + + + +#include "scitems.hxx" +#include <editeng/eeitem.hxx> + + +#include <svx/algitem.hxx> +#include <editeng/wghtitem.hxx> +#include <editeng/postitem.hxx> +#include <editeng/udlnitem.hxx> +#include <editeng/fontitem.hxx> +#include <editeng/fhgtitem.hxx> +#include <svl/style.hxx> +#include <svtools/rtfout.hxx> +#include <svtools/rtfkeywd.hxx> + +#include "rtfexp.hxx" +#include "filter.hxx" +#include "document.hxx" +#include "patattr.hxx" +#include "attrib.hxx" +#include "cell.hxx" +#include "cellform.hxx" +#include "editutil.hxx" +#include "stlpool.hxx" +#include "ftools.hxx" + +//------------------------------------------------------------------ + +FltError ScFormatFilterPluginImpl::ScExportRTF( SvStream& rStrm, ScDocument* pDoc, + const ScRange& rRange, const CharSet /*eNach*/ ) +{ + ScRTFExport aEx( rStrm, pDoc, rRange ); + return aEx.Write(); +} + + +ScRTFExport::ScRTFExport( SvStream& rStrmP, ScDocument* pDocP, const ScRange& rRangeP ) + : + ScExportBase( rStrmP, pDocP, rRangeP ), + pCellX( new ULONG[ MAXCOL+2 ] ) +{ +} + + +ScRTFExport::~ScRTFExport() +{ + delete [] pCellX; +} + + +ULONG ScRTFExport::Write() +{ + rStrm << '{' << OOO_STRING_SVTOOLS_RTF_RTF; + rStrm << OOO_STRING_SVTOOLS_RTF_ANSI << sNewLine; + +#if 0 +// das ist noch nicht ausgegoren +/* + SfxStyleSheetBasePool* pStylePool = pDoc->GetStyleSheetPool(); + SfxStyleSheetBase* pStyleSheet = NULL; + DBG_ASSERT( pStylePool, "StylePool not found! :-(" ); + pStylePool->SetSearchMask( SFX_STYLE_FAMILY_PARA, SFXSTYLEBIT_ALL ); + pStyleSheet = pStylePool->Find( STRING_STANDARD, SFX_STYLE_FAMILY_PARA ); + DBG_ASSERT( pStyleSheet, "ParaStyle not found! :-(" ); + const SfxItemSet& rSetPara = pStyleSheet->GetItemSet(); + + // fonttbl + String aFontFamilyName( + ((const SvxFontItem&)(rSetPara.Get( ATTR_FONT ))).GetFamilyName() ); + rStrm << OOO_STRING_SVTOOLS_RTF_DEFF << '0' + << '{' << OOO_STRING_SVTOOLS_RTF_FONTTBL + << '{' << OOO_STRING_SVTOOLS_RTF_F << '0' << OOO_STRING_SVTOOLS_RTF_FNIL << ' ' << aFontFamilyName.GetStr() << ";}" + << '}' << sNewLine; + + // hier kaeme die colortbl + + // stylesheet + UINT32 nFontHeight = + ((const SvxFontHeightItem&)(rSetPara.Get( ATTR_FONT_HEIGHT ))).GetHeight(); + rStrm << '{' << OOO_STRING_SVTOOLS_RTF_STYLESHEET + << '{' << OOO_STRING_SVTOOLS_RTF_FS << String( UINT32(nFontHeight / TWIPS_PER_POINT) ).GetStr() + << ' ' << pStyleSheet->GetName().GetStr() << ";}" + << '}' << sNewLine; +*/ +#endif + + // Daten + for ( SCTAB nTab = aRange.aStart.Tab(); nTab <= aRange.aEnd.Tab(); nTab++ ) + { + if ( nTab > aRange.aStart.Tab() ) + rStrm << OOO_STRING_SVTOOLS_RTF_PAR; + WriteTab( nTab ); + } + + rStrm << '}' << sNewLine; + return rStrm.GetError(); +} + + +void ScRTFExport::WriteTab( SCTAB nTab ) +{ + rStrm << '{' << sNewLine; + if ( pDoc->HasTable( nTab ) ) + { + memset( &pCellX[0], 0, (MAXCOL+2) * sizeof(ULONG) ); + SCCOL nCol; + SCCOL nEndCol = aRange.aEnd.Col(); + for ( nCol = aRange.aStart.Col(); nCol <= nEndCol; nCol++ ) + { + pCellX[nCol+1] = pCellX[nCol] + pDoc->GetColWidth( nCol, nTab ); + } + + SCROW nEndRow = aRange.aEnd.Row(); + for ( SCROW nRow = aRange.aStart.Row(); nRow <= nEndRow; nRow++ ) + { + WriteRow( nTab, nRow ); + } + } + rStrm << '}' << sNewLine; +} + + +void ScRTFExport::WriteRow( SCTAB nTab, SCROW nRow ) +{ + rStrm << OOO_STRING_SVTOOLS_RTF_TROWD << OOO_STRING_SVTOOLS_RTF_TRGAPH << "30" << OOO_STRING_SVTOOLS_RTF_TRLEFT << "-30"; + rStrm << OOO_STRING_SVTOOLS_RTF_TRRH << ByteString::CreateFromInt32( pDoc->GetRowHeight( nRow, nTab ) ).GetBuffer(); + SCCOL nCol; + SCCOL nEndCol = aRange.aEnd.Col(); + for ( nCol = aRange.aStart.Col(); nCol <= nEndCol; nCol++ ) + { + const ScPatternAttr* pAttr = pDoc->GetPattern( nCol, nRow, nTab ); + const ScMergeAttr& rMergeAttr = (const ScMergeAttr&) pAttr->GetItem( ATTR_MERGE ); + const SvxVerJustifyItem& rVerJustifyItem= (const SvxVerJustifyItem&)pAttr->GetItem( ATTR_VER_JUSTIFY ); + + const sal_Char* pChar; + + if ( rMergeAttr.GetColMerge() != 0 ) + rStrm << OOO_STRING_SVTOOLS_RTF_CLMGF; + else + { + const ScMergeFlagAttr& rMergeFlagAttr = (const ScMergeFlagAttr&) pAttr->GetItem( ATTR_MERGE_FLAG ); + if ( rMergeFlagAttr.IsHorOverlapped() ) + rStrm << OOO_STRING_SVTOOLS_RTF_CLMRG; + } + + switch( rVerJustifyItem.GetValue() ) + { + case SVX_VER_JUSTIFY_TOP: pChar = OOO_STRING_SVTOOLS_RTF_CLVERTALT; break; + case SVX_VER_JUSTIFY_CENTER: pChar = OOO_STRING_SVTOOLS_RTF_CLVERTALC; break; + case SVX_VER_JUSTIFY_BOTTOM: pChar = OOO_STRING_SVTOOLS_RTF_CLVERTALB; break; + case SVX_VER_JUSTIFY_STANDARD: pChar = OOO_STRING_SVTOOLS_RTF_CLVERTALB; break; //! Bottom + default: pChar = NULL; break; + } + if ( pChar ) + rStrm << pChar; + + rStrm << OOO_STRING_SVTOOLS_RTF_CELLX << ByteString::CreateFromInt32( pCellX[nCol+1] ).GetBuffer(); + if ( (nCol & 0x0F) == 0x0F ) + rStrm << sNewLine; // Zeilen nicht zu lang werden lassen + } + rStrm << OOO_STRING_SVTOOLS_RTF_PARD << OOO_STRING_SVTOOLS_RTF_PLAIN << OOO_STRING_SVTOOLS_RTF_INTBL << sNewLine; + + ULONG nStrmPos = rStrm.Tell(); + for ( nCol = aRange.aStart.Col(); nCol <= nEndCol; nCol++ ) + { + WriteCell( nTab, nRow, nCol ); + if ( rStrm.Tell() - nStrmPos > 255 ) + { // Zeilen nicht zu lang werden lassen + rStrm << sNewLine; + nStrmPos = rStrm.Tell(); + } + } + rStrm << OOO_STRING_SVTOOLS_RTF_ROW << sNewLine; +} + + +void ScRTFExport::WriteCell( SCTAB nTab, SCROW nRow, SCCOL nCol ) +{ + const ScPatternAttr* pAttr = pDoc->GetPattern( nCol, nRow, nTab ); + + const ScMergeFlagAttr& rMergeFlagAttr = (const ScMergeFlagAttr&) pAttr->GetItem( ATTR_MERGE_FLAG ); + if ( rMergeFlagAttr.IsHorOverlapped() ) + { + rStrm << OOO_STRING_SVTOOLS_RTF_CELL; + return ; + } + + ScBaseCell* pCell; + pDoc->GetCell( nCol, nRow, nTab, pCell ); + BOOL bValueData; + String aContent; + if ( pCell ) + { + switch ( pCell->GetCellType() ) + { + case CELLTYPE_NOTE : + bValueData = FALSE; + break; // nix + case CELLTYPE_EDIT : + { + bValueData = FALSE; + EditEngine& rEngine = GetEditEngine(); + const EditTextObject* pObj; + ((const ScEditCell*)pCell)->GetData( pObj ); + if ( pObj ) + { + rEngine.SetText( *pObj ); + aContent = rEngine.GetText( LINEEND_LF ); // LineFeed zwischen Absaetzen! + } + } + break; + default: + { + bValueData = pCell->HasValueData(); + ULONG nFormat = pAttr->GetNumberFormat( pFormatter ); + Color* pColor; + ScCellFormat::GetString( pCell, nFormat, aContent, &pColor, *pFormatter ); + } + } + } + else + bValueData = FALSE; + + BOOL bResetPar, bResetAttr; + bResetPar = bResetAttr = FALSE; + + const SvxHorJustifyItem& rHorJustifyItem = (const SvxHorJustifyItem&)pAttr->GetItem( ATTR_HOR_JUSTIFY ); + const SvxWeightItem& rWeightItem = (const SvxWeightItem&) pAttr->GetItem( ATTR_FONT_WEIGHT ); + const SvxPostureItem& rPostureItem = (const SvxPostureItem&) pAttr->GetItem( ATTR_FONT_POSTURE ); + const SvxUnderlineItem& rUnderlineItem = (const SvxUnderlineItem&) pAttr->GetItem( ATTR_FONT_UNDERLINE ); + + const sal_Char* pChar; + + switch( rHorJustifyItem.GetValue() ) + { + case SVX_HOR_JUSTIFY_STANDARD: + pChar = (bValueData ? OOO_STRING_SVTOOLS_RTF_QR : OOO_STRING_SVTOOLS_RTF_QL); + break; + case SVX_HOR_JUSTIFY_CENTER: pChar = OOO_STRING_SVTOOLS_RTF_QC; break; + case SVX_HOR_JUSTIFY_BLOCK: pChar = OOO_STRING_SVTOOLS_RTF_QJ; break; + case SVX_HOR_JUSTIFY_RIGHT: pChar = OOO_STRING_SVTOOLS_RTF_QR; break; + case SVX_HOR_JUSTIFY_LEFT: + case SVX_HOR_JUSTIFY_REPEAT: + default: pChar = OOO_STRING_SVTOOLS_RTF_QL; break; + } + rStrm << pChar; + + if ( rWeightItem.GetWeight() >= WEIGHT_BOLD ) + { // bold + bResetAttr = TRUE; + rStrm << OOO_STRING_SVTOOLS_RTF_B; + } + if ( rPostureItem.GetPosture() != ITALIC_NONE ) + { // italic + bResetAttr = TRUE; + rStrm << OOO_STRING_SVTOOLS_RTF_I; + } + if ( rUnderlineItem.GetLineStyle() != UNDERLINE_NONE ) + { // underline + bResetAttr = TRUE; + rStrm << OOO_STRING_SVTOOLS_RTF_UL; + } + + rStrm << ' '; + RTFOutFuncs::Out_String( rStrm, aContent ); + rStrm << OOO_STRING_SVTOOLS_RTF_CELL; + + if ( bResetPar ) + rStrm << OOO_STRING_SVTOOLS_RTF_PARD << OOO_STRING_SVTOOLS_RTF_INTBL; + if ( bResetAttr ) + rStrm << OOO_STRING_SVTOOLS_RTF_PLAIN; +} + + diff --git a/sc/source/filter/rtf/rtfimp.cxx b/sc/source/filter/rtf/rtfimp.cxx new file mode 100644 index 000000000000..83b48b1fa2b1 --- /dev/null +++ b/sc/source/filter/rtf/rtfimp.cxx @@ -0,0 +1,75 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sc.hxx" + + + +#ifndef PCH +#include "global.hxx" +#include "document.hxx" +#include "filter.hxx" +#endif +#include "editutil.hxx" +#include "rtfimp.hxx" +#include "rtfparse.hxx" +#include "ftools.hxx" + + +FltError ScFormatFilterPluginImpl::ScImportRTF( SvStream &rStream, const String& rBaseURL, ScDocument *pDoc, ScRange& rRange ) +{ + ScRTFImport aImp( pDoc, rRange ); + FltError nErr = (FltError) aImp.Read( rStream, rBaseURL ); + ScRange aR = aImp.GetRange(); + rRange.aEnd = aR.aEnd; + aImp.WriteToDocument(); + return nErr; +} + +ScEEAbsImport *ScFormatFilterPluginImpl::CreateRTFImport( ScDocument* pDoc, const ScRange& rRange ) +{ + return new ScRTFImport( pDoc, rRange ); +} + + +ScRTFImport::ScRTFImport( ScDocument* pDocP, const ScRange& rRange ) : + ScEEImport( pDocP, rRange ) +{ + mpParser = new ScRTFParser( mpEngine ); +} + + +ScRTFImport::~ScRTFImport() +{ + // Reihenfolge wichtig, sonst knallt's irgendwann irgendwo in irgendeinem Dtor! + // Ist gewaehrleistet, da ScEEImport Basisklasse ist + delete (ScRTFParser*) mpParser; // vor EditEngine! +} + + + diff --git a/sc/source/filter/rtf/rtfparse.cxx b/sc/source/filter/rtf/rtfparse.cxx new file mode 100644 index 000000000000..b3373bbf4596 --- /dev/null +++ b/sc/source/filter/rtf/rtfparse.cxx @@ -0,0 +1,420 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sc.hxx" + + + +//------------------------------------------------------------------------ + +#include "scitems.hxx" +#include <editeng/eeitem.hxx> + + +#include <editeng/editeng.hxx> +#include <editeng/fhgtitem.hxx> +#include <editeng/svxrtf.hxx> +#include <vcl/outdev.hxx> +#include <svtools/rtftoken.h> + +#define SC_RTFPARSE_CXX +#include "rtfparse.hxx" +#include "global.hxx" +#include "document.hxx" +#include "docpool.hxx" + +#define SC_RTFTWIPTOL 10 // 10 Twips Toleranz bei Spaltenbestimmung + + + +SV_IMPL_VARARR_SORT( ScRTFColTwips, ULONG ); + + + +ScRTFParser::ScRTFParser( EditEngine* pEditP ) : + ScEEParser( pEditP ), + pDefaultList( new ScRTFDefaultList ), + pColTwips( new ScRTFColTwips ), + pActDefault( NULL ), + pDefMerge( NULL ), + nStartAdjust( (ULONG)~0 ), + nLastWidth(0), + bNewDef( FALSE ) +{ + // RTF default FontSize 12Pt + long nMM = OutputDevice::LogicToLogic( 12, MAP_POINT, MAP_100TH_MM ); + pPool->SetPoolDefaultItem( SvxFontHeightItem( nMM, 100, EE_CHAR_FONTHEIGHT ) ); + // freifliegender pInsDefault + pInsDefault = new ScRTFCellDefault( pPool ); +} + + +ScRTFParser::~ScRTFParser() +{ + delete pInsDefault; + delete pColTwips; + for ( ScRTFCellDefault* pD = pDefaultList->First(); pD; pD = pDefaultList->Next() ) + delete pD; + delete pDefaultList; +} + + +ULONG ScRTFParser::Read( SvStream& rStream, const String& rBaseURL ) +{ + Link aOldLink = pEdit->GetImportHdl(); + pEdit->SetImportHdl( LINK( this, ScRTFParser, RTFImportHdl ) ); + ULONG nErr = pEdit->Read( rStream, rBaseURL, EE_FORMAT_RTF ); + if ( nLastToken == RTF_PAR ) + { + ScEEParseEntry* pE = pList->Last(); + if ( pE + // komplett leer + && (( pE->aSel.nStartPara == pE->aSel.nEndPara + && pE->aSel.nStartPos == pE->aSel.nEndPos) + // leerer Paragraph + || ( pE->aSel.nStartPara + 1 == pE->aSel.nEndPara + && pE->aSel.nStartPos == pEdit->GetTextLen( pE->aSel.nStartPara ) + && pE->aSel.nEndPos == 0 )) ) + { // den letzten leeren Absatz nicht uebernehmen + pList->Remove(); + delete pE; + } + } + ColAdjust(); + pEdit->SetImportHdl( aOldLink ); + return nErr; +} + + +void ScRTFParser::EntryEnd( ScEEParseEntry* pE, const ESelection& aSel ) +{ + // Paragraph -2 stript den angehaengten leeren Paragraph + pE->aSel.nEndPara = aSel.nEndPara - 2; + // obwohl das nEndPos heisst, ist das letzte Position + 1 + pE->aSel.nEndPos = pEdit->GetTextLen( aSel.nEndPara - 1 ); +} + + +inline void ScRTFParser::NextRow() +{ + if ( nRowMax < ++nRowCnt ) + nRowMax = nRowCnt; +} + + +BOOL ScRTFParser::SeekTwips( USHORT nTwips, SCCOL* pCol ) +{ + USHORT nPos; + BOOL bFound = pColTwips->Seek_Entry( nTwips, &nPos ); + *pCol = static_cast<SCCOL>(nPos); + if ( bFound ) + return TRUE; + USHORT nCount = pColTwips->Count(); + if ( !nCount ) + return FALSE; + SCCOL nCol = *pCol; + // nCol ist Einfuegeposition, da liegt der Naechsthoehere (oder auch nicht) + if ( nCol < static_cast<SCCOL>(nCount) && (((*pColTwips)[nCol] - SC_RTFTWIPTOL) <= nTwips) ) + return TRUE; + // nicht kleiner als alles andere? dann mit Naechstniedrigerem vergleichen + else if ( nCol != 0 && (((*pColTwips)[nCol-1] + SC_RTFTWIPTOL) >= nTwips) ) + { + (*pCol)--; + return TRUE; + } + return FALSE; +} + + +void ScRTFParser::ColAdjust() +{ + if ( nStartAdjust != (ULONG)~0 ) + { + SCCOL nCol = 0; + ScEEParseEntry* pE; + pE = pList->Seek( nStartAdjust ); + while ( pE ) + { + if ( pE->nCol == 0 ) + nCol = 0; + pE->nCol = nCol; + if ( pE->nColOverlap > 1 ) + nCol = nCol + pE->nColOverlap; // merged cells mit \clmrg + else + { + SeekTwips( pE->nTwips, &nCol ); + if ( ++nCol <= pE->nCol ) + nCol = pE->nCol + 1; // verschobene Zell-X + pE->nColOverlap = nCol - pE->nCol; // merged cells ohne \clmrg + } + if ( nCol > nColMax ) + nColMax = nCol; + pE = pList->Next(); + } + nStartAdjust = (ULONG)~0; + pColTwips->Remove( (USHORT)0, pColTwips->Count() ); + } +} + + +IMPL_LINK( ScRTFParser, RTFImportHdl, ImportInfo*, pInfo ) +{ + switch ( pInfo->eState ) + { + case RTFIMP_NEXTTOKEN: + ProcToken( pInfo ); + break; + case RTFIMP_UNKNOWNATTR: + ProcToken( pInfo ); + break; + case RTFIMP_START: + { + SvxRTFParser* pParser = (SvxRTFParser*) pInfo->pParser; + pParser->SetAttrPool( pPool ); + RTFPardAttrMapIds& rMap = pParser->GetPardMap(); + rMap.nBrush = ATTR_BACKGROUND; + rMap.nBox = ATTR_BORDER; + rMap.nShadow = ATTR_SHADOW; + } + break; + case RTFIMP_END: + if ( pInfo->aSelection.nEndPos ) + { // falls noch Text: letzten Absatz erzeugen + pActDefault = NULL; + pInfo->nToken = RTF_PAR; + // EditEngine hat keinen leeren Paragraph mehr angehaengt + // den EntryEnd strippen koennte + pInfo->aSelection.nEndPara++; + ProcToken( pInfo ); + } + break; + case RTFIMP_SETATTR: + break; + case RTFIMP_INSERTTEXT: + break; + case RTFIMP_INSERTPARA: + break; + default: + DBG_ERRORFILE("unknown ImportInfo.eState"); + } + return 0; +} + + +// bei RTF_INTBL bzw. am Anfang von erstem RTF_CELL nach RTF_CELLX wenn es +// kein RTF_INTBL gab, bad behavior +void ScRTFParser::NewCellRow( ImportInfo* /*pInfo*/ ) +{ + if ( bNewDef ) + { + ScRTFCellDefault* pD; + bNewDef = FALSE; + // rechts nicht buendig? => neue Tabelle + if ( nLastWidth + && ((pD = pDefaultList->Last()) != 0) && pD->nTwips != nLastWidth ) + { + SCCOL n1, n2; + if ( !( SeekTwips( nLastWidth, &n1 ) + && SeekTwips( pD->nTwips, &n2 ) && n1 == n2) ) + ColAdjust(); + } + // TwipCols aufbauen, erst nach nLastWidth Vergleich! + for ( pD = pDefaultList->First(); pD; pD = pDefaultList->Next() ) + { + SCCOL n; + if ( !SeekTwips( pD->nTwips, &n ) ) + pColTwips->Insert( pD->nTwips ); + } + } + pDefMerge = NULL; + pActDefault = pDefaultList->First(); + DBG_ASSERT( pActDefault, "NewCellRow: pActDefault==0" ); +} + + +/* + SW: + ~~~ + [\par] + \trowd \cellx \cellx ... + \intbl \cell \cell ... + \row + [\par] + [\trowd \cellx \cellx ...] + \intbl \cell \cell ... + \row + [\par] + + M$-Word: + ~~~~~~~~ + [\par] + \trowd \cellx \cellx ... + \intbl \cell \cell ... + \intbl \row + [\par] + [\trowd \cellx \cellx ...] + \intbl \cell \cell ... + \intbl \row + [\par] + + */ + +void ScRTFParser::ProcToken( ImportInfo* pInfo ) +{ + ScRTFCellDefault* pD; + ScEEParseEntry* pE; + switch ( pInfo->nToken ) + { + case RTF_TROWD: // denotes table row defauls, before RTF_CELLX + { + if ( (pD = pDefaultList->Last()) != 0 ) + nLastWidth = pD->nTwips; + nColCnt = 0; + for ( pD = pDefaultList->First(); pD; pD = pDefaultList->Next() ) + delete pD; + pDefaultList->Clear(); + pDefMerge = NULL; + nLastToken = pInfo->nToken; + } + break; + case RTF_CLMGF: // The first cell of cells to be merged + { + pDefMerge = pInsDefault; + nLastToken = pInfo->nToken; + } + break; + case RTF_CLMRG: // A cell to be merged with the preceding cell + { + if ( !pDefMerge ) + pDefMerge = pDefaultList->Last(); + DBG_ASSERT( pDefMerge, "RTF_CLMRG: pDefMerge==0" ); + if ( pDefMerge ) // sonst rottes RTF + pDefMerge->nColOverlap++; // mehrere nacheinander moeglich + pInsDefault->nColOverlap = 0; // Flag: ignoriere diese + nLastToken = pInfo->nToken; + } + break; + case RTF_CELLX: // closes cell default + { + bNewDef = TRUE; + pInsDefault->nCol = nColCnt; + pInsDefault->nTwips = pInfo->nTokenValue; // rechter Zellenrand + pDefaultList->Insert( pInsDefault, LIST_APPEND ); + // neuer freifliegender pInsDefault + pInsDefault = new ScRTFCellDefault( pPool ); + if ( ++nColCnt > nColMax ) + nColMax = nColCnt; + nLastToken = pInfo->nToken; + } + break; + case RTF_INTBL: // before the first RTF_CELL + { + // einmal ueber NextToken und einmal ueber UnknownAttrToken + // oder z.B. \intbl ... \cell \pard \intbl ... \cell + if ( nLastToken != RTF_INTBL && nLastToken != RTF_CELL && nLastToken != RTF_PAR ) + { + NewCellRow( pInfo ); + nLastToken = pInfo->nToken; + } + } + break; + case RTF_CELL: // denotes the end of a cell. + { + DBG_ASSERT( pActDefault, "RTF_CELL: pActDefault==0" ); + if ( bNewDef || !pActDefault ) + NewCellRow( pInfo ); // davor war kein \intbl, bad behavior + // rottes RTF? retten was zu retten ist + if ( !pActDefault ) + pActDefault = pInsDefault; + if ( pActDefault->nColOverlap > 0 ) + { // nicht merged mit vorheriger + pActEntry->nCol = pActDefault->nCol; + pActEntry->nColOverlap = pActDefault->nColOverlap; + pActEntry->nTwips = pActDefault->nTwips; + pActEntry->nRow = nRowCnt; + pActEntry->aItemSet.Set( pActDefault->aItemSet ); + EntryEnd( pActEntry, pInfo->aSelection ); + + if ( nStartAdjust == (ULONG)~0 ) + nStartAdjust = pList->Count(); + pList->Insert( pActEntry, LIST_APPEND ); + NewActEntry( pActEntry ); // neuer freifliegender pActEntry + } + else + { // aktuelle Twips der MergeCell zuweisen + if ( (pE = pList->Last()) != 0 ) + pE->nTwips = pActDefault->nTwips; + // Selection des freifliegenden pActEntry anpassen + // Paragraph -1 wg. Textaufbruch in EditEngine waehrend Parse + pActEntry->aSel.nStartPara = pInfo->aSelection.nEndPara - 1; + } + pActDefault = pDefaultList->Next(); + nLastToken = pInfo->nToken; + } + break; + case RTF_ROW: // means the end of a row + { + NextRow(); + nLastToken = pInfo->nToken; + } + break; + case RTF_PAR: // Paragraph + { + if ( !pActDefault ) + { // text not in table + ColAdjust(); // close the processing table + pActEntry->nCol = 0; + pActEntry->nRow = nRowCnt; + EntryEnd( pActEntry, pInfo->aSelection ); + pList->Insert( pActEntry, LIST_APPEND ); + NewActEntry( pActEntry ); // new pActEntry + NextRow(); + } + nLastToken = pInfo->nToken; + } + break; + default: + { // do not set nLastToken + switch ( pInfo->nToken & ~(0xff | RTF_TABLEDEF) ) + { + case RTF_SHADINGDEF: + ((SvxRTFParser*)pInfo->pParser)->ReadBackgroundAttr( + pInfo->nToken, pInsDefault->aItemSet, TRUE ); + break; + case RTF_BRDRDEF: + ((SvxRTFParser*)pInfo->pParser)->ReadBorderAttr( + pInfo->nToken, pInsDefault->aItemSet, TRUE ); + break; + } + } + } +} + + + + |