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