xref: /AOO41X/main/sw/source/core/edit/edfld.cxx (revision 707fc0d4d52eb4f69d89a98ffec6918ca5de6326)
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->GetFld().GetFld();
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)->GetFld() == &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->GetFld();
394                         pCurFld = pFmtFld->GetFld();
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