Kaydet (Commit) 5b2794e2 authored tarafından Kohei Yoshida's avatar Kohei Yoshida

Ported dde-reconnect-on-load-*.diff from ooo-build.

Improve reliability of DDE connections between documents opened in LO.
With this change, LO tries to reconnect to a DDE server document upon
opening if that server document is being listened to by one of the
open documents.

Also, the old implementation would load a DDE server document
invisible, and would never close it when the user updates the link.
This had the consequence that when the user tries to open this
document while it's loaded hidden, it causes some weird focus issues,
and closing it and opening it again would disconnect the DDE
connection.  The new implementation closes the server document
immediately after the DDE link update is complete.

This change also fixes a bug in Calc where DDE link updates to cells
would fail when the formula syntax is set to something other than Calc
A1.
üst c360b9e3
......@@ -33,10 +33,18 @@
#include <tools/string.hxx>
#include <svl/svarray.hxx>
#include <vector>
class SfxObjectShell;
class Graphic;
class Size;
namespace com { namespace sun { namespace star {
namespace lang {
class XComponent;
}
}}}
namespace sfx2
{
// Damit der Link ueber den Status der zu ladenen Grafik informierten werden
......@@ -55,6 +63,10 @@ SV_DECL_PTRARR( SvLinkSources, SvLinkSourcePtr, 1, 1 )
class SFX2_DLLPUBLIC LinkManager
{
typedef ::std::vector< ::com::sun::star::uno::Reference< ::com::sun::star::lang::XComponent > >
CompVector;
CompVector maCachedComps;
SvBaseLinks aLinkTbl;
SvLinkSources aServerTbl;
......@@ -74,6 +86,16 @@ public:
LinkManager( SfxObjectShell * pCacheCont );
~LinkManager();
/**
* Insert a component loaded during link update, which needs to be closed
* when the update is complete.
*
* @param xComp component loaded during link update.
*/
void InsertCachedComp(const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XComponent >& xComp);
void CloseCachedComps();
SfxObjectShell* GetPersist() const { return pPersist; }
void SetPersist( SfxObjectShell * p ) { pPersist = p; }
......@@ -100,6 +122,17 @@ public:
// falls am Link schon alles eingestellt ist !
BOOL InsertFileLink( sfx2::SvBaseLink& );
void ReconnectDdeLink(SfxObjectShell& rServer);
/**
* Reconnect the server document shell to a DDE link object.
*
* @param rPath path to the server document
* @param rServer server document shell instance
* @param rLink link object of the client document
*/
void LinkServerShell(const ::rtl::OUString& rPath, SfxObjectShell& rServer, ::sfx2::SvBaseLink& rLink) const;
// erfrage die Strings fuer den Dialog
BOOL GetDisplayNames( const SvBaseLink *,
String* pType,
......
......@@ -127,6 +127,9 @@ namespace com { namespace sun { namespace star {
namespace document {
class XDocumentProperties;
}
namespace lang {
class XComponent;
}
} } }
typedef sal_uInt32 SfxObjectShellFlags;
......@@ -524,6 +527,9 @@ public:
const String& rMimeType,
const ::com::sun::star::uno::Any & rValue );
virtual ::sfx2::SvLinkSource* DdeCreateLinkSource( const String& rItem );
virtual void ReconnectDdeLink(SfxObjectShell& rServer);
static void ReconnectDdeLinks(SfxObjectShell& rServer);
// Contents
virtual SfxStyleSheetBasePool* GetStyleSheetPool();
......@@ -631,6 +637,9 @@ public:
static SfxObjectShell* CreateObject( const String& rServiceName, SfxObjectCreateMode = SFX_CREATE_MODE_STANDARD );
static SfxObjectShell* CreateObjectByFactoryName( const String& rURL, SfxObjectCreateMode = SFX_CREATE_MODE_STANDARD );
static SfxObjectShell* CreateAndLoadObject( const SfxItemSet& rSet, SfxFrame* pFrame=0 );
static ::com::sun::star::uno::Reference< ::com::sun::star::lang::XComponent >
CreateAndLoadComponent( const SfxItemSet& rSet, SfxFrame* pFrame = NULL );
static SfxObjectShell* GetShellFromComponent( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XComponent >& xComp );
static String GetServiceNameFromFactory( const String& rFact );
BOOL IsInPlaceActive();
BOOL IsUIActive();
......
......@@ -362,6 +362,7 @@
#define SID_OPENCOPY (SID_SFX_START + 674)
#define SID_SOURCEVIEW (SID_SFX_START + 675)
#define SID_DOC_STARTPRESENTATION (SID_SFX_START + 695)
#define SID_DDE_RECONNECT_ONLOAD (SID_SFX_START + 696)
#define SID_PLUGFRAMEARG (SID_SFX_START + 666)
#define SID_NEWWINDOWFOREDIT (SID_SFX_START + 667)
......
......@@ -365,6 +365,23 @@ long SfxObjectShell::DdeSetData
return 0;
}
void SfxObjectShell::ReconnectDdeLink(SfxObjectShell& /*rServer*/)
{
}
void SfxObjectShell::ReconnectDdeLinks(SfxObjectShell& rServer)
{
TypeId aType = TYPE(SfxObjectShell);
SfxObjectShell* p = GetFirst(&aType, false);
while (p)
{
if (&rServer != p)
p->ReconnectDdeLink(rServer);
p = GetNext(*p, &aType, false);
}
}
//========================================================================
long SfxViewFrame::DdeExecute
......
......@@ -149,6 +149,7 @@ static char const sOpenNewView[] = "OpenNewView";
static char const sViewId[] = "ViewId";
static char const sPluginMode[] = "PluginMode";
static char const sReadOnly[] = "ReadOnly";
static char const sDdeReconnect[] = "DDEReconnect";
static char const sStartPresentation[] = "StartPresentation";
static char const sFrameName[] = "FrameName";
static char const sMediaType[] = "MediaType";
......@@ -608,6 +609,14 @@ void TransformParameters( sal_uInt16 nSlotId, const ::com::sun::star::uno::Seque
if (bOK)
rSet.Put( SfxBoolItem( SID_DOC_READONLY, bVal ) );
}
else if ( aName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM(sDdeReconnect)) )
{
sal_Bool bVal = sal_True;
sal_Bool bOK = (rProp.Value >>= bVal);
DBG_ASSERT( bOK, "invalid type for DDEReconnect" );
if (bOK)
rSet.Put( SfxBoolItem( SID_DDE_RECONNECT_ONLOAD, bVal ) );
}
else if ( aName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM(sStartPresentation)) )
{
sal_Bool bVal = sal_False;
......@@ -1007,6 +1016,8 @@ void TransformItems( sal_uInt16 nSlotId, const SfxItemSet& rSet, ::com::sun::sta
nAdditional++;
if ( rSet.GetItemState( SID_DOC_READONLY ) == SFX_ITEM_SET )
nAdditional++;
if ( rSet.GetItemState( SID_DDE_RECONNECT_ONLOAD ) == SFX_ITEM_SET )
nAdditional++;
if ( rSet.GetItemState( SID_DOC_STARTPRESENTATION ) == SFX_ITEM_SET )
nAdditional++;
if ( rSet.GetItemState( SID_SELECTION ) == SFX_ITEM_SET )
......@@ -1423,6 +1434,11 @@ void TransformItems( sal_uInt16 nSlotId, const SfxItemSet& rSet, ::com::sun::sta
pValue[nActProp].Name = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(sReadOnly));
pValue[nActProp++].Value <<= ( ((SfxBoolItem*)pItem)->GetValue() );
}
if ( rSet.GetItemState( SID_DDE_RECONNECT_ONLOAD, sal_False, &pItem ) == SFX_ITEM_SET )
{
pValue[nActProp].Name = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(sDdeReconnect));
pValue[nActProp++].Value <<= ( ((SfxBoolItem*)pItem)->GetValue() );
}
if ( rSet.GetItemState( SID_DOC_STARTPRESENTATION, sal_False, &pItem ) == SFX_ITEM_SET )
{
pValue[nActProp].Name = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(sStartPresentation));
......
......@@ -55,6 +55,16 @@
#define _SVSTDARR_STRINGSDTOR
#include <svl/svstdarr.hxx>
#include <com/sun/star/lang/XComponent.hpp>
#include <com/sun/star/util/XCloseable.hpp>
using ::com::sun::star::uno::UNO_QUERY;
using ::com::sun::star::uno::Reference;
using ::com::sun::star::lang::XComponent;
using ::com::sun::star::util::XCloseable;
using ::rtl::OUString;
using ::rtl::OUStringBuffer;
namespace sfx2
{
......@@ -89,6 +99,24 @@ LinkManager::~LinkManager()
}
}
void LinkManager::InsertCachedComp(const Reference<XComponent>& xComp)
{
maCachedComps.push_back(xComp);
}
void LinkManager::CloseCachedComps()
{
CompVector::iterator itr = maCachedComps.begin(), itrEnd = maCachedComps.end();
for (; itr != itrEnd; ++itr)
{
Reference<XCloseable> xCloseable(*itr, UNO_QUERY);
if (!xCloseable.is())
continue;
xCloseable->close(true);
}
maCachedComps.clear();
}
/************************************************************************
|* LinkManager::Remove()
......@@ -329,6 +357,7 @@ void LinkManager::UpdateAllLinks(
pLink->Update();
}
CloseCachedComps();
}
/************************************************************************
......@@ -387,6 +416,56 @@ void MakeLnkName( String& rName, const String* pType, const String& rFile,
((rName += cTokenSeperator ) += *pFilter).EraseLeadingChars().EraseTrailingChars();
}
void LinkManager::ReconnectDdeLink(SfxObjectShell& rServer)
{
SfxMedium* pMed = rServer.GetMedium();
if (!pMed)
return;
const ::sfx2::SvBaseLinks& rLinks = GetLinks();
sal_uInt16 n = rLinks.Count();
for (sal_uInt16 i = 0; i < n; ++i)
{
::sfx2::SvBaseLink* p = *rLinks[i];
String aType, aFile, aLink, aFilter;
if (!GetDisplayNames(p, &aType, &aFile, &aLink, &aFilter))
continue;
if (!aType.EqualsAscii("soffice"))
// DDE connections between OOo apps are always named 'soffice'.
continue;
String aTmp;
OUString aURL = aFile;
if (utl::LocalFileHelper::ConvertPhysicalNameToURL(aFile, aTmp))
aURL = aTmp;
if (!aURL.equalsIgnoreAsciiCase(pMed->GetName()))
// This DDE link is not associated with this server shell... Skip it.
continue;
if (!aLink.Len())
continue;
LinkServerShell(aLink, rServer, *p);
}
}
void LinkManager::LinkServerShell(const OUString& rPath, SfxObjectShell& rServer, ::sfx2::SvBaseLink& rLink) const
{
::sfx2::SvLinkSource* pSrvSrc = rServer.DdeCreateLinkSource(rPath);
if (pSrvSrc)
{
::com::sun::star::datatransfer::DataFlavor aFl;
SotExchange::GetFormatDataFlavor(rLink.GetContentType(), aFl);
rLink.SetObj(pSrvSrc);
pSrvSrc->AddDataAdvise(
&rLink, aFl.MimeType,
sfx2::LINKUPDATE_ONCALL == rLink.GetUpdateMode() ? ADVISEMODE_ONLYONCE : 0);
}
}
BOOL LinkManager::InsertFileLink( sfx2::SvBaseLink& rLink,
USHORT nFileType,
const String& rFileNm,
......@@ -511,9 +590,8 @@ BOOL SvxInternalLink::Connect( sfx2::SvBaseLink* pLink )
SfxObjectShell* pFndShell = 0;
USHORT nUpdateMode = com::sun::star::document::UpdateDocMode::NO_UPDATE;
String sTopic, sItem, sReferer;
if( pLink->GetLinkManager() &&
pLink->GetLinkManager()->GetDisplayNames( pLink, 0, &sTopic, &sItem )
&& sTopic.Len() )
LinkManager* pLinkMgr = pLink->GetLinkManager();
if (pLinkMgr && pLinkMgr->GetDisplayNames(pLink, 0, &sTopic, &sItem) && sTopic.Len())
{
// erstmal nur ueber die DocumentShells laufen und die mit dem
// Namen heraussuchen:
......@@ -528,7 +606,7 @@ BOOL SvxInternalLink::Connect( sfx2::SvBaseLink* pLink )
TypeId aType( TYPE(SfxObjectShell) );
BOOL bFirst = TRUE;
SfxObjectShell* pShell = pLink->GetLinkManager()->GetPersist();
SfxObjectShell* pShell = pLinkMgr->GetPersist();
if( pShell && pShell->GetMedium() )
{
sReferer = pShell->GetMedium()->GetBaseURL();
......@@ -578,7 +656,23 @@ BOOL SvxInternalLink::Connect( sfx2::SvBaseLink* pLink )
if( !sTopic.Len() )
return FALSE;
if( !pFndShell )
if (pFndShell)
{
sfx2::SvLinkSource* pNewSrc = pFndShell->DdeCreateLinkSource( sItem );
if( pNewSrc )
{
::com::sun::star::datatransfer::DataFlavor aFl;
SotExchange::GetFormatDataFlavor( pLink->GetContentType(), aFl );
pLink->SetObj( pNewSrc );
pNewSrc->AddDataAdvise( pLink, aFl.MimeType,
sfx2::LINKUPDATE_ONCALL == pLink->GetUpdateMode()
? ADVISEMODE_ONLYONCE
: 0 );
return true;
}
}
else
{
// dann versuche die Datei zu laden:
INetURLObject aURL( sTopic );
......@@ -593,7 +687,11 @@ BOOL SvxInternalLink::Connect( sfx2::SvBaseLink* pLink )
SfxStringItem aTarget( SID_TARGETNAME, String::CreateFromAscii("_blank") );
SfxStringItem aReferer( SID_REFERER, sReferer );
SfxUInt16Item aUpdate( SID_UPDATEDOCMODE, nUpdateMode );
SfxBoolItem aReadOnly(SID_DOC_READONLY, TRUE);
SfxBoolItem aReadOnly(SID_DOC_READONLY, false);
// Disable automatic re-connection to avoid this link instance
// being destroyed at re-connection.
SfxBoolItem aDdeConnect(SID_DDE_RECONNECT_ONLOAD, false);
// #i14200# (DDE-link crashes wordprocessor)
SfxAllItemSet aArgs( SFX_APP()->GetPool() );
......@@ -604,29 +702,19 @@ BOOL SvxInternalLink::Connect( sfx2::SvBaseLink* pLink )
aArgs.Put(aName);
aArgs.Put(aUpdate);
aArgs.Put(aReadOnly);
pFndShell = SfxObjectShell::CreateAndLoadObject( aArgs );
aArgs.Put(aDdeConnect);
Reference<XComponent> xComp = SfxObjectShell::CreateAndLoadComponent(aArgs);
pFndShell = SfxObjectShell::GetShellFromComponent(xComp);
if (xComp.is() && pFndShell)
{
pLinkMgr->InsertCachedComp(xComp);
pLinkMgr->LinkServerShell(sItem, *pFndShell, *pLink);
return true;
}
}
}
BOOL bRet = FALSE;
if( pFndShell )
{
sfx2::SvLinkSource* pNewSrc = pFndShell->DdeCreateLinkSource( sItem );
if( pNewSrc )
{
bRet = TRUE;
::com::sun::star::datatransfer::DataFlavor aFl;
SotExchange::GetFormatDataFlavor( pLink->GetContentType(), aFl );
pLink->SetObj( pNewSrc );
pNewSrc->AddDataAdvise( pLink, aFl.MimeType,
sfx2::LINKUPDATE_ONCALL == pLink->GetUpdateMode()
? ADVISEMODE_ONLYONCE
: 0 );
}
}
return bRet;
return false;
}
......
......@@ -794,6 +794,16 @@ sal_Bool SfxObjectShell::DoLoad( SfxMedium *pMed )
}
}
const SfxBoolItem* pDdeReconnectItem = static_cast<const SfxBoolItem*>(
SfxRequest::GetItem(pMedium->GetItemSet(), SID_DDE_RECONNECT_ONLOAD, false, TYPE(SfxBoolItem)));
bool bReconnectDde = true; // by default, we try to auto-connect DDE connections.
if (pDdeReconnectItem)
bReconnectDde = pDdeReconnectItem->GetValue();
if (bReconnectDde)
ReconnectDdeLinks(*this);
#if 0
if ( pMedium->HasStorage_Impl() )
{
......
......@@ -1021,6 +1021,12 @@ SfxObjectShell* SfxObjectShell::CreateObject( const String& rServiceName, SfxObj
}
SfxObjectShell* SfxObjectShell::CreateAndLoadObject( const SfxItemSet& rSet, SfxFrame* pFrame )
{
Reference<lang::XComponent> xComp = CreateAndLoadComponent(rSet, pFrame);
return GetShellFromComponent(xComp);
}
Reference<lang::XComponent> SfxObjectShell::CreateAndLoadComponent( const SfxItemSet& rSet, SfxFrame* pFrame )
{
uno::Sequence < beans::PropertyValue > aProps;
TransformItems( SID_OPENDOC, rSet, aProps );
......@@ -1042,20 +1048,31 @@ SfxObjectShell* SfxObjectShell::CreateAndLoadObject( const SfxItemSet& rSet, Sfx
xLoader = uno::Reference < frame::XComponentLoader >( comphelper::getProcessServiceFactory()->createInstance(
::rtl::OUString::createFromAscii("com.sun.star.frame.Desktop") ), uno::UNO_QUERY );
uno::Reference < lang::XUnoTunnel > xObj;
Reference <lang::XComponent> xComp;
try
{
xObj = uno::Reference< lang::XUnoTunnel >( xLoader->loadComponentFromURL( aURL, aTarget, 0, aProps ), uno::UNO_QUERY );
xComp = xLoader->loadComponentFromURL(aURL, aTarget, 0, aProps);
}
catch( uno::Exception& )
{}
if ( xObj.is() )
return xComp;
}
SfxObjectShell* SfxObjectShell::GetShellFromComponent( const Reference<lang::XComponent>& xComp )
{
try
{
Reference<lang::XUnoTunnel> xTunnel(xComp, UNO_QUERY_THROW);
Sequence <sal_Int8> aSeq( SvGlobalName( SFX_GLOBAL_CLASSID ).GetByteSequence() );
sal_Int64 nHandle = xTunnel->getSomething( aSeq );
if (!nHandle)
return NULL;
return reinterpret_cast< SfxObjectShell* >(sal::static_int_cast< sal_IntPtr >( nHandle ));
}
catch (const Exception&)
{
::com::sun::star::uno::Sequence < sal_Int8 > aSeq( SvGlobalName( SFX_GLOBAL_CLASSID ).GetByteSequence() );
sal_Int64 nHandle = xObj->getSomething( aSeq );
if ( nHandle )
return reinterpret_cast< SfxObjectShell* >(sal::static_int_cast< sal_IntPtr >( nHandle ));
}
return NULL;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment