xref: /trunk/main/sw/source/core/edit/edfld.cxx (revision 3a7cf181c55416e69e525ddc0b38c22235ec1569)
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