kword

KWTextDocument.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2001-2005 David Faure <faure@kde.org>
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18*/
19
20#include "KWCommand.h"
21#include "KWDocument.h"
22#include "KWTextDocument.h"
23#include "KWTextFrameSet.h"
24#include "KWTextParag.h"
25#include "KWLoadingInfo.h"
26#include "KWVariable.h"
27#include "KWAnchor.h"
28#include "KWOasisLoader.h"
29#include "KWTableFrameSet.h"
30
31#include <KoOasisContext.h>
32#include <KoXmlNS.h>
33#include <KoDom.h>
34
35#include <kdebug.h>
36#include <tdeglobalsettings.h>
37#include <tdelocale.h>
38
39KWTextDocument::KWTextDocument( KWTextFrameSet * textfs, KoTextFormatCollection *fc, KoTextFormatter *formatter )
40 : KoTextDocument( textfs->kWordDocument(), fc, formatter, false ), m_textfs( textfs )
41{
42 init();
43}
44
45KWTextDocument::KWTextDocument( KoTextZoomHandler * zoomHandler )
46 : KoTextDocument( zoomHandler, new KoTextFormatCollection( TDEGlobalSettings::generalFont() /*unused*/, TQColor(), TDEGlobal::locale()->language(), false), 0L, false ),
47 m_textfs( 0 )
48{
49 init();
50}
51
52void KWTextDocument::init()
53{
54 // Create initial paragraph as a KWTextParag
55 clear( true );
56}
57
58KWTextDocument::~KWTextDocument()
59{
60}
61
62KoTextParag * KWTextDocument::createParag( KoTextDocument *d, KoTextParag *pr, KoTextParag *nx, bool updateIds )
63{
64 return new KWTextParag( static_cast<KoTextDocument *>(d), static_cast<KoTextParag *>(pr), static_cast<KoTextParag *>(nx), updateIds );
65}
66
67KoTextDocCommand *KWTextDocument::deleteTextCommand( KoTextDocument *textdoc, int id, int index, const TQMemArray<KoTextStringChar> & str, const CustomItemsMap & customItemsMap, const TQValueList<KoParagLayout> & oldParagLayouts )
68{
69 //kdDebug(32500)<<" KoTextDocument::deleteTextCommand************\n";
70 return new KWTextDeleteCommand( textdoc, id, index, str, customItemsMap, oldParagLayouts );
71}
72
73void KWTextDocument::loadOasisTOC( const TQDomElement& tag, KoOasisContext& context, KoTextParag* & lastParagraph, KoStyleCollection * styleColl, KoTextParag* nextParagraph )
74{
75 // table-of-content OOo SPEC 7.5 p452
76 //fillStyleStack( tag, "text:style-name" ); that's the section style
77
78 //TQDomElement tocSource = KoDom::namedItemNS( toc, KoXmlNS::text, "table-of-content-source" );
79 // TODO parse templates and generate "Contents ..." styles from it
80 //for ( TQDomNode n(tocSource.firstChild()); !text.isNull(); text = text.nextSibling() )
81 //{
82 //}
83
84 TQDomElement tocIndexBody = KoDom::namedItemNS( tag, KoXmlNS::text, "index-body" );
85 TQDomElement t;
86 forEachElement( t, tocIndexBody )
87 {
88 context.styleStack().save();
89 const TQString localName = t.localName();
90 TQDomElement e;
91 bool isTextNS = tag.namespaceURI() == KoXmlNS::text;
92 if ( isTextNS && localName == "index-title" ) {
93 lastParagraph = loadOasisText( t, context, lastParagraph, styleColl, nextParagraph ); // recurse again
94 lastParagraph->setPartOfTableOfContents( true );
95 } else if ( isTextNS && localName == "p" ) {
96 context.fillStyleStack( t, KoXmlNS::text, "style-name", "paragraph" );
97 lastParagraph = createParag( this, lastParagraph, nextParagraph );
98 uint pos = 0;
99 lastParagraph->loadOasis( t, context, styleColl, pos );
100 lastParagraph->setPartOfTableOfContents( true );
101 } else
102 kdWarning() << "OASIS TOC loading: unknown tag " << t.tagName() << " found in index-body" << endl;
103 context.styleStack().restore();
104 }
105
106 m_textfs->kWordDocument()->setTocPresent( true );
107}
108
109bool KWTextDocument::loadOasisBodyTag( const TQDomElement& tag, KoOasisContext& context,
110 KoTextParag* & lastParagraph, KoStyleCollection* styleColl,
111 KoTextParag* nextParagraph )
112{
113 const TQString localName( tag.localName() );
114 // Non-inline frame (i.e. anchored to page)
115 if ( localName == "frame" && tag.namespaceURI() == KoXmlNS::draw )
116 {
117 KWDocument* doc = m_textfs->kWordDocument();
118 KWOasisLoader loader( doc );
119 KWFrame* frame = loader.loadFrame( tag, context, KoPoint() );
120 if ( frame )
121 return true;
122 }
123
124 // Anchored-to-paragraph table.
125 else if ( localName == "table" && tag.namespaceURI() == KoXmlNS::table )
126 {
127 KWDocument* doc = m_textfs->kWordDocument();
128 KWOasisLoader loader( doc );
129 KWTableFrameSet* table = loader.loadOasisTable( tag, context );
130 table->finalize();
131 // Create paragraph for this table
132 KoTextParag *parag = createParag( this, lastParagraph, nextParagraph );
133 if ( !lastParagraph ) // First parag
134 setFirstParag( parag );
135 lastParagraph = parag;
136 // Put inline table in that paragraph
137 parag->insert( 0, KoTextObject::customItemChar() );
138 table->setAnchorFrameset( m_textfs );
139 parag->setCustomItem( 0, table->createAnchor( m_textfs->textDocument(), 0 ), 0 );
140 return true;
141 }
142 else if ( localName == "table-of-content" && tag.namespaceURI() == KoXmlNS::text )
143 {
144 loadOasisTOC( tag, context, lastParagraph, styleColl, nextParagraph );
145 return true;
146 }
147
148 return false;
149}
150
151void KWTextDocument::appendBookmark( KoTextParag* parag, int pos, KoTextParag* endParag, int endPos, const TQString& name )
152{
153 // The OASIS format is cool. No need to store the bookmarks until end of loading (e.g. KWLoadingInfo)
154 // We can "resolve" them right away.
155 m_textfs->kWordDocument()->insertBookmark( name, parag, endParag, pos, endPos );
156}
157
158void KWTextDocument::loadOasisFootnote( const TQDomElement& tag, KoOasisContext& context,
159 KoTextCustomItem* & customItem )
160{
161 const TQString frameName( tag.attributeNS( KoXmlNS::text, "id", TQString()) );
162 const TQString localName( tag.localName() );
163 const TQDomElement citationElem = tag.namedItem( localName + "-citation" ).toElement();
164
165 bool endnote = localName == "endnote" && tag.namespaceURI() == KoXmlNS::text;
166
167 TQString label = citationElem.attributeNS( KoXmlNS::text, "label", TQString() );
168 bool autoNumbered = label.isEmpty();
169
170 KWFootNoteFrameSet *fs = m_textfs->insertFootNote(
171 endnote ? EndNote : FootNote,
172 autoNumbered ? KWFootNoteVariable::Auto : KWFootNoteVariable::Manual,
173 label );
174 customItem = fs->footNoteVariable();
175
176 fs->createInitialFrame( 0 ); // we don't know the page number...
177
178 // Parse contents into the frameset
179 const TQDomElement bodyElem = KoDom::namedItemNS( tag, KoXmlNS::text, TQCString( localName.latin1() ) + "-body" ).toElement();
180 fs->loadOasisContent( bodyElem, context );
181}
182
183bool KWTextDocument::loadSpanTag( const TQDomElement& tag, KoOasisContext& context,
184 KoTextParag* parag, uint pos,
185 TQString& textData, KoTextCustomItem* & customItem )
186{
187 const TQString localName( tag.localName() );
188 const bool isTextNS = tag.namespaceURI() == KoXmlNS::text;
189 kdDebug(32500) << "KWTextDocument::loadSpanTag: " << localName << endl;
190
191 if ( isTextNS )
192 {
193 if ( localName == "a" )
194 {
195 TQString href( tag.attributeNS( KoXmlNS::xlink, "href", TQString()) );
196 if ( href.startsWith("#") )
197 {
198 context.styleStack().save();
199 // We have a reference to a bookmark (### TODO)
200 // As we do not support it now, treat it as a <span> without formatting
201 parag->loadOasisSpan( tag, context, pos ); // recurse
202 context.styleStack().restore();
203 }
204 else
205 {
206 // The text is contained in a <span> inside the <a> element. In theory
207 // we could have multiple spans there, but OO ensures that there is always only one,
208 // splitting the hyperlink if necessary (at format changes).
209 // Note that we ignore the formatting of the span.
210 TQDomElement spanElem = KoDom::namedItemNS( tag, KoXmlNS::text, "span" );
211 TQString text;
212 if( spanElem.isNull() )
213 text = tag.text();
214 else {
215 // The save/restore of the stack is done by the caller (KoTextParag::loadOasisSpan)
216 // This allows to use the span's format for the variable.
217 //kdDebug(32500) << "filling stack with " << spanElem.attributeNS( KoXmlNS::text, "style-name", TQString() ) << endl;
218 context.fillStyleStack( spanElem, KoXmlNS::text, "style-name", "text" );
219 text = spanElem.text();
220 }
221 textData = KoTextObject::customItemChar(); // hyperlink placeholder
222 // unused tag.attributeNS( KoXmlNS::office, "name", TQString() )
223 KoVariableCollection& coll = context.variableCollection();
224 customItem = new KoLinkVariable( this, text, href,
225 coll.formatCollection()->format( "STRING" ),
226 &coll );
227 }
228 return true;
229 }
230 else if ( localName == "bookmark" )
231 {
232 appendBookmark( parag, pos, parag, pos, tag.attributeNS( KoXmlNS::text, "name", TQString() ) );
233 return true;
234 }
235 else if ( localName == "bookmark-start" ) {
236 KWLoadingInfo* loadingInfo = m_textfs->kWordDocument()->loadingInfo();
237 loadingInfo->m_bookmarkStarts.insert( tag.attributeNS( KoXmlNS::text, "name", TQString() ),
238 KWLoadingInfo::BookmarkStart( this, parag, pos ) );
239 return true;
240 }
241 else if ( localName == "bookmark-end" ) {
242 KWLoadingInfo* loadingInfo = m_textfs->kWordDocument()->loadingInfo();
243 TQString bkName = tag.attributeNS( KoXmlNS::text, "name", TQString() );
244 KWLoadingInfo::BookmarkStartsMap::iterator it = loadingInfo->m_bookmarkStarts.find( bkName );
245 if ( it == loadingInfo->m_bookmarkStarts.end() ) { // bookmark end without start. This seems to happen..
246 // insert simple bookmark then
247 appendBookmark( parag, pos, parag, pos, tag.attributeNS( KoXmlNS::text, "name", TQString() ) );
248 } else {
249 if ( (*it).doc != this ) {
250 // Oh tell me this never happens...
251 kdWarning(32500) << "Cross-frameset bookmark! Not supported." << endl;
252 } else {
253 appendBookmark( (*it).parag, (*it).pos, parag, pos, it.key() );
254 }
255 loadingInfo->m_bookmarkStarts.remove( it );
256 }
257 return true;
258 }
259 else if ( localName == "footnote" || localName == "endnote" )
260 {
261 textData = KoTextObject::customItemChar(); // anchor placeholder
262 loadOasisFootnote( tag, context, customItem );
263 return true;
264 }
265 }
266 else // not in the "text" namespace
267 {
268 if ( tag.namespaceURI() == KoXmlNS::draw && localName == "frame" )
269 {
270 if ( tag.attributeNS( KoXmlNS::koffice, "is-wrapper-frame", TQString() )
271 == "true" )
272 {
273 TQDomElement textbox = KoDom::namedItemNS( tag, KoXmlNS::draw, "text-box" );
274 if ( !textbox.isNull() )
275 {
276 int numberOfElements = 0;
277 TQDomElement elem;
278 TQDomElement firstElem;
279 forEachElement( elem, textbox )
280 {
281 ++numberOfElements;
282 firstElem = elem;
283 }
284 if ( numberOfElements == 1 ) // if someone added more stuff, keep the wrapper frame
285 {
286 kdDebug(32001) << "Wrapper frame removed, loading " << firstElem.tagName() << " directly" << endl;
287 // load the only child, e.g. table:table
288 return loadSpanTag( firstElem, context, parag, pos, textData, customItem );
289 }
290 }
291 return true;
292 }
293
294 KWDocument* doc = m_textfs->kWordDocument();
295 KWOasisLoader loader( doc );
296 KWFrame* frame = loader.loadFrame( tag, context, KoPoint() );
297 if ( frame )
298 {
299 KWFrameSet* fs = frame->frameSet();
300 // Hmm, if this is a continuation frame of a non-inline frameset,
301 // it's going to inline the whole frameset...
302 // ###### In fact this shows we should inline frames, not framesets, in KWord (!!!!) (big TODO)
303 // ## well, for tables it's the whole frameset.
304 textData = KoTextObject::customItemChar();
305 fs->setAnchorFrameset( m_textfs );
306 customItem = fs->createAnchor( m_textfs->textDocument(), 0 /*frame number; TODO somehow*/ );
307 }
308 return true;
309 }
310 // anchored-as-char table. Not supported by OASIS directly, but we end up
311 // calling this when removing the wrapper frame above.
312 else if ( tag.namespaceURI() == KoXmlNS::table && localName == "table" )
313 {
314 KWDocument* doc = m_textfs->kWordDocument();
315 KWOasisLoader loader( doc );
316 KWTableFrameSet* table = loader.loadOasisTable( tag, context );
317 table->finalize();
318 textData = KoTextObject::customItemChar();
319 table->setAnchorFrameset( m_textfs );
320 customItem = table->createAnchor( m_textfs->textDocument(), 0 /*frame number*/ );
321 return true;
322 }
323 }
324 return false;
325}
326
327#include "KWTextDocument.moc"
Class: KWFrameSet Base type, a frameset holds content as well as frames to show that content.
Definition KWFrameSet.h:62
virtual KWAnchor * createAnchor(KoTextDocument *txt, int frameNum)
Create an anchor for the floating frame identified by frameNum.
void setAnchorFrameset(KWTextFrameSet *textfs)
Sets the frameset in which we are about to become inline. Used for OASIS loading.
Definition KWFrameSet.h:376
This class represents a single frame.
Definition KWFrame.h:68
KWFrameSet * frameSet() const
Data stucture methods.
Definition KWFrame.h:143
Temporary information used only during loading.
This class implements tables by acting as the manager for the frame(set)s which make up the table cel...
virtual void finalize()
Called once the frameset has been completely loaded or constructed.
virtual KWAnchor * createAnchor(KoTextDocument *txt, int frameNum)
Create an anchor for the floating frame identified by frameNum.
virtual bool loadOasisBodyTag(const TQDomElement &tag, KoOasisContext &context, KoTextParag *&lastParagraph, KoStyleCollection *styleColl, KoTextParag *nextParagraph)
Extensions to KoTextDocument::loadOasisText.
KWTextDocument(KWTextFrameSet *textfs, KoTextFormatCollection *fc, KoTextFormatter *formatter=0L)
A real text document inside a frameset.
virtual bool loadSpanTag(const TQDomElement &tag, KoOasisContext &context, KoTextParag *parag, uint pos, TQString &textData, KoTextCustomItem *&customItem)
Extensions to KoTextParag::loadOasisSpan.
Class: KWTextFrameSet Contains text (KoTextObject) and frames to display that text.
void loadOasisContent(const TQDomElement &bodyElem, KoOasisContext &context)
Load the contents of a frame (i.e. the text).
Bookmarks (OASIS XML). Only need to store bookmark starts, until hitting bookmark ends.