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 #include <hintids.hxx> 31 #include <vcl/salbtype.hxx> // FRound 32 #include <tools/urlobj.hxx> 33 #include <svl/undo.hxx> 34 #ifndef SVTOOLS_FSTATHELPER_HXX 35 #include <svl/fstathelper.hxx> 36 #endif 37 #include <svtools/imap.hxx> 38 #include <svtools/filter.hxx> 39 #include <sot/storage.hxx> 40 #include <sfx2/linkmgr.hxx> 41 #include <editeng/boxitem.hxx> 42 #include <sot/formats.hxx> 43 #include <fmtfsize.hxx> 44 #include <fmturl.hxx> 45 #include <frmfmt.hxx> 46 #include <doc.hxx> 47 #include <frmatr.hxx> 48 #include <grfatr.hxx> 49 #include <swtypes.hxx> 50 #include <ndgrf.hxx> 51 #include <fmtcol.hxx> 52 #include <hints.hxx> 53 #include <swbaslnk.hxx> 54 #include <pagefrm.hxx> 55 #include <editsh.hxx> 56 #include <pam.hxx> 57 58 #include <unotools/ucbstreamhelper.hxx> 59 #include <com/sun/star/embed/ElementModes.hpp> 60 #include <com/sun/star/embed/XTransactedObject.hpp> 61 #include <tools/link.hxx> 62 #include <vcl/svapp.hxx> 63 #include <com/sun/star/io/XSeekable.hpp> 64 // --> OD 2007-03-28 #i73788# 65 #include <retrieveinputstreamconsumer.hxx> 66 // <-- 67 68 using namespace com::sun::star; 69 70 // -------------------- 71 // SwGrfNode 72 // -------------------- 73 SwGrfNode::SwGrfNode( 74 const SwNodeIndex & rWhere, 75 const String& rGrfName, const String& rFltName, 76 const Graphic* pGraphic, 77 SwGrfFmtColl *pGrfColl, 78 SwAttrSet* pAutoAttr ) : 79 SwNoTxtNode( rWhere, ND_GRFNODE, pGrfColl, pAutoAttr ), 80 // --> OD 2007-01-23 #i73788# 81 mbLinkedInputStreamReady( false ), 82 mbIsStreamReadOnly( sal_False ) 83 // <-- 84 { 85 aGrfObj.SetSwapStreamHdl( LINK( this, SwGrfNode, SwapGraphic ) ); 86 bInSwapIn = bChgTwipSize = bChgTwipSizeFromPixel = bLoadLowResGrf = 87 bFrameInPaint = bScaleImageMap = sal_False; 88 89 bGrafikArrived = sal_True; 90 ReRead(rGrfName,rFltName, pGraphic, 0, sal_False); 91 } 92 93 SwGrfNode::SwGrfNode( const SwNodeIndex & rWhere, 94 const GraphicObject& rGrfObj, 95 SwGrfFmtColl *pGrfColl, SwAttrSet* pAutoAttr ) : 96 SwNoTxtNode( rWhere, ND_GRFNODE, pGrfColl, pAutoAttr ), 97 // --> OD 2007-01-23 #i73788# 98 mbLinkedInputStreamReady( false ), 99 mbIsStreamReadOnly( sal_False ) 100 // <-- 101 { 102 aGrfObj = rGrfObj; 103 aGrfObj.SetSwapStreamHdl( LINK( this, SwGrfNode, SwapGraphic ) ); 104 if( rGrfObj.HasUserData() && rGrfObj.IsSwappedOut() ) 105 aGrfObj.SetSwapState(); 106 bInSwapIn = bChgTwipSize = bChgTwipSizeFromPixel= bLoadLowResGrf = 107 bFrameInPaint = bScaleImageMap = sal_False; 108 bGrafikArrived = sal_True; 109 } 110 111 // Konstruktor fuer den SW/G-Reader. Dieser ctor wird verwendet, 112 // wenn eine gelinkte Grafik gelesen wird. Sie liest diese NICHT ein. 113 114 115 SwGrfNode::SwGrfNode( const SwNodeIndex & rWhere, 116 const String& rGrfName, const String& rFltName, 117 SwGrfFmtColl *pGrfColl, 118 SwAttrSet* pAutoAttr ) : 119 SwNoTxtNode( rWhere, ND_GRFNODE, pGrfColl, pAutoAttr ), 120 // --> OD 2007-01-23 #i73788# 121 mbLinkedInputStreamReady( false ), 122 mbIsStreamReadOnly( sal_False ) 123 // <-- 124 { 125 aGrfObj.SetSwapStreamHdl( LINK( this, SwGrfNode, SwapGraphic ) ); 126 127 Graphic aGrf; aGrf.SetDefaultType(); 128 aGrfObj.SetGraphic( aGrf, rGrfName ); 129 130 bInSwapIn = bChgTwipSize = bChgTwipSizeFromPixel = bLoadLowResGrf = 131 bFrameInPaint = bScaleImageMap = sal_False; 132 bGrafikArrived = sal_True; 133 134 InsertLink( rGrfName, rFltName ); 135 if( IsLinkedFile() ) 136 { 137 INetURLObject aUrl( rGrfName ); 138 if( INET_PROT_FILE == aUrl.GetProtocol() && 139 FStatHelper::IsDocument( aUrl.GetMainURL( INetURLObject::NO_DECODE ) )) 140 { 141 // File vorhanden, Verbindung herstellen ohne ein Update 142 ((SwBaseLink*)&refLink)->Connect(); 143 } 144 } 145 } 146 147 sal_Bool SwGrfNode::ReRead( 148 const String& rGrfName, const String& rFltName, 149 const Graphic* pGraphic, const GraphicObject* pGrfObj, 150 sal_Bool bNewGrf ) 151 { 152 sal_Bool bReadGrf = sal_False, bSetTwipSize = sal_True; 153 154 ASSERT( pGraphic || pGrfObj || rGrfName.Len(), 155 "GraphicNode without a name, Graphic or GraphicObject" ); 156 157 // ReadRead mit Namen 158 if( refLink.Is() ) 159 { 160 ASSERT( !bInSwapIn, "ReRead: stehe noch im SwapIn" ); 161 162 if( rGrfName.Len() ) 163 { 164 // Besonderheit: steht im FltNamen DDE, handelt es sich um eine 165 // DDE-gelinkte Grafik 166 String sCmd( rGrfName ); 167 if( rFltName.Len() ) 168 { 169 sal_uInt16 nNewType; 170 if( rFltName.EqualsAscii( "DDE" )) 171 nNewType = OBJECT_CLIENT_DDE; 172 else 173 { 174 sfx2::MakeLnkName( sCmd, 0, rGrfName, aEmptyStr, &rFltName ); 175 nNewType = OBJECT_CLIENT_GRF; 176 } 177 178 if( nNewType != refLink->GetObjType() ) 179 { 180 refLink->Disconnect(); 181 ((SwBaseLink*)&refLink)->SetObjType( nNewType ); 182 } 183 } 184 185 refLink->SetLinkSourceName( sCmd ); 186 } 187 else // kein Name mehr, Link aufheben 188 { 189 GetDoc()->GetLinkManager().Remove( refLink ); 190 refLink.Clear(); 191 } 192 193 if( pGraphic ) 194 { 195 aGrfObj.SetGraphic( *pGraphic, rGrfName ); 196 bReadGrf = sal_True; 197 } 198 else if( pGrfObj ) 199 { 200 aGrfObj = *pGrfObj; 201 if( pGrfObj->HasUserData() && pGrfObj->IsSwappedOut() ) 202 aGrfObj.SetSwapState(); 203 aGrfObj.SetLink( rGrfName ); 204 bReadGrf = sal_True; 205 } 206 else 207 { 208 // MIB 25.02.97: Daten der alten Grafik zuruecksetzen, damit 209 // die korrekte Ersatz-Darstellung erscheint, wenn die 210 // der neue Link nicht geladen werden konnte. 211 Graphic aGrf; aGrf.SetDefaultType(); 212 aGrfObj.SetGraphic( aGrf, rGrfName ); 213 214 if( refLink.Is() ) 215 { 216 if( getLayoutFrm( GetDoc()->GetCurrentLayout() ) ) 217 { 218 SwMsgPoolItem aMsgHint( RES_GRF_REREAD_AND_INCACHE ); 219 ModifyNotification( &aMsgHint, &aMsgHint ); 220 } 221 // --> OD 2006-11-03 #i59688# 222 // do not load linked graphic, if it isn't a new linked graphic. 223 // else { 224 else if ( bNewGrf ) 225 // <-- 226 { 227 //TODO refLink->setInputStream(getInputStream()); 228 ((SwBaseLink*)&refLink)->SwapIn(); 229 } 230 } 231 bSetTwipSize = sal_False; 232 } 233 } 234 else if( pGraphic && !rGrfName.Len() ) 235 { 236 // MIB 27.02.2001: Old stream must be deleted before the new one is set. 237 if( HasStreamName() ) 238 DelStreamName(); 239 240 aGrfObj.SetGraphic( *pGraphic ); 241 bReadGrf = sal_True; 242 } 243 else if( pGrfObj && !rGrfName.Len() ) 244 { 245 // MIB 27.02.2001: Old stream must be deleted before the new one is set. 246 if( HasStreamName() ) 247 DelStreamName(); 248 249 aGrfObj = *pGrfObj; 250 if( pGrfObj->HasUserData() && pGrfObj->IsSwappedOut() ) 251 aGrfObj.SetSwapState(); 252 bReadGrf = sal_True; 253 } 254 // Import einer Grafik: 255 // Ist die Grafik bereits geladen? 256 else if( !bNewGrf && GRAPHIC_NONE != aGrfObj.GetType() ) 257 return sal_True; 258 259 else 260 { 261 if( HasStreamName() ) 262 DelStreamName(); 263 264 // einen neuen Grafik-Link anlegen 265 InsertLink( rGrfName, rFltName ); 266 267 if( GetNodes().IsDocNodes() ) 268 { 269 if( pGraphic ) 270 { 271 aGrfObj.SetGraphic( *pGraphic, rGrfName ); 272 bReadGrf = sal_True; 273 // Verbindung herstellen ohne ein Update; Grafik haben wir! 274 ((SwBaseLink*)&refLink)->Connect(); 275 } 276 else if( pGrfObj ) 277 { 278 aGrfObj = *pGrfObj; 279 aGrfObj.SetLink( rGrfName ); 280 bReadGrf = sal_True; 281 // Verbindung herstellen ohne ein Update; Grafik haben wir! 282 ((SwBaseLink*)&refLink)->Connect(); 283 } 284 else 285 { 286 // MIB 25.02.97: Daten der alten Grafik zuruecksetzen, damit 287 // die korrekte Ersatz-Darstellung erscheint, wenn die 288 // der neue Kink nicht geladen werden konnte. 289 Graphic aGrf; aGrf.SetDefaultType(); 290 aGrfObj.SetGraphic( aGrf, rGrfName ); 291 // --> OD 2006-11-03 #i59688# 292 // do not load linked graphic, if it isn't a new linked graphic. 293 // //TODO refLink->setInputStream(getInputStream()); 294 // ((SwBaseLink*)&refLink)->SwapIn(); 295 if ( bNewGrf ) 296 { 297 ((SwBaseLink*)&refLink)->SwapIn(); 298 } 299 // <-- 300 } 301 } 302 } 303 304 // Bug 39281: Size nicht sofort loeschen - Events auf ImageMaps 305 // sollten nicht beim Austauschen nicht ins "leere greifen" 306 if( bSetTwipSize ) 307 SetTwipSize( ::GetGraphicSizeTwip( aGrfObj.GetGraphic(), 0 ) ); 308 309 // erzeuge noch einen Update auf die Frames 310 if( bReadGrf && bNewGrf ) 311 { 312 SwMsgPoolItem aMsgHint( RES_UPDATE_ATTR ); 313 ModifyNotification( &aMsgHint, &aMsgHint ); 314 } 315 316 return bReadGrf; 317 } 318 319 320 SwGrfNode::~SwGrfNode() 321 { 322 // --> OD 2007-03-30 #i73788# 323 mpThreadConsumer.reset(); 324 // <-- 325 326 SwDoc* pDoc = GetDoc(); 327 if( refLink.Is() ) 328 { 329 ASSERT( !bInSwapIn, "DTOR: stehe noch im SwapIn" ); 330 pDoc->GetLinkManager().Remove( refLink ); 331 refLink->Disconnect(); 332 } 333 else 334 { 335 // --> OD 2005-01-19 #i40014# - A graphic node, which are in linked 336 // section, whose link is another section is the document, doesn't 337 // have to remove the stream from the storage. 338 // Because it's hard to detect this case here and it would only fix 339 // one problem with shared graphic files - there are also problems, 340 // a certain graphic file is referenced by two independent graphic nodes, 341 // brush item or drawing objects, the stream isn't no longer removed here. 342 // To do this stuff correct, a reference counting on shared streams 343 // inside one document have to be implemented. 344 // if( !pDoc->IsInDtor() && HasStreamName() ) 345 // DelStreamName(); 346 // <-- 347 } 348 //#39289# Die Frames muessen hier bereits geloescht weil der DTor der 349 //Frms die Grafik noch fuer StopAnimation braucht. 350 if( GetDepends() ) 351 DelFrms(); 352 } 353 354 355 SwCntntNode *SwGrfNode::SplitCntntNode( const SwPosition & ) 356 { 357 return this; 358 } 359 360 361 SwGrfNode * SwNodes::MakeGrfNode( const SwNodeIndex & rWhere, 362 const String& rGrfName, 363 const String& rFltName, 364 const Graphic* pGraphic, 365 SwGrfFmtColl* pGrfColl, 366 SwAttrSet* pAutoAttr, 367 sal_Bool bDelayed ) 368 { 369 ASSERT( pGrfColl, "MakeGrfNode: Formatpointer ist 0." ); 370 SwGrfNode *pNode; 371 // Delayed erzeugen nur aus dem SW/G-Reader 372 if( bDelayed ) 373 pNode = new SwGrfNode( rWhere, rGrfName, 374 rFltName, pGrfColl, pAutoAttr ); 375 else 376 pNode = new SwGrfNode( rWhere, rGrfName, 377 rFltName, pGraphic, pGrfColl, pAutoAttr ); 378 return pNode; 379 } 380 381 SwGrfNode * SwNodes::MakeGrfNode( const SwNodeIndex & rWhere, 382 const GraphicObject& rGrfObj, 383 SwGrfFmtColl* pGrfColl, 384 SwAttrSet* pAutoAttr ) 385 { 386 ASSERT( pGrfColl, "MakeGrfNode: Formatpointer ist 0." ); 387 return new SwGrfNode( rWhere, rGrfObj, pGrfColl, pAutoAttr ); 388 } 389 390 391 Size SwGrfNode::GetTwipSize() const 392 { 393 return nGrfSize; 394 } 395 396 397 398 sal_Bool SwGrfNode::ImportGraphic( SvStream& rStrm ) 399 { 400 Graphic aGraphic; 401 if( !GraphicFilter::GetGraphicFilter()->ImportGraphic( aGraphic, String(), rStrm ) ) 402 { 403 const String aUserData( aGrfObj.GetUserData() ); 404 405 aGrfObj.SetGraphic( aGraphic ); 406 aGrfObj.SetUserData( aUserData ); 407 return sal_True; 408 } 409 410 return sal_False; 411 } 412 413 // Returnwert: 414 // -1 : ReRead erfolgreich 415 // 0 : nicht geladen 416 // 1 : Einlesen erfolgreich 417 418 short SwGrfNode::SwapIn( sal_Bool bWaitForData ) 419 { 420 if( bInSwapIn ) // nicht rekuriv!! 421 return !aGrfObj.IsSwappedOut(); 422 423 short nRet = 0; 424 bInSwapIn = sal_True; 425 SwBaseLink* pLink = (SwBaseLink*)(::sfx2::SvBaseLink*) refLink; 426 427 if( pLink ) 428 { 429 if( GRAPHIC_NONE == aGrfObj.GetType() || 430 GRAPHIC_DEFAULT == aGrfObj.GetType() ) 431 { 432 // noch nicht geladener Link 433 //TODO pLink->setInputStream(getInputStream()); 434 if( pLink->SwapIn( bWaitForData ) ) 435 nRet = -1; 436 else if( GRAPHIC_DEFAULT == aGrfObj.GetType() ) 437 { 438 // keine default Bitmap mehr, also neu Painten! 439 aGrfObj.SetGraphic( Graphic() ); 440 SwMsgPoolItem aMsgHint( RES_GRAPHIC_PIECE_ARRIVED ); 441 ModifyNotification( &aMsgHint, &aMsgHint ); 442 } 443 } 444 else if( aGrfObj.IsSwappedOut() ) { 445 // nachzuladender Link 446 //TODO pLink->setInputStream(getInputStream()); 447 nRet = pLink->SwapIn( bWaitForData ) ? 1 : 0; 448 } 449 else 450 nRet = 1; 451 } 452 else if( aGrfObj.IsSwappedOut() ) 453 { 454 // Die Grafik ist im Storage oder im TempFile drin 455 if( !HasStreamName() ) 456 nRet = (short)aGrfObj.SwapIn(); 457 else 458 { 459 460 // --> OD 2005-05-04 #i48434# - usage of new method <_GetStreamForEmbedGrf(..)> 461 try 462 { 463 // --> OD, MAV 2005-08-17 #i53025# - needed correction of new 464 // method <_GetStreamForEmbedGrf(..)> 465 // bool bGraphic(false); 466 // SvStream* pStrm = _GetStreamForEmbedGrf( bGraphic ); 467 String aStrmName, aPicStgName; 468 _GetStreamStorageNames( aStrmName, aPicStgName ); 469 uno::Reference < embed::XStorage > refPics = _GetDocSubstorageOrRoot( aPicStgName ); 470 SvStream* pStrm = _GetStreamForEmbedGrf( refPics, aStrmName ); 471 if ( pStrm ) 472 { 473 if ( ImportGraphic( *pStrm ) ) 474 nRet = 1; 475 delete pStrm; 476 } 477 // <-- 478 } 479 catch ( uno::Exception& ) 480 { 481 // --> OD 2005-04-25 #i48434# 482 ASSERT( false, "<SwGrfNode::SwapIn(..)> - unhandled exception!" ); 483 // <-- 484 } 485 // <-- 486 } 487 488 if( 1 == nRet ) 489 { 490 SwMsgPoolItem aMsg( RES_GRAPHIC_SWAPIN ); 491 ModifyNotification( &aMsg, &aMsg ); 492 } 493 } 494 else 495 nRet = 1; 496 DBG_ASSERTWARNING( nRet, "Grafik kann nicht eingeswapt werden" ); 497 498 if( nRet ) 499 { 500 if( !nGrfSize.Width() && !nGrfSize.Height() ) 501 SetTwipSize( ::GetGraphicSizeTwip( aGrfObj.GetGraphic(), 0 ) ); 502 } 503 bInSwapIn = sal_False; 504 return nRet; 505 } 506 507 508 short SwGrfNode::SwapOut() 509 { 510 if( aGrfObj.GetType() != GRAPHIC_DEFAULT && 511 aGrfObj.GetType() != GRAPHIC_NONE && 512 !aGrfObj.IsSwappedOut() && !bInSwapIn ) 513 { 514 if( !refLink.Is() ) 515 { 516 // Das Swapping brauchen wir nur fuer Embedded Pictures 517 // Die Grafik wird in eine TempFile geschrieben, wenn 518 // sie frisch eingefuegt war, d.h. wenn es noch keinen 519 // Streamnamen im Storage gibt. 520 if( !HasStreamName() ) 521 if( !aGrfObj.SwapOut() ) 522 return 0; 523 } 524 // Geschriebene Grafiken oder Links werden jetzt weggeschmissen 525 return (short) aGrfObj.SwapOut( NULL ); 526 } 527 return 1; 528 } 529 530 531 sal_Bool SwGrfNode::GetFileFilterNms( String* pFileNm, String* pFilterNm ) const 532 { 533 sal_Bool bRet = sal_False; 534 if( refLink.Is() && refLink->GetLinkManager() ) 535 { 536 sal_uInt16 nType = refLink->GetObjType(); 537 if( OBJECT_CLIENT_GRF == nType ) 538 bRet = refLink->GetLinkManager()->GetDisplayNames( 539 refLink, 0, pFileNm, 0, pFilterNm ); 540 else if( OBJECT_CLIENT_DDE == nType && pFileNm && pFilterNm ) 541 { 542 String sApp, sTopic, sItem; 543 if( refLink->GetLinkManager()->GetDisplayNames( 544 refLink, &sApp, &sTopic, &sItem ) ) 545 { 546 ( *pFileNm = sApp ) += sfx2::cTokenSeperator; 547 ( *pFileNm += sTopic ) += sfx2::cTokenSeperator; 548 *pFileNm += sItem; 549 pFilterNm->AssignAscii( RTL_CONSTASCII_STRINGPARAM( "DDE" )); 550 bRet = sal_True; 551 } 552 } 553 } 554 return bRet; 555 } 556 557 558 // Eine Grafik Undo-faehig machen. Falls sie sich bereits in 559 // einem Storage befindet, muss sie geladen werden. 560 561 sal_Bool SwGrfNode::SavePersistentData() 562 { 563 if( refLink.Is() ) 564 { 565 ASSERT( !bInSwapIn, "SavePersistentData: stehe noch im SwapIn" ); 566 GetDoc()->GetLinkManager().Remove( refLink ); 567 return sal_True; 568 } 569 570 // Erst mal reinswappen, falls sie im Storage ist 571 if( HasStreamName() && !SwapIn() ) 572 return sal_False; 573 574 // --> OD 2005-04-19 #i44367# 575 // Do not delete graphic file in storage, because the graphic file could 576 // be referenced by other graphic nodes. 577 // Because it's hard to detect this case here and it would only fix 578 // one problem with shared graphic files - there are also problems, 579 // a certain graphic file is referenced by two independent graphic nodes, 580 // brush item or drawing objects, the stream isn't no longer removed here. 581 // To do this stuff correct, a reference counting on shared streams 582 // inside one document have to be implemented. 583 // Important note: see also fix for #i40014# 584 // if( HasStreamName() ) 585 // DelStreamName(); 586 // <-- 587 588 // Und in TempFile rausswappen 589 return (sal_Bool) SwapOut(); 590 } 591 592 593 sal_Bool SwGrfNode::RestorePersistentData() 594 { 595 if( refLink.Is() ) 596 { 597 IDocumentLinksAdministration* pIDLA = getIDocumentLinksAdministration(); 598 refLink->SetVisible( pIDLA->IsVisibleLinks() ); 599 pIDLA->GetLinkManager().InsertDDELink( refLink ); 600 if( getIDocumentLayoutAccess()->GetCurrentLayout() ) //swmod 080218 601 refLink->Update(); 602 } 603 return sal_True; 604 } 605 606 607 void SwGrfNode::InsertLink( const String& rGrfName, const String& rFltName ) 608 { 609 refLink = new SwBaseLink( sfx2::LINKUPDATE_ONCALL, FORMAT_GDIMETAFILE, this ); 610 611 IDocumentLinksAdministration* pIDLA = getIDocumentLinksAdministration(); 612 if( GetNodes().IsDocNodes() ) 613 { 614 refLink->SetVisible( pIDLA->IsVisibleLinks() ); 615 if( rFltName.EqualsAscii( "DDE" )) 616 { 617 sal_uInt16 nTmp = 0; 618 String sApp, sTopic, sItem; 619 sApp = rGrfName.GetToken( 0, sfx2::cTokenSeperator, nTmp ); 620 sTopic = rGrfName.GetToken( 0, sfx2::cTokenSeperator, nTmp ); 621 sItem = rGrfName.Copy( nTmp ); 622 pIDLA->GetLinkManager().InsertDDELink( refLink, 623 sApp, sTopic, sItem ); 624 } 625 else 626 { 627 sal_Bool bSync = rFltName.EqualsAscii( "SYNCHRON" ); 628 refLink->SetSynchron( bSync ); 629 refLink->SetContentType( SOT_FORMATSTR_ID_SVXB ); 630 631 pIDLA->GetLinkManager().InsertFileLink( *refLink, 632 OBJECT_CLIENT_GRF, rGrfName, 633 (!bSync && rFltName.Len() ? &rFltName : 0) ); 634 } 635 } 636 aGrfObj.SetLink( rGrfName ); 637 } 638 639 640 void SwGrfNode::ReleaseLink() 641 { 642 if( refLink.Is() ) 643 { 644 // erst die Grafik reinswappen! 645 // if( aGraphic.IsSwapOut() || !refLink->IsSynchron() ) 646 { 647 bInSwapIn = sal_True; 648 SwBaseLink* pLink = (SwBaseLink*)(::sfx2::SvBaseLink*) refLink; 649 //TODO pLink->setInputStream(getInputStream()); 650 pLink->SwapIn( sal_True, sal_True ); 651 bInSwapIn = sal_False; 652 } 653 getIDocumentLinksAdministration()->GetLinkManager().Remove( refLink ); 654 refLink.Clear(); 655 aGrfObj.SetLink(); 656 } 657 } 658 659 660 void SwGrfNode::SetTwipSize( const Size& rSz ) 661 { 662 nGrfSize = rSz; 663 if( IsScaleImageMap() && nGrfSize.Width() && nGrfSize.Height() ) 664 { 665 // Image-Map an Grafik-Groesse anpassen 666 ScaleImageMap(); 667 668 // Image-Map nicht noch einmal skalieren 669 SetScaleImageMap( sal_False ); 670 } 671 } 672 673 void SwGrfNode::ScaleImageMap() 674 { 675 if( !nGrfSize.Width() || !nGrfSize.Height() ) 676 return; 677 678 // dann die Image-Map skalieren 679 SwFrmFmt* pFmt = GetFlyFmt(); 680 681 if( !pFmt ) 682 return; 683 684 SwFmtURL aURL( pFmt->GetURL() ); 685 if ( !aURL.GetMap() ) 686 return; 687 688 sal_Bool bScale = sal_False; 689 Fraction aScaleX( 1, 1 ); 690 Fraction aScaleY( 1, 1 ); 691 692 const SwFmtFrmSize& rFrmSize = pFmt->GetFrmSize(); 693 const SvxBoxItem& rBox = pFmt->GetBox(); 694 695 if( !rFrmSize.GetWidthPercent() ) 696 { 697 SwTwips nWidth = rFrmSize.GetWidth(); 698 699 nWidth -= rBox.CalcLineSpace(BOX_LINE_LEFT) + 700 rBox.CalcLineSpace(BOX_LINE_RIGHT); 701 702 ASSERT( nWidth>0, "Gibt es 0 twip breite Grafiken!?" ); 703 704 if( nGrfSize.Width() != nWidth ) 705 { 706 aScaleX = Fraction( nGrfSize.Width(), nWidth ); 707 bScale = sal_True; 708 } 709 } 710 if( !rFrmSize.GetHeightPercent() ) 711 { 712 SwTwips nHeight = rFrmSize.GetHeight(); 713 714 nHeight -= rBox.CalcLineSpace(BOX_LINE_TOP) + 715 rBox.CalcLineSpace(BOX_LINE_BOTTOM); 716 717 ASSERT( nHeight>0, "Gibt es 0 twip hohe Grafiken!?" ); 718 719 if( nGrfSize.Height() != nHeight ) 720 { 721 aScaleY = Fraction( nGrfSize.Height(), nHeight ); 722 bScale = sal_True; 723 } 724 } 725 726 if( bScale ) 727 { 728 aURL.GetMap()->Scale( aScaleX, aScaleY ); 729 pFmt->SetFmtAttr( aURL ); 730 } 731 } 732 733 734 void SwGrfNode::DelStreamName() 735 { 736 if( HasStreamName() ) 737 { 738 // Dann die Grafik im Storage loeschen 739 uno::Reference < embed::XStorage > xDocStg = GetDoc()->GetDocStorage(); 740 if( xDocStg.is() ) 741 { 742 try 743 { 744 String aPicStgName, aStrmName; 745 _GetStreamStorageNames( aStrmName, aPicStgName ); 746 uno::Reference < embed::XStorage > refPics = xDocStg; 747 if ( aPicStgName.Len() ) 748 refPics = xDocStg->openStorageElement( aPicStgName, embed::ElementModes::READWRITE ); 749 refPics->removeElement( aStrmName ); 750 uno::Reference < embed::XTransactedObject > xTrans( refPics, uno::UNO_QUERY ); 751 if ( xTrans.is() ) 752 xTrans->commit(); 753 } 754 catch ( uno::Exception& ) 755 { 756 // --> OD 2005-04-25 #i48434# 757 ASSERT( false, "<SwGrfNode::DelStreamName()> - unhandled exception!" ); 758 // <-- 759 } 760 } 761 762 aGrfObj.SetUserData(); 763 } 764 } 765 766 /** helper method to get a substorage of the document storage for readonly access. 767 768 OD, MAV 2005-08-17 #i53025# 769 A substorage with the specified name will be opened readonly. If the provided 770 name is empty the root storage will be returned. 771 */ 772 uno::Reference< embed::XStorage > SwGrfNode::_GetDocSubstorageOrRoot( const String& aStgName ) const 773 { 774 uno::Reference < embed::XStorage > refStor = 775 const_cast<SwGrfNode*>(this)->GetDoc()->GetDocStorage(); 776 ASSERT( refStor.is(), "Kein Storage am Doc" ); 777 778 if ( aStgName.Len() ) 779 { 780 if( refStor.is() ) 781 return refStor->openStorageElement( aStgName, embed::ElementModes::READ ); 782 } 783 784 return refStor; 785 } 786 787 /** helper method to determine stream for the embedded graphic. 788 789 OD 2005-05-04 #i48434# 790 Important note: caller of this method has to handle the thrown exceptions 791 OD, MAV 2005-08-17 #i53025# 792 Storage, which should contain the stream of the embedded graphic, is 793 provided via parameter. Otherwise the returned stream will be closed 794 after the the method returns, because its parent stream is closed and deleted. 795 Proposed name of embedded graphic stream is also provided by parameter. 796 797 @author OD 798 */ 799 SvStream* SwGrfNode::_GetStreamForEmbedGrf( 800 const uno::Reference< embed::XStorage >& _refPics, 801 String& _aStrmName ) const 802 { 803 SvStream* pStrm( 0L ); 804 805 if( _refPics.is() && _aStrmName.Len() ) 806 { 807 // If stream doesn't exist in the storage, try access the graphic file by 808 // re-generating its name. 809 // A save action can have changed the filename of the embedded graphic, 810 // because a changed unique ID of the graphic is calculated. 811 // --> OD 2006-01-30 #b6364738# 812 // recursive calls of <GetUniqueID()> have to be avoided. 813 // Thus, use local static boolean to assure this. 814 static bool bInRegenerateStrmName( false ); 815 if ( !bInRegenerateStrmName && 816 ( !_refPics->hasByName( _aStrmName ) || 817 !_refPics->isStreamElement( _aStrmName ) ) ) 818 { 819 bInRegenerateStrmName = true; 820 xub_StrLen nExtPos = _aStrmName.Search( '.' ); 821 String aExtStr = _aStrmName.Copy( nExtPos ); 822 Graphic aGraphic( GetGrfObj().GetGraphic() ); 823 if ( aGraphic.GetType() != GRAPHIC_NONE ) 824 { 825 _aStrmName = String( GetGrfObj().GetUniqueID(), RTL_TEXTENCODING_ASCII_US ); 826 _aStrmName += aExtStr; 827 } 828 bInRegenerateStrmName = false; 829 } 830 // <-- 831 832 // assure that graphic file exist in the storage. 833 if ( _refPics->hasByName( _aStrmName ) && 834 _refPics->isStreamElement( _aStrmName ) ) 835 { 836 uno::Reference < io::XStream > refStrm = _refPics->openStreamElement( _aStrmName, embed::ElementModes::READ ); 837 pStrm = utl::UcbStreamHelper::CreateStream( refStrm ); 838 } 839 else 840 { 841 ASSERT( false, "<SwGrfNode::_GetStreamForEmbedGrf(..)> - embedded graphic file not found!" ); 842 } 843 } 844 845 return pStrm; 846 } 847 848 849 // --> OD 2005-08-17 #i53025# - stream couldn't be in a 3.1 - 5.2 storage any more. 850 // Thus, removing corresponding code. 851 void SwGrfNode::_GetStreamStorageNames( String& rStrmName, 852 String& rStorName ) const 853 { 854 rStorName.Erase(); 855 rStrmName.Erase(); 856 857 String aUserData( aGrfObj.GetUserData() ); 858 if( !aUserData.Len() ) 859 return; 860 861 String aProt( RTL_CONSTASCII_STRINGPARAM( "vnd.sun.star.Package:" ) ); 862 if( 0 == aUserData.CompareTo( aProt, aProt.Len() ) ) 863 { 864 // 6.0 (XML) Package 865 xub_StrLen nPos = aUserData.Search( '/' ); 866 if( STRING_NOTFOUND == nPos ) 867 { 868 rStrmName = aUserData.Copy( aProt.Len() ); 869 } 870 else 871 { 872 xub_StrLen nPathStart = aProt.Len(); 873 if( 0 == aUserData.CompareToAscii( "./", 2 ) ) 874 nPathStart += 2; 875 rStorName = aUserData.Copy( nPathStart, nPos-nPathStart ); 876 rStrmName = aUserData.Copy( nPos+1 ); 877 } 878 } 879 else 880 { 881 ASSERT( false, 882 "<SwGrfNode::_GetStreamStorageNames(..)> - unknown graphic URL type. Code for handling 3.1 - 5.2 storages has been deleted by issue i53025." ); 883 } 884 ASSERT( STRING_NOTFOUND == rStrmName.Search( '/' ), 885 "invalid graphic stream name" ); 886 } 887 // <-- 888 889 SwCntntNode* SwGrfNode::MakeCopy( SwDoc* pDoc, const SwNodeIndex& rIdx ) const 890 { 891 // kopiere die Formate in das andere Dokument: 892 SwGrfFmtColl* pColl = pDoc->CopyGrfColl( *GetGrfColl() ); 893 894 Graphic aTmpGrf; 895 SwBaseLink* pLink = (SwBaseLink*)(::sfx2::SvBaseLink*) refLink; 896 if( !pLink && HasStreamName() ) 897 { 898 // --> OD 2005-05-04 #i48434# - usage of new method <_GetStreamForEmbedGrf(..)> 899 try 900 { 901 // --> OD, MAV 2005-08-17 #i53025# - needed correction of new 902 // method <_GetStreamForEmbedGrf(..)> 903 // bool bGraphic(false); 904 // SvStream* pStrm = _GetStreamForEmbedGrf( bGraphic ); 905 String aStrmName, aPicStgName; 906 _GetStreamStorageNames( aStrmName, aPicStgName ); 907 uno::Reference < embed::XStorage > refPics = _GetDocSubstorageOrRoot( aPicStgName ); 908 SvStream* pStrm = _GetStreamForEmbedGrf( refPics, aStrmName ); 909 if ( pStrm ) 910 { 911 GraphicFilter::GetGraphicFilter()->ImportGraphic( aTmpGrf, String(), *pStrm ); 912 delete pStrm; 913 } 914 // <-- 915 } 916 catch ( uno::Exception& ) 917 { 918 // --> OD 2005-04-25 #i48434# 919 ASSERT( false, "<SwGrfNode::MakeCopy(..)> - unhandled exception!" ); 920 // <-- 921 } 922 // <-- 923 } 924 else 925 { 926 if( aGrfObj.IsSwappedOut() ) 927 const_cast<SwGrfNode*>(this)->SwapIn(); 928 aTmpGrf = aGrfObj.GetGraphic(); 929 } 930 931 const sfx2::LinkManager& rMgr = getIDocumentLinksAdministration()->GetLinkManager(); 932 String sFile, sFilter; 933 if( IsLinkedFile() ) 934 rMgr.GetDisplayNames( refLink, 0, &sFile, 0, &sFilter ); 935 else if( IsLinkedDDE() ) 936 { 937 String sTmp1, sTmp2; 938 rMgr.GetDisplayNames( refLink, &sTmp1, &sTmp2, &sFilter ); 939 sfx2::MakeLnkName( sFile, &sTmp1, sTmp2, sFilter ); 940 sFilter.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "DDE" )); 941 } 942 943 SwGrfNode* pGrfNd = pDoc->GetNodes().MakeGrfNode( rIdx, sFile, sFilter, 944 &aTmpGrf, pColl, 945 (SwAttrSet*)GetpSwAttrSet() ); 946 pGrfNd->SetTitle( GetTitle() ); 947 pGrfNd->SetDescription( GetDescription() ); 948 pGrfNd->SetContour( HasContour(), HasAutomaticContour() ); 949 return pGrfNd; 950 } 951 952 IMPL_LINK( SwGrfNode, SwapGraphic, GraphicObject*, pGrfObj ) 953 { 954 SvStream* pRet; 955 956 // #101174#: Keep graphic while in swap in. That's at least important 957 // when breaking links, because in this situation a reschedule call and 958 // a DataChanged call lead to a paint of the graphic. 959 if( pGrfObj->IsInSwapOut() && (IsSelected() || bInSwapIn) ) 960 pRet = GRFMGR_AUTOSWAPSTREAM_NONE; 961 else if( refLink.Is() ) 962 { 963 if( pGrfObj->IsInSwapIn() ) 964 { 965 // then make it by your self 966 if( !bInSwapIn ) 967 { 968 sal_Bool bIsModifyLocked = IsModifyLocked(); 969 LockModify(); 970 SwapIn( sal_False ); 971 if( !bIsModifyLocked ) 972 UnlockModify(); 973 } 974 pRet = GRFMGR_AUTOSWAPSTREAM_NONE; 975 } 976 else 977 pRet = GRFMGR_AUTOSWAPSTREAM_LINK; 978 } 979 else 980 { 981 pRet = GRFMGR_AUTOSWAPSTREAM_TEMP; 982 983 if( HasStreamName() ) 984 { 985 // --> OD 2005-05-04 #i48434# - usage of new method <_GetStreamForEmbedGrf(..)> 986 try 987 { 988 // --> OD, MAV 2005-08-17 #i53025# - needed correction of new 989 // method <_GetStreamForEmbedGrf(..)> 990 // bool bGraphic(false); 991 // SvStream* pStrm = _GetStreamForEmbedGrf( bGraphic ); 992 String aStrmName, aPicStgName; 993 _GetStreamStorageNames( aStrmName, aPicStgName ); 994 uno::Reference < embed::XStorage > refPics = _GetDocSubstorageOrRoot( aPicStgName ); 995 SvStream* pStrm = _GetStreamForEmbedGrf( refPics, aStrmName ); 996 if ( pStrm ) 997 { 998 if( pGrfObj->IsInSwapOut() ) 999 { 1000 pRet = GRFMGR_AUTOSWAPSTREAM_LINK; 1001 } 1002 else 1003 { 1004 ImportGraphic( *pStrm ); 1005 pRet = GRFMGR_AUTOSWAPSTREAM_LOADED; 1006 } 1007 delete pStrm; 1008 } 1009 // <-- 1010 } 1011 catch ( uno::Exception& ) 1012 { 1013 // --> OD 2005-04-25 #i48434# 1014 ASSERT( false, "<SwapGraphic> - unhandled exception!" ); 1015 // <-- 1016 } 1017 // <-- 1018 } 1019 } 1020 1021 return (long)pRet; 1022 } 1023 1024 1025 // alle QuickDraw-Bitmaps eines speziellen Docs loeschen 1026 void DelAllGrfCacheEntries( SwDoc* pDoc ) 1027 { 1028 if( pDoc ) 1029 { 1030 // alle Graphic-Links mit dem Namen aus dem Cache loeschen 1031 const sfx2::LinkManager& rLnkMgr = pDoc->GetLinkManager(); 1032 const ::sfx2::SvBaseLinks& rLnks = rLnkMgr.GetLinks(); 1033 SwGrfNode* pGrfNd; 1034 String sFileNm; 1035 for( sal_uInt16 n = rLnks.Count(); n; ) 1036 { 1037 ::sfx2::SvBaseLink* pLnk = &(*rLnks[ --n ]); 1038 if( pLnk && OBJECT_CLIENT_GRF == pLnk->GetObjType() && 1039 rLnkMgr.GetDisplayNames( pLnk, 0, &sFileNm ) && 1040 pLnk->ISA( SwBaseLink ) && 0 != ( pGrfNd = 1041 ((SwBaseLink*)pLnk)->GetCntntNode()->GetGrfNode()) ) 1042 { 1043 pGrfNd->GetGrfObj().ReleaseFromCache(); 1044 } 1045 } 1046 } 1047 } 1048 1049 // returns the with our graphic attributes filled Graphic-Attr-Structure 1050 GraphicAttr& SwGrfNode::GetGraphicAttr( GraphicAttr& rGA, 1051 const SwFrm* pFrm ) const 1052 { 1053 const SwAttrSet& rSet = GetSwAttrSet(); 1054 1055 rGA.SetDrawMode( (GraphicDrawMode)rSet.GetDrawModeGrf().GetValue() ); 1056 1057 const SwMirrorGrf & rMirror = rSet.GetMirrorGrf(); 1058 sal_uLong nMirror = BMP_MIRROR_NONE; 1059 if( rMirror.IsGrfToggle() && pFrm && !pFrm->FindPageFrm()->OnRightPage() ) 1060 { 1061 switch( rMirror.GetValue() ) 1062 { 1063 case RES_MIRROR_GRAPH_DONT: nMirror = BMP_MIRROR_HORZ; break; 1064 case RES_MIRROR_GRAPH_VERT: nMirror = BMP_MIRROR_NONE; break; 1065 case RES_MIRROR_GRAPH_HOR: nMirror = BMP_MIRROR_HORZ|BMP_MIRROR_VERT; 1066 break; 1067 default: nMirror = BMP_MIRROR_VERT; break; 1068 } 1069 } 1070 else 1071 switch( rMirror.GetValue() ) 1072 { 1073 case RES_MIRROR_GRAPH_BOTH: nMirror = BMP_MIRROR_HORZ|BMP_MIRROR_VERT; 1074 break; 1075 case RES_MIRROR_GRAPH_VERT: nMirror = BMP_MIRROR_HORZ; break; 1076 case RES_MIRROR_GRAPH_HOR: nMirror = BMP_MIRROR_VERT; break; 1077 } 1078 1079 rGA.SetMirrorFlags( nMirror ); 1080 1081 const SwCropGrf& rCrop = rSet.GetCropGrf(); 1082 rGA.SetCrop( TWIP_TO_MM100( rCrop.GetLeft() ), 1083 TWIP_TO_MM100( rCrop.GetTop() ), 1084 TWIP_TO_MM100( rCrop.GetRight() ), 1085 TWIP_TO_MM100( rCrop.GetBottom() )); 1086 1087 const SwRotationGrf& rRotation = rSet.GetRotationGrf(); 1088 rGA.SetRotation( rRotation.GetValue() ); 1089 1090 rGA.SetLuminance( rSet.GetLuminanceGrf().GetValue() ); 1091 rGA.SetContrast( rSet.GetContrastGrf().GetValue() ); 1092 rGA.SetChannelR( rSet.GetChannelRGrf().GetValue() ); 1093 rGA.SetChannelG( rSet.GetChannelGGrf().GetValue() ); 1094 rGA.SetChannelB( rSet.GetChannelBGrf().GetValue() ); 1095 rGA.SetGamma( rSet.GetGammaGrf().GetValue() ); 1096 rGA.SetInvert( rSet.GetInvertGrf().GetValue() ); 1097 1098 const sal_uInt16 nTrans = rSet.GetTransparencyGrf().GetValue(); 1099 rGA.SetTransparency( (sal_uInt8) FRound( 1100 Min( nTrans, (sal_uInt16) 100 ) * 2.55 ) ); 1101 1102 return rGA; 1103 } 1104 1105 sal_Bool SwGrfNode::IsTransparent() const 1106 { 1107 sal_Bool bRet = aGrfObj.IsTransparent(); 1108 if( !bRet ) // ask the attribut 1109 bRet = 0 != GetSwAttrSet().GetTransparencyGrf().GetValue(); 1110 1111 return bRet; 1112 } 1113 1114 1115 sal_Bool SwGrfNode::IsSelected() const 1116 { 1117 sal_Bool bRet = sal_False; 1118 const SwEditShell* pESh = GetDoc()->GetEditShell(); 1119 if( pESh ) 1120 { 1121 const SwNode* pN = this; 1122 const ViewShell* pV = pESh; 1123 do { 1124 if( pV->ISA( SwEditShell ) && pN == &((SwCrsrShell*)pV) 1125 ->GetCrsr()->GetPoint()->nNode.GetNode() ) 1126 { 1127 bRet = sal_True; 1128 break; 1129 } 1130 } 1131 while( pESh != ( pV = (ViewShell*)pV->GetNext() )); 1132 } 1133 return bRet; 1134 } 1135 1136 // --> OD 2006-12-22 #i73788# 1137 boost::weak_ptr< SwAsyncRetrieveInputStreamThreadConsumer > SwGrfNode::GetThreadConsumer() 1138 { 1139 return mpThreadConsumer; 1140 } 1141 1142 void SwGrfNode::TriggerAsyncRetrieveInputStream() 1143 { 1144 if ( !IsLinkedFile() ) 1145 { 1146 ASSERT( false, 1147 "<SwGrfNode::TriggerAsyncLoad()> - Method is misused. Method call is only valid for graphic nodes, which refer a linked graphic file" ); 1148 return; 1149 } 1150 1151 if ( mpThreadConsumer.get() == 0 ) 1152 { 1153 mpThreadConsumer.reset( new SwAsyncRetrieveInputStreamThreadConsumer( *this ) ); 1154 1155 String sGrfNm; 1156 refLink->GetLinkManager()->GetDisplayNames( refLink, 0, &sGrfNm, 0, 0 ); 1157 1158 mpThreadConsumer->CreateThread( sGrfNm ); 1159 } 1160 } 1161 1162 bool SwGrfNode::IsLinkedInputStreamReady() const 1163 { 1164 return mbLinkedInputStreamReady; 1165 } 1166 1167 void SwGrfNode::ApplyInputStream( 1168 com::sun::star::uno::Reference<com::sun::star::io::XInputStream> xInputStream, 1169 const sal_Bool bIsStreamReadOnly ) 1170 { 1171 if ( IsLinkedFile() ) 1172 { 1173 if ( xInputStream.is() ) 1174 { 1175 mxInputStream = xInputStream; 1176 mbIsStreamReadOnly = bIsStreamReadOnly; 1177 mbLinkedInputStreamReady = true; 1178 SwMsgPoolItem aMsgHint( RES_LINKED_GRAPHIC_STREAM_ARRIVED ); 1179 ModifyNotification( &aMsgHint, &aMsgHint ); 1180 } 1181 } 1182 } 1183 1184 void SwGrfNode::UpdateLinkWithInputStream() 1185 { 1186 // --> OD #i85105# 1187 // do not work on link, if a <SwapIn> has been triggered. 1188 if ( !bInSwapIn && IsLinkedFile() ) 1189 // <-- 1190 { 1191 GetLink()->setStreamToLoadFrom( mxInputStream, mbIsStreamReadOnly ); 1192 GetLink()->Update(); 1193 SwMsgPoolItem aMsgHint( RES_GRAPHIC_ARRIVED ); 1194 ModifyNotification( &aMsgHint, &aMsgHint ); 1195 1196 // --> OD 2008-06-18 #i88291# 1197 mxInputStream.clear(); 1198 GetLink()->clearStreamToLoadFrom(); 1199 // <-- 1200 mbLinkedInputStreamReady = false; 1201 mpThreadConsumer.reset(); 1202 } 1203 } 1204 // <-- 1205 1206 // --> OD 2008-07-21 #i90395# 1207 bool SwGrfNode::IsAsyncRetrieveInputStreamPossible() const 1208 { 1209 bool bRet = false; 1210 1211 if ( IsLinkedFile() ) 1212 { 1213 String sGrfNm; 1214 refLink->GetLinkManager()->GetDisplayNames( refLink, 0, &sGrfNm, 0, 0 ); 1215 String sProtocol( RTL_CONSTASCII_STRINGPARAM( "vnd.sun.star.pkg:" ) ); 1216 if ( sGrfNm.CompareTo( sProtocol, sProtocol.Len() ) != 0 ) 1217 { 1218 bRet = true; 1219 } 1220 } 1221 1222 return bRet; 1223 } 1224 // <-- 1225