xref: /aoo42x/main/sw/source/core/edit/edfld.cxx (revision 2f121198)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sw.hxx"
30 
31 
32 #include <unotools/charclass.hxx>
33 #include <editsh.hxx>
34 #include <fldbas.hxx>
35 #include <ndtxt.hxx>		// GetCurFld
36 #include <doc.hxx>
37 #include <docary.hxx>
38 #include <fmtfld.hxx>
39 #include <txtfld.hxx>
40 #include <edimp.hxx>
41 #include <dbfld.hxx>
42 #include <expfld.hxx>
43 #include <flddat.hxx>
44 #include <swundo.hxx>
45 #include <dbmgr.hxx>
46 #include <swddetbl.hxx>
47 #include <hints.hxx>
48 #include <switerator.hxx>
49 #include <fieldhint.hxx>
50 
51 /*--------------------------------------------------------------------
52 	Beschreibung: Feldtypen zu einer ResId zaehlen
53 				  wenn 0 alle zaehlen
54  --------------------------------------------------------------------*/
55 
56 sal_uInt16 SwEditShell::GetFldTypeCount(sal_uInt16 nResId, sal_Bool bUsed ) const
57 {
58 	const SwFldTypes* pFldTypes = GetDoc()->GetFldTypes();
59 	const sal_uInt16 nSize = pFldTypes->Count();
60 
61 	if(nResId == USHRT_MAX)
62 	{
63 		if(!bUsed)
64 			return nSize;
65 		else
66 		{
67 			sal_uInt16 nUsed = 0;
68 			for ( sal_uInt16 i = 0; i < nSize; i++ )
69 			{
70 				if(IsUsed(*(*pFldTypes)[i]))
71 					nUsed++;
72 			}
73 			return nUsed;
74 		}
75 	}
76 
77 	// Alle Typen mit gleicher ResId
78 	sal_uInt16 nIdx  = 0;
79 	for(sal_uInt16 i = 0; i < nSize; ++i)
80 	{   // Gleiche ResId -> Index erhoehen
81 		SwFieldType& rFldType = *((*pFldTypes)[i]);
82 		if(rFldType.Which() == nResId)
83 			nIdx++;
84 	}
85 	return nIdx;
86 }
87 
88 /*--------------------------------------------------------------------
89 	Beschreibung: Feldtypen zu einer ResId finden
90 				  wenn 0 alle finden
91  --------------------------------------------------------------------*/
92 SwFieldType* SwEditShell::GetFldType(sal_uInt16 nFld, sal_uInt16 nResId, sal_Bool bUsed ) const
93 {
94 	const SwFldTypes* pFldTypes = GetDoc()->GetFldTypes();
95 	const sal_uInt16 nSize = pFldTypes->Count();
96 
97 	if(nResId == USHRT_MAX && nFld < nSize)
98 	{
99 		if(!bUsed)
100 			return (*pFldTypes)[nFld];
101 		else
102 		{
103 			sal_uInt16 i, nUsed = 0;
104 			for ( i = 0; i < nSize; i++ )
105 			{
106 				if(IsUsed(*(*pFldTypes)[i]))
107 				{
108 					if(nUsed == nFld)
109 						break;
110 					nUsed++;
111 				}
112 			}
113 			return i < nSize ? (*pFldTypes)[i] : 0;
114 		}
115 	}
116 
117 	sal_uInt16 nIdx = 0;
118 	for(sal_uInt16 i = 0; i < nSize; ++i)
119 	{   // Gleiche ResId -> Index erhoehen
120 		SwFieldType* pFldType = (*pFldTypes)[i];
121 		if(pFldType->Which() == nResId)
122 		{
123 			if (!bUsed || IsUsed(*pFldType))
124 			{
125 				if(nIdx == nFld)
126 					return pFldType;
127 				nIdx++;
128 			}
129 		}
130 	}
131 	return 0;
132 }
133 
134 /*--------------------------------------------------------------------
135 	Beschreibung: Den ersten Typen mit ResId und Namen finden
136  --------------------------------------------------------------------*/
137 SwFieldType* SwEditShell::GetFldType(sal_uInt16 nResId, const String& rName) const
138 {
139 	return GetDoc()->GetFldType( nResId, rName, false );
140 }
141 
142 /*--------------------------------------------------------------------
143 	Beschreibung: Feldtypen loeschen
144  --------------------------------------------------------------------*/
145 void SwEditShell::RemoveFldType(sal_uInt16 nFld, sal_uInt16 nResId)
146 {
147 	if( USHRT_MAX == nResId )
148 	{
149 		GetDoc()->RemoveFldType(nFld);
150 		return;
151 	}
152 
153 	const SwFldTypes* pFldTypes = GetDoc()->GetFldTypes();
154 	const sal_uInt16 nSize = pFldTypes->Count();
155 	sal_uInt16 nIdx = 0;
156 	for( sal_uInt16 i = 0; i < nSize; ++i )
157 		// Gleiche ResId -> Index erhoehen
158 		if( (*pFldTypes)[i]->Which() == nResId &&
159 			nIdx++ == nFld )
160 		{
161 			GetDoc()->RemoveFldType( i );
162 			return;
163 		}
164 }
165 
166 /*--------------------------------------------------------------------
167 	Beschreibung: FieldType ueber Name loeschen
168  --------------------------------------------------------------------*/
169 void SwEditShell::RemoveFldType(sal_uInt16 nResId, const String& rStr)
170 {
171 	const SwFldTypes* pFldTypes = GetDoc()->GetFldTypes();
172 	const sal_uInt16 nSize = pFldTypes->Count();
173 	const CharClass& rCC = GetAppCharClass();
174 
175 	String aTmp( rCC.lower( rStr ));
176 
177 	for(sal_uInt16 i = 0; i < nSize; ++i)
178 	{
179 		// Gleiche ResId -> Index erhoehen
180 		SwFieldType* pFldType = (*pFldTypes)[i];
181 		if( pFldType->Which() == nResId )
182 		{
183 			if( aTmp.Equals( rCC.lower( pFldType->GetName() ) ))
184 			{
185 				GetDoc()->RemoveFldType(i);
186 				return;
187 			}
188 		}
189 	}
190 }
191 
192 
193 void SwEditShell::FieldToText( SwFieldType* pType )
194 {
195 	if( !pType->GetDepends() )
196 		return;
197 
198 	SET_CURR_SHELL( this );
199 	StartAllAction();
200 	StartUndo( UNDO_DELETE );
201 	Push();
202 	SwPaM* pPaM = GetCrsr();
203 
204     SwFieldHint aHint( pPaM );
205 	SwClientIter aIter( *pType );
206     for ( SwClient* pClient = aIter.GoStart(); pClient; pClient = ++aIter )
207     {
208         pPaM->DeleteMark();
209         pClient->SwClientNotifyCall( *pType, aHint );
210  	}
211 
212 	Pop( sal_False );
213 	EndAllAction();
214 	EndUndo( UNDO_DELETE );
215 }
216 
217 /*************************************************************************
218 |*
219 |*					SwEditShell::Insert( SwField )
220 |*
221 |*	  Beschreibung	an der Cursorposition ein Feld einfuegen
222 |*	  Quelle:		vgl. SwEditShell::Insert( String )
223 |*
224 *************************************************************************/
225 void SwEditShell::Insert2(SwField& rFld, const bool bForceExpandHints)
226 {
227 	SET_CURR_SHELL( this );
228 	StartAllAction();
229 	SwFmtFld aFld( rFld );
230 
231     const SetAttrMode nInsertFlags = (bForceExpandHints)
232         ? nsSetAttrMode::SETATTR_FORCEHINTEXPAND
233         : nsSetAttrMode::SETATTR_DEFAULT;
234 
235 	FOREACHPAM_START(this)						// fuer jeden PaM
236         bool bSuccess(GetDoc()->InsertPoolItem(*PCURCRSR, aFld, nInsertFlags));
237         ASSERT( bSuccess, "Doc->Insert(Field) failed");
238         (void) bSuccess;
239 	FOREACHPAM_END()					  // fuer jeden PaM
240 
241 	EndAllAction();
242 }
243 
244 /*************************************************************************
245 |*
246 |*					SwEditShell::GetCurFld()
247 |*
248 |*	  Beschreibung	Stehen die PaMs auf Feldern ?
249 |*	  Quelle:		edtfrm.cxx:
250 |*
251 *************************************************************************/
252 
253 inline SwTxtFld *GetDocTxtFld( const SwPosition* pPos )
254 {
255     SwTxtNode * const pNode = pPos->nNode.GetNode().GetTxtNode();
256     return (pNode)
257         ? static_cast<SwTxtFld*>( pNode->GetTxtAttrForCharAt(
258                 pPos->nContent.GetIndex(), RES_TXTATR_FIELD ))
259         : 0;
260 }
261 
262 SwField* SwEditShell::GetCurFld() const
263 {
264 	// Wenn es keine Selektionen gibt, gilt der Wert der aktuellen
265 	// Cursor-Position.
266 
267 	SwPaM* pCrsr = GetCrsr();
268 	SwTxtFld *pTxtFld = GetDocTxtFld( pCrsr->Start() );
269 	SwField *pCurFld = NULL;
270 
271     /* #108536# Field was only recognized if no selection was
272         present. Now it is recognized if either the cursor is in the
273         field or the selection spans exactly over the field. */
274 	if( pTxtFld &&
275         pCrsr->GetNext() == pCrsr &&
276         pCrsr->Start()->nNode == pCrsr->End()->nNode &&
277         (pCrsr->End()->nContent.GetIndex() -
278          pCrsr->Start()->nContent.GetIndex()) <= 1)
279 	{
280 		pCurFld = (SwField*)pTxtFld->GetFld().GetFld();
281 		// TabellenFormel ? wandel internen in externen Namen um
282 		if( RES_TABLEFLD == pCurFld->GetTyp()->Which() )
283 		{
284 			const SwTableNode* pTblNd = IsCrsrInTbl();
285 			((SwTblField*)pCurFld)->PtrToBoxNm( pTblNd ? &pTblNd->GetTable() : 0 );
286 		}
287 
288 	}
289 
290     /* #108536# removed handling of multi-selections */
291 
292 	return pCurFld;
293 }
294 
295 
296 /*************************************************************************
297 |*
298 |*					SwEditShell::UpdateFlds()
299 |*
300 |*	  Beschreibung	Stehen die PaMs auf Feldern ?
301 |*					BP 12.05.92
302 |*
303 *************************************************************************/
304 SwTxtFld* lcl_FindInputFld( SwDoc* pDoc, SwField& rFld )
305 {
306 	// suche das Feld ueber seine Addresse. Muss fuer InputFelder in
307 	// geschuetzten Feldern erfolgen
308 	SwTxtFld* pTFld = 0;
309 	if( RES_INPUTFLD == rFld.Which() || ( RES_SETEXPFLD == rFld.Which() &&
310 		((SwSetExpField&)rFld).GetInputFlag() ) )
311 	{
312 		const SfxPoolItem* pItem;
313 		sal_uInt32 n, nMaxItems =
314             pDoc->GetAttrPool().GetItemCount2( RES_TXTATR_FIELD );
315 		for( n = 0; n < nMaxItems; ++n )
316 			if( 0 != (pItem =
317                       pDoc->GetAttrPool().GetItem2( RES_TXTATR_FIELD, n ) )
318 				&& ((SwFmtFld*)pItem)->GetFld() == &rFld )
319 			{
320 				pTFld = ((SwFmtFld*)pItem)->GetTxtFld();
321 				break;
322 			}
323 	}
324 	return pTFld;
325 }
326 
327 void SwEditShell::UpdateFlds( SwField &rFld )
328 {
329 	SET_CURR_SHELL( this );
330 	StartAllAction();
331 	{
332 		SwField *pCurFld = 0;
333 
334 		// Wenn es keine Selektionen gibt, gilt der Wert der aktuellen
335 		// Cursor-Position.
336 		SwMsgPoolItem* pMsgHnt = 0;
337 		SwRefMarkFldUpdate aRefMkHt( GetOut() );
338 		sal_uInt16 nFldWhich = rFld.GetTyp()->Which();
339 		if( RES_GETREFFLD == nFldWhich )
340 			pMsgHnt = &aRefMkHt;
341 
342 		SwPaM* pCrsr = GetCrsr();
343 		SwTxtFld *pTxtFld;
344 		SwFmtFld *pFmtFld;
345 
346 // 		if( pCrsr->GetNext() == pCrsr && !pCrsr->HasMark() &&
347 // 			( 0 != ( pTxtFld = GetDocTxtFld( pCrsr->Start() ) ) ||
348 // 			  0 != ( pTxtFld = lcl_FindInputFld( GetDoc(), rFld ) ) ) &&
349 // 			( pFmtFld = (SwFmtFld*)&pTxtFld->GetFld())->GetFld()
350 // 				->GetTyp()->Which() == rFld.GetTyp()->Which() )
351         if ( pCrsr->GetNext() == pCrsr && !pCrsr->HasMark())
352         {
353             pTxtFld = GetDocTxtFld(pCrsr->Start());
354 
355             if (!pTxtFld) // #i30221#
356                 pTxtFld = lcl_FindInputFld( GetDoc(), rFld);
357 
358             if (pTxtFld != 0)
359                 GetDoc()->UpdateFld(pTxtFld, rFld, pMsgHnt, sal_True); // #111840#
360         }
361 
362 		// bOkay (statt return wg. EndAllAction) wird sal_False,
363 		// 1) wenn nur ein Pam mehr als ein Feld enthaelt oder
364 		// 2) bei gemischten Feldtypen
365 		sal_Bool bOkay = sal_True;
366 		sal_Bool bTblSelBreak = sal_False;
367 
368 		SwMsgPoolItem aHint( RES_TXTATR_FIELD );  // Such-Hint
369 		FOREACHPAM_START(this)						// fuer jeden PaM
370 			if( PCURCRSR->HasMark() && bOkay )		// ... mit Selektion
371 			{
372 				// Kopie des PaM
373 				SwPaM aCurPam( *PCURCRSR->GetMark(), *PCURCRSR->GetPoint() );
374 				SwPaM aPam( *PCURCRSR->GetPoint() );
375 
376 				SwPosition *pCurStt = aCurPam.Start(), *pCurEnd =
377                     aCurPam.End();
378 				/*
379 				 * Fuer den Fall, dass zwei aneinanderliegende Felder in einem
380 				 * PaM liegen, hangelt sich aPam portionsweise bis zum Ende.
381 				 * aCurPam wird dabei nach jeder Schleifenrunde verkuerzt.
382 				 * Wenn aCurPam vollstaendig durchsucht wurde, ist Start = End
383 				 * und die Schleife terminiert.
384 				 */
385 
386 				// Suche nach SwTxtFld ...
387 				while(	bOkay
388 					 && pCurStt->nContent != pCurEnd->nContent
389 					 && aPam.Find( aHint, sal_False, fnMoveForward, &aCurPam ) )
390 				{
391 					//	wenn nur ein Pam mehr als ein Feld enthaelt ...
392 					if( aPam.Start()->nContent != pCurStt->nContent )
393 						bOkay = sal_False;
394 
395 					if( 0 != (pTxtFld = GetDocTxtFld( pCurStt )) )
396 					{
397 						pFmtFld = (SwFmtFld*)&pTxtFld->GetFld();
398 						pCurFld = pFmtFld->GetFld();
399 
400 						// bei gemischten Feldtypen
401 						if( pCurFld->GetTyp()->Which() !=
402                             rFld.GetTyp()->Which() )
403 							bOkay = sal_False;
404 
405                         bTblSelBreak = GetDoc()->UpdateFld(pTxtFld, rFld,
406                                                            pMsgHnt, sal_False); // #111840#
407 					}
408 					// Der Suchbereich wird um den gefundenen Bereich
409 					// verkuerzt.
410 					pCurStt->nContent++;
411 				}
412 			}
413 
414 			if( bTblSelBreak )		// wenn Tabellen Selektion und Tabellen-
415 				break;				// Formel aktualisiert wurde -> beenden
416 
417 		FOREACHPAM_END()					  // fuer jeden PaM
418 	}
419 	GetDoc()->SetModified();
420 	EndAllAction();
421 }
422 
423 /*-----------------13.05.92 10:54-------------------
424  Liefert den logischen fuer die Datenbank zurueck
425  --------------------------------------------------*/
426 
427 SwDBData SwEditShell::GetDBData() const
428 {
429 	return GetDoc()->GetDBData();
430 }
431 
432 const SwDBData& SwEditShell::GetDBDesc() const
433 {
434 	return GetDoc()->GetDBDesc();
435 }
436 
437 void SwEditShell::ChgDBData(const SwDBData& rNewData)
438 {
439 	GetDoc()->ChgDBData(rNewData);
440 }
441 
442 void SwEditShell::GetAllUsedDB( SvStringsDtor& rDBNameList,
443 								SvStringsDtor* pAllDBNames )
444 {
445 	GetDoc()->GetAllUsedDB( rDBNameList, pAllDBNames );
446 }
447 
448 void SwEditShell::ChangeDBFields( const SvStringsDtor& rOldNames,
449 									const String& rNewName )
450 {
451 	GetDoc()->ChangeDBFields( rOldNames, rNewName );
452 }
453 
454 /*--------------------------------------------------------------------
455 	Beschreibung:  Alle Expression-Felder erneuern
456  --------------------------------------------------------------------*/
457 void SwEditShell::UpdateExpFlds(sal_Bool bCloseDB)
458 {
459 	SET_CURR_SHELL( this );
460 	StartAllAction();
461 	GetDoc()->UpdateExpFlds(NULL, true);
462 	if (bCloseDB)
463 		GetDoc()->GetNewDBMgr()->CloseAll();	// Alle Datenbankverbindungen dichtmachen
464 	EndAllAction();
465 }
466 
467 SwNewDBMgr* SwEditShell::GetNewDBMgr() const
468 {
469 	return GetDoc()->GetNewDBMgr();
470 }
471 
472 /*--------------------------------------------------------------------
473 	Beschreibung: Feldtypen einfuegen
474  --------------------------------------------------------------------*/
475 SwFieldType* SwEditShell::InsertFldType(const SwFieldType& rFldType)
476 {
477 	return GetDoc()->InsertFldType(rFldType);
478 }
479 
480 void SwEditShell::LockExpFlds()
481 {
482 	GetDoc()->LockExpFlds();
483 }
484 
485 void SwEditShell::UnlockExpFlds()
486 {
487 	GetDoc()->UnlockExpFlds();
488 }
489 
490 
491 void SwEditShell::SetFldUpdateFlags( SwFldUpdateFlags eFlags )
492 {
493     getIDocumentSettingAccess()->setFieldUpdateFlags( eFlags );
494 }
495 
496 SwFldUpdateFlags SwEditShell::GetFldUpdateFlags(sal_Bool bDocSettings) const
497 {
498     return getIDocumentSettingAccess()->getFieldUpdateFlags( !bDocSettings );
499 }
500 
501 void SwEditShell::SetFixFields( sal_Bool bOnlyTimeDate,
502 								const DateTime* pNewDateTime )
503 {
504 	SET_CURR_SHELL( this );
505 	sal_Bool bUnLockView = !IsViewLocked();
506 	LockView( sal_True );
507 	StartAllAction();
508 	GetDoc()->SetFixFields( bOnlyTimeDate, pNewDateTime );
509 	EndAllAction();
510 	if( bUnLockView )
511 		LockView( sal_False );
512 }
513 
514 void SwEditShell::SetLabelDoc( sal_Bool bFlag )
515 {
516 	GetDoc()->set(IDocumentSettingAccess::LABEL_DOCUMENT, bFlag );
517 }
518 
519 sal_Bool SwEditShell::IsLabelDoc() const
520 {
521     return getIDocumentSettingAccess()->get(IDocumentSettingAccess::LABEL_DOCUMENT);
522 }
523 /* -----------------------------21.12.99 12:53--------------------------------
524 
525  ---------------------------------------------------------------------------*/
526 void SwEditShell::ChangeAuthorityData(const SwAuthEntry* pNewData)
527 {
528 	GetDoc()->ChangeAuthorityData(pNewData);
529 }
530 /* -----------------------------03.08.2001 12:04------------------------------
531 
532  ---------------------------------------------------------------------------*/
533 sal_Bool SwEditShell::IsAnyDatabaseFieldInDoc()const
534 {
535     const SwFldTypes * pFldTypes = GetDoc()->GetFldTypes();
536     const sal_uInt16 nSize = pFldTypes->Count();
537     for(sal_uInt16 i = 0; i < nSize; ++i)
538     {
539         SwFieldType& rFldType = *((*pFldTypes)[i]);
540         sal_uInt16 nWhich = rFldType.Which();
541         if(IsUsed(rFldType))
542         {
543             switch(nWhich)
544             {
545                 case RES_DBFLD:
546                 case RES_DBNEXTSETFLD:
547                 case RES_DBNUMSETFLD:
548                 case RES_DBSETNUMBERFLD:
549                 {
550                     SwIterator<SwFmtFld,SwFieldType> aIter( rFldType );
551                     SwFmtFld* pFld = aIter.First();
552                     while(pFld)
553                     {
554                         if(pFld->IsFldInDoc())
555                             return sal_True;
556                         pFld = aIter.Next();
557                     }
558                 }
559                 break;
560             }
561         }
562     }
563     return sal_False;
564 }
565