merge the formfield patch from ooo-build
[ooovba.git] / sw / source / core / edit / edfld.cxx
blob82e915cdfe2d4f0bf75d0dcbf88be7e4ceb2e689
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: edfld.cxx,v $
10 * $Revision: 1.19 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sw.hxx"
35 #include <unotools/charclass.hxx>
36 #include <editsh.hxx>
37 #include <fldbas.hxx>
38 #include <ndtxt.hxx> // GetCurFld
39 #include <doc.hxx>
40 #include <docary.hxx>
41 #include <fmtfld.hxx>
42 #include <txtfld.hxx>
43 #include <edimp.hxx>
44 #include <dbfld.hxx>
45 #include <expfld.hxx>
46 #include <flddat.hxx>
47 #include <swundo.hxx>
48 #ifndef _DBMGR_HXX
49 #include <dbmgr.hxx>
50 #endif
51 #include <swddetbl.hxx>
52 #include <hints.hxx>
55 /*--------------------------------------------------------------------
56 Beschreibung: Feldtypen zu einer ResId zaehlen
57 wenn 0 alle zaehlen
58 --------------------------------------------------------------------*/
60 USHORT SwEditShell::GetFldTypeCount(USHORT nResId, BOOL bUsed ) const
62 const SwFldTypes* pFldTypes = GetDoc()->GetFldTypes();
63 const USHORT nSize = pFldTypes->Count();
65 if(nResId == USHRT_MAX)
67 if(!bUsed)
68 return nSize;
69 else
71 USHORT nUsed = 0;
72 for ( USHORT i = 0; i < nSize; i++ )
74 if(IsUsed(*(*pFldTypes)[i]))
75 nUsed++;
77 return nUsed;
81 // Alle Typen mit gleicher ResId
82 USHORT nIdx = 0;
83 for(USHORT i = 0; i < nSize; ++i)
84 { // Gleiche ResId -> Index erhoehen
85 SwFieldType& rFldType = *((*pFldTypes)[i]);
86 if(rFldType.Which() == nResId)
87 nIdx++;
89 return nIdx;
92 /*--------------------------------------------------------------------
93 Beschreibung: Feldtypen zu einer ResId finden
94 wenn 0 alle finden
95 --------------------------------------------------------------------*/
96 SwFieldType* SwEditShell::GetFldType(USHORT nFld, USHORT nResId, BOOL bUsed ) const
98 const SwFldTypes* pFldTypes = GetDoc()->GetFldTypes();
99 const USHORT nSize = pFldTypes->Count();
101 if(nResId == USHRT_MAX && nFld < nSize)
103 if(!bUsed)
104 return (*pFldTypes)[nFld];
105 else
107 USHORT i, nUsed = 0;
108 for ( i = 0; i < nSize; i++ )
110 if(IsUsed(*(*pFldTypes)[i]))
112 if(nUsed == nFld)
113 break;
114 nUsed++;
117 return i < nSize ? (*pFldTypes)[i] : 0;
121 USHORT nIdx = 0;
122 for(USHORT i = 0; i < nSize; ++i)
123 { // Gleiche ResId -> Index erhoehen
124 SwFieldType* pFldType = (*pFldTypes)[i];
125 if(pFldType->Which() == nResId)
127 if (!bUsed || IsUsed(*pFldType))
129 if(nIdx == nFld)
130 return pFldType;
131 nIdx++;
135 return 0;
138 /*--------------------------------------------------------------------
139 Beschreibung: Den ersten Typen mit ResId und Namen finden
140 --------------------------------------------------------------------*/
141 SwFieldType* SwEditShell::GetFldType(USHORT nResId, const String& rName) const
143 return GetDoc()->GetFldType( nResId, rName, false );
146 /*--------------------------------------------------------------------
147 Beschreibung: Feldtypen loeschen
148 --------------------------------------------------------------------*/
149 void SwEditShell::RemoveFldType(USHORT nFld, USHORT nResId)
151 if( USHRT_MAX == nResId )
153 GetDoc()->RemoveFldType(nFld);
154 return;
157 const SwFldTypes* pFldTypes = GetDoc()->GetFldTypes();
158 const USHORT nSize = pFldTypes->Count();
159 USHORT nIdx = 0;
160 for( USHORT i = 0; i < nSize; ++i )
161 // Gleiche ResId -> Index erhoehen
162 if( (*pFldTypes)[i]->Which() == nResId &&
163 nIdx++ == nFld )
165 GetDoc()->RemoveFldType( i );
166 return;
170 /*--------------------------------------------------------------------
171 Beschreibung: FieldType ueber Name loeschen
172 --------------------------------------------------------------------*/
173 void SwEditShell::RemoveFldType(USHORT nResId, const String& rStr)
175 const SwFldTypes* pFldTypes = GetDoc()->GetFldTypes();
176 const USHORT nSize = pFldTypes->Count();
177 const CharClass& rCC = GetAppCharClass();
179 String aTmp( rCC.lower( rStr ));
181 for(USHORT i = 0; i < nSize; ++i)
183 // Gleiche ResId -> Index erhoehen
184 SwFieldType* pFldType = (*pFldTypes)[i];
185 if( pFldType->Which() == nResId )
187 if( aTmp.Equals( rCC.lower( pFldType->GetName() ) ))
189 GetDoc()->RemoveFldType(i);
190 return;
197 void SwEditShell::FieldToText( SwFieldType* pType )
199 if( !pType->GetDepends() )
200 return;
202 SET_CURR_SHELL( this );
203 StartAllAction();
204 StartUndo( UNDO_DELETE );
205 Push();
206 SwPaM* pPaM = GetCrsr();
208 BOOL bDDEFld = RES_DDEFLD == pType->Which();
209 // Modify-Object gefunden, trage alle Felder ins Array ein
210 SwClientIter aIter( *pType );
211 SwClient * pLast = aIter.GoStart();
213 if( pLast ) // konnte zum Anfang gesprungen werden ??
214 do {
215 pPaM->DeleteMark();
216 const SwFmtFld* pFmtFld = bDDEFld
217 ? PTR_CAST( SwFmtFld, pLast )
218 : (SwFmtFld*)pLast;
220 if( pFmtFld )
222 if( !pFmtFld->GetTxtFld() )
223 continue;
225 // kann keine DDETabelle sein
226 const SwTxtNode& rTxtNode = pFmtFld->GetTxtFld()->GetTxtNode();
227 pPaM->GetPoint()->nNode = rTxtNode;
228 pPaM->GetPoint()->nContent.Assign( (SwTxtNode*)&rTxtNode,
229 *pFmtFld->GetTxtFld()->GetStart() );
231 // Feldinhalt durch Text ersetzen
232 String aEntry( pFmtFld->GetFld()->Expand() );
233 pPaM->SetMark();
234 pPaM->Move( fnMoveForward );
235 GetDoc()->DeleteRange( *pPaM );
236 GetDoc()->InsertString( *pPaM, aEntry );
238 else if( bDDEFld )
240 // DDETabelle
241 SwDepend* pDep = (SwDepend*)pLast;
242 SwDDETable* pDDETbl = (SwDDETable*)pDep->GetToTell();
243 pDDETbl->NoDDETable();
246 } while( 0 != ( pLast = aIter++ ));
248 Pop( FALSE );
249 EndAllAction();
250 EndUndo( UNDO_DELETE );
253 /*************************************************************************
255 |* SwEditShell::Insert( SwField )
257 |* Beschreibung an der Cursorposition ein Feld einfuegen
258 |* Quelle: vgl. SwEditShell::Insert( String )
260 *************************************************************************/
261 void SwEditShell::Insert2(SwField& rFld, const bool bForceExpandHints)
263 SET_CURR_SHELL( this );
264 StartAllAction();
265 SwFmtFld aFld( rFld );
267 const SetAttrMode nInsertFlags = (bForceExpandHints)
268 ? nsSetAttrMode::SETATTR_FORCEHINTEXPAND
269 : nsSetAttrMode::SETATTR_DEFAULT;
271 FOREACHPAM_START(this) // fuer jeden PaM
272 bool bSuccess(GetDoc()->InsertPoolItem(*PCURCRSR, aFld, nInsertFlags));
273 ASSERT( bSuccess, "Doc->Insert(Field) failed");
274 (void) bSuccess;
275 FOREACHPAM_END() // fuer jeden PaM
277 EndAllAction();
280 /*************************************************************************
282 |* SwEditShell::GetCurFld()
284 |* Beschreibung Stehen die PaMs auf Feldern ?
285 |* Quelle: edtfrm.cxx:
287 *************************************************************************/
289 inline SwTxtFld *GetDocTxtFld( const SwPosition* pPos )
291 SwTxtNode * const pNode = pPos->nNode.GetNode().GetTxtNode();
292 return (pNode)
293 ? static_cast<SwTxtFld*>( pNode->GetTxtAttrForCharAt(
294 pPos->nContent.GetIndex(), RES_TXTATR_FIELD ))
295 : 0;
298 SwField* SwEditShell::GetCurFld() const
300 // Wenn es keine Selektionen gibt, gilt der Wert der aktuellen
301 // Cursor-Position.
303 SwPaM* pCrsr = GetCrsr();
304 SwTxtFld *pTxtFld = GetDocTxtFld( pCrsr->Start() );
305 SwField *pCurFld = NULL;
307 /* #108536# Field was only recognized if no selection was
308 present. Now it is recognized if either the cursor is in the
309 field or the selection spans exactly over the field. */
310 if( pTxtFld &&
311 pCrsr->GetNext() == pCrsr &&
312 pCrsr->Start()->nNode == pCrsr->End()->nNode &&
313 (pCrsr->End()->nContent.GetIndex() -
314 pCrsr->Start()->nContent.GetIndex()) <= 1)
316 pCurFld = (SwField*)pTxtFld->GetFld().GetFld();
317 // TabellenFormel ? wandel internen in externen Namen um
318 if( RES_TABLEFLD == pCurFld->GetTyp()->Which() )
320 const SwTableNode* pTblNd = IsCrsrInTbl();
321 ((SwTblField*)pCurFld)->PtrToBoxNm( pTblNd ? &pTblNd->GetTable() : 0 );
326 /* #108536# removed handling of multi-selections */
328 return pCurFld;
332 /*************************************************************************
334 |* SwEditShell::UpdateFlds()
336 |* Beschreibung Stehen die PaMs auf Feldern ?
337 |* BP 12.05.92
339 *************************************************************************/
340 SwTxtFld* lcl_FindInputFld( SwDoc* pDoc, SwField& rFld )
342 // suche das Feld ueber seine Addresse. Muss fuer InputFelder in
343 // geschuetzten Feldern erfolgen
344 SwTxtFld* pTFld = 0;
345 if( RES_INPUTFLD == rFld.Which() || ( RES_SETEXPFLD == rFld.Which() &&
346 ((SwSetExpField&)rFld).GetInputFlag() ) )
348 const SfxPoolItem* pItem;
349 USHORT n, nMaxItems =
350 pDoc->GetAttrPool().GetItemCount( RES_TXTATR_FIELD );
351 for( n = 0; n < nMaxItems; ++n )
352 if( 0 != (pItem =
353 pDoc->GetAttrPool().GetItem( RES_TXTATR_FIELD, n ) )
354 && ((SwFmtFld*)pItem)->GetFld() == &rFld )
356 pTFld = ((SwFmtFld*)pItem)->GetTxtFld();
357 break;
360 return pTFld;
363 void SwEditShell::UpdateFlds( SwField &rFld )
365 SET_CURR_SHELL( this );
366 StartAllAction();
368 SwField *pCurFld = 0;
370 // Wenn es keine Selektionen gibt, gilt der Wert der aktuellen
371 // Cursor-Position.
372 SwMsgPoolItem* pMsgHnt = 0;
373 SwRefMarkFldUpdate aRefMkHt( GetOut() );
374 USHORT nFldWhich = rFld.GetTyp()->Which();
375 if( RES_GETREFFLD == nFldWhich )
376 pMsgHnt = &aRefMkHt;
378 SwPaM* pCrsr = GetCrsr();
379 SwTxtFld *pTxtFld;
380 SwFmtFld *pFmtFld;
382 // if( pCrsr->GetNext() == pCrsr && !pCrsr->HasMark() &&
383 // ( 0 != ( pTxtFld = GetDocTxtFld( pCrsr->Start() ) ) ||
384 // 0 != ( pTxtFld = lcl_FindInputFld( GetDoc(), rFld ) ) ) &&
385 // ( pFmtFld = (SwFmtFld*)&pTxtFld->GetFld())->GetFld()
386 // ->GetTyp()->Which() == rFld.GetTyp()->Which() )
387 if ( pCrsr->GetNext() == pCrsr && !pCrsr->HasMark())
389 pTxtFld = GetDocTxtFld(pCrsr->Start());
391 if (!pTxtFld) // #i30221#
392 pTxtFld = lcl_FindInputFld( GetDoc(), rFld);
394 if (pTxtFld != 0)
395 GetDoc()->UpdateFld(pTxtFld, rFld, pMsgHnt, TRUE); // #111840#
398 // bOkay (statt return wg. EndAllAction) wird FALSE,
399 // 1) wenn nur ein Pam mehr als ein Feld enthaelt oder
400 // 2) bei gemischten Feldtypen
401 BOOL bOkay = TRUE;
402 BOOL bTblSelBreak = FALSE;
404 SwMsgPoolItem aHint( RES_TXTATR_FIELD ); // Such-Hint
405 FOREACHPAM_START(this) // fuer jeden PaM
406 if( PCURCRSR->HasMark() && bOkay ) // ... mit Selektion
408 // Kopie des PaM
409 SwPaM aCurPam( *PCURCRSR->GetMark(), *PCURCRSR->GetPoint() );
410 SwPaM aPam( *PCURCRSR->GetPoint() );
412 SwPosition *pCurStt = aCurPam.Start(), *pCurEnd =
413 aCurPam.End();
415 * Fuer den Fall, dass zwei aneinanderliegende Felder in einem
416 * PaM liegen, hangelt sich aPam portionsweise bis zum Ende.
417 * aCurPam wird dabei nach jeder Schleifenrunde verkuerzt.
418 * Wenn aCurPam vollstaendig durchsucht wurde, ist Start = End
419 * und die Schleife terminiert.
422 // Suche nach SwTxtFld ...
423 while( bOkay
424 && pCurStt->nContent != pCurEnd->nContent
425 && aPam.Find( aHint, FALSE, fnMoveForward, &aCurPam ) )
427 // wenn nur ein Pam mehr als ein Feld enthaelt ...
428 if( aPam.Start()->nContent != pCurStt->nContent )
429 bOkay = FALSE;
431 if( 0 != (pTxtFld = GetDocTxtFld( pCurStt )) )
433 pFmtFld = (SwFmtFld*)&pTxtFld->GetFld();
434 pCurFld = pFmtFld->GetFld();
436 // bei gemischten Feldtypen
437 if( pCurFld->GetTyp()->Which() !=
438 rFld.GetTyp()->Which() )
439 bOkay = FALSE;
441 bTblSelBreak = GetDoc()->UpdateFld(pTxtFld, rFld,
442 pMsgHnt, FALSE); // #111840#
444 // Der Suchbereich wird um den gefundenen Bereich
445 // verkuerzt.
446 pCurStt->nContent++;
450 if( bTblSelBreak ) // wenn Tabellen Selektion und Tabellen-
451 break; // Formel aktualisiert wurde -> beenden
453 FOREACHPAM_END() // fuer jeden PaM
455 GetDoc()->SetModified();
456 EndAllAction();
459 /*-----------------13.05.92 10:54-------------------
460 Liefert den logischen fuer die Datenbank zurueck
461 --------------------------------------------------*/
463 SwDBData SwEditShell::GetDBData() const
465 return GetDoc()->GetDBData();
468 const SwDBData& SwEditShell::GetDBDesc() const
470 return GetDoc()->GetDBDesc();
473 void SwEditShell::ChgDBData(const SwDBData& rNewData)
475 GetDoc()->ChgDBData(rNewData);
478 void SwEditShell::GetAllUsedDB( SvStringsDtor& rDBNameList,
479 SvStringsDtor* pAllDBNames )
481 GetDoc()->GetAllUsedDB( rDBNameList, pAllDBNames );
484 void SwEditShell::ChangeDBFields( const SvStringsDtor& rOldNames,
485 const String& rNewName )
487 GetDoc()->ChangeDBFields( rOldNames, rNewName );
490 /*--------------------------------------------------------------------
491 Beschreibung: Alle Expression-Felder erneuern
492 --------------------------------------------------------------------*/
493 void SwEditShell::UpdateExpFlds(BOOL bCloseDB)
495 SET_CURR_SHELL( this );
496 StartAllAction();
497 GetDoc()->UpdateExpFlds(NULL, true);
498 if (bCloseDB)
499 GetDoc()->GetNewDBMgr()->CloseAll(); // Alle Datenbankverbindungen dichtmachen
500 EndAllAction();
503 SwNewDBMgr* SwEditShell::GetNewDBMgr() const
505 return GetDoc()->GetNewDBMgr();
508 /*--------------------------------------------------------------------
509 Beschreibung: Feldtypen einfuegen
510 --------------------------------------------------------------------*/
511 SwFieldType* SwEditShell::InsertFldType(const SwFieldType& rFldType)
513 return GetDoc()->InsertFldType(rFldType);
516 void SwEditShell::LockExpFlds()
518 GetDoc()->LockExpFlds();
521 void SwEditShell::UnlockExpFlds()
523 GetDoc()->UnlockExpFlds();
527 void SwEditShell::SetFldUpdateFlags( SwFldUpdateFlags eFlags )
529 getIDocumentSettingAccess()->setFieldUpdateFlags( eFlags );
532 SwFldUpdateFlags SwEditShell::GetFldUpdateFlags(BOOL bDocSettings) const
534 return getIDocumentSettingAccess()->getFieldUpdateFlags( !bDocSettings );
537 void SwEditShell::SetFixFields( BOOL bOnlyTimeDate,
538 const DateTime* pNewDateTime )
540 SET_CURR_SHELL( this );
541 BOOL bUnLockView = !IsViewLocked();
542 LockView( TRUE );
543 StartAllAction();
544 GetDoc()->SetFixFields( bOnlyTimeDate, pNewDateTime );
545 EndAllAction();
546 if( bUnLockView )
547 LockView( FALSE );
550 void SwEditShell::SetLabelDoc( BOOL bFlag )
552 GetDoc()->set(IDocumentSettingAccess::LABEL_DOCUMENT, bFlag );
555 BOOL SwEditShell::IsLabelDoc() const
557 return getIDocumentSettingAccess()->get(IDocumentSettingAccess::LABEL_DOCUMENT);
559 /* -----------------------------21.12.99 12:53--------------------------------
561 ---------------------------------------------------------------------------*/
562 void SwEditShell::ChangeAuthorityData(const SwAuthEntry* pNewData)
564 GetDoc()->ChangeAuthorityData(pNewData);
566 /* -----------------------------03.08.2001 12:04------------------------------
568 ---------------------------------------------------------------------------*/
569 BOOL SwEditShell::IsAnyDatabaseFieldInDoc()const
571 const SwFldTypes * pFldTypes = GetDoc()->GetFldTypes();
572 const USHORT nSize = pFldTypes->Count();
573 for(USHORT i = 0; i < nSize; ++i)
575 SwFieldType& rFldType = *((*pFldTypes)[i]);
576 USHORT nWhich = rFldType.Which();
577 if(IsUsed(rFldType))
579 switch(nWhich)
581 case RES_DBFLD:
582 case RES_DBNEXTSETFLD:
583 case RES_DBNUMSETFLD:
584 case RES_DBSETNUMBERFLD:
586 SwClientIter aIter( rFldType );
587 SwFmtFld* pFld = (SwFmtFld*)aIter.First( TYPE( SwFmtFld ));
588 while(pFld)
590 if(pFld->IsFldInDoc())
591 return TRUE;
592 pFld = (SwFmtFld*)aIter.Next();
595 break;
599 return FALSE;