usingnamespace ::com::sun::star; usingnamespace ::com::sun::star::uno; usingnamespace ::com::sun::star::ucb; usingnamespace ::com::sun::star::frame; usingnamespace ::com::sun::star::lang; using ::com::sun::star::awt::XWindow; using ::com::sun::star::beans::PropertyValue; using ::com::sun::star::document::XViewDataSupplier; using ::com::sun::star::container::XIndexContainer;
namespace { /// Asks the user if editing a read-only document is really wanted. class SfxEditDocumentDialog : public weld::MessageDialogController
{ public:
SfxEditDocumentDialog(weld::Widget* pParent);
};
bool AskPasswordToModify_Impl( const uno::Reference< task::XInteractionHandler >& xHandler, const OUString& aPath, const std::shared_ptr<const SfxFilter>& pFilter, sal_uInt32 nPasswordHash, const uno::Sequence< beans::PropertyValue >& aInfo )
{ // TODO/LATER: In future the info should replace the direct hash completely bool bResult = ( !nPasswordHash && !aInfo.hasElements() );
SAL_WARN_IF( !(pFilter && ( pFilter->GetFilterFlags() & SfxFilterFlags::PASSWORDTOMODIFY )), "sfx.view", "PasswordToModify feature is active for a filter that does not support it!");
void SfxViewFrame::ExecReload_Impl( SfxRequest& rReq )
{
SfxObjectShell* pSh = GetObjectShell(); switch ( rReq.GetSlot() )
{ case SID_EDITDOC: case SID_READONLYDOC:
{ // Due to Double occupancy in toolboxes (with or without Ctrl), // it is also possible that the slot is enabled, but Ctrl-click // despite this is not! if( !pSh || !pSh->HasName() || !(pSh->Get_Impl()->nLoadedFlags & SfxLoadedFlags::MAINDOCUMENT )) break;
if (pSh->isEditDocLocked()) break;
// Only change read-only UI and remove info bar when we succeed struct ReadOnlyUIGuard
{
SfxViewFrame* m_pFrame;
SfxObjectShell* m_pSh;
SfxMedium* m_pMed = nullptr; bool m_bSetRO;
ReadOnlyUIGuard(SfxViewFrame* pFrame, SfxObjectShell* p_Sh)
: m_pFrame(pFrame), m_pSh(p_Sh), m_bSetRO(p_Sh->IsReadOnlyUI())
{}
~ReadOnlyUIGuard() COVERITY_NOEXCEPT_FALSE
{ if (m_bSetRO != m_pSh->IsReadOnlyUI())
{
m_pSh->SetReadOnlyUI(m_bSetRO); if (!m_bSetRO)
m_pFrame->RemoveInfoBar(u"readonly"); if (m_pMed)
{ boolconst isEnableSetModified(m_pSh->IsEnableSetModified());
m_pSh->EnableSetModified(false); // tdf#116066: DoSaveCompleted should be called after SetReadOnlyUI
m_pSh->DoSaveCompleted(m_pMed);
m_pSh->Broadcast(SfxHint(SfxHintId::ModeChanged));
m_pSh->EnableSetModified(isEnableSetModified);
}
}
}
} aReadOnlyUIGuard(this, pSh);
GetDispatcher()->Execute( SID_OPENDOC, SfxCallMode::ASYNCHRON, aSet ); return;
}
StreamMode nOpenMode; bool bNeedsReload = false; bool bPasswordEntered = false; if ( !pSh->IsReadOnly() )
{ // Save and reload Readonly if( pSh->IsModified() )
{ if ( pSh->PrepareClose() )
{ // the storing could let the medium be changed
pMed = pSh->GetMedium();
bNeedsReload = true;
} else
{
rReq.SetReturnValue( SfxBoolItem( rReq.GetSlot(), false ) ); return;
}
}
nOpenMode = SFX_STREAM_READONLY;
aReadOnlyUIGuard.m_bSetRO = true;
} else
{ if ( pSh->IsReadOnlyMedium()
&& ( pSh->GetModifyPasswordHash() || pSh->GetModifyPasswordInfo().hasElements() )
&& !pSh->IsModifyPasswordEntered() )
{ const OUString aDocumentName = INetURLObject( pMed->GetOrigURL() ).GetMainURL( INetURLObject::DecodeMechanism::WithCharset ); if( !AskPasswordToModify_Impl( pMed->GetInteractionHandler(), aDocumentName, pMed->GetFilter(), pSh->GetModifyPasswordHash(), pSh->GetModifyPasswordInfo() ) )
{ // this is a read-only document, if it has "Password to modify" // the user should enter password before he can edit the document
rReq.SetReturnValue( SfxBoolItem( rReq.GetSlot(), false ) ); return;
}
// if only the view was in the readonly mode then there is no need to do the reload if ( !pSh->IsReadOnlyMedium() )
{ // SetReadOnlyUI causes recomputation of window title, using // open mode among other things, so call SetOpenMode before // SetReadOnlyUI:
pMed->SetOpenMode( nOpenMode ); return;
}
}
if ( rReq.IsAPI() )
{ // Control through API if r/w or r/o const SfxBoolItem* pEditItem = rReq.GetArg<SfxBoolItem>(SID_EDITDOC); if ( pEditItem )
nOpenMode = pEditItem->GetValue() ? SFX_STREAM_READWRITE : SFX_STREAM_READONLY;
}
// -> tdf#82744 // the logic below is following: // if the document seems not to need to be reloaded // and the physical name is different to the logical one, // then on file system it can be checked that the copy is still newer than the original and no document reload is required. // Did some semplification to enhance readability of the 'if' expression // // when the 'http/https' protocol is active, the bool bPhysObjIsYounger relies upon the getlastmodified Property of a WebDAV resource. // Said property should be implemented, but sometimes it's not. // implemented. On this case the reload activated here will not work properly. // TODO: change the check age method for WebDAV to etag (entity-tag) property value, need some rethinking, since the // etag tells that the cache representation (e.g. in LO) is different from the one on the server, // but tells nothing about the age // Details at this link: http://tools.ietf.org/html/rfc4918#section-15, section 15.7 bool bIsWebDAV = aMedObj.isAnyKnownWebDAVScheme();
// tdf#118938 Reload the document when the user enters the editing password, // even if the physical name isn't different to the logical name. if ( ( !bNeedsReload && ( ( aMedObj.GetProtocol() == INetProtocol::File &&
( aMedObj.getFSysPath( FSysStyle::Detect ) != aPhysObj.getFSysPath( FSysStyle::Detect )
|| bPasswordEntered ) &&
!physObjIsOlder(aMedObj, aPhysObj))
|| (bIsWebDAV && !physObjIsOlder(aMedObj, aPhysObj))
|| ( pMed->IsRemote() && !bIsWebDAV ) ) )
|| pVersionItem ) // <- tdf#82744
{ bool bOK = false; bool bRetryIgnoringLock = false; bool bOpenTemplate = false;
std::optional<bool> aOrigROVal; if (!pVersionItem)
{ auto pRO = pMed->GetItemSet().GetItem<SfxBoolItem>(SID_DOC_READONLY, false); if (pRO)
aOrigROVal = pRO->GetValue();
} do {
LockFileEntry aLockData; if ( !pVersionItem )
{ if (bRetryIgnoringLock)
pMed->ResetError();
bool bHasStorage = pMed->HasStorage_Impl(); // switching edit mode could be possible without reload if ( bHasStorage && pMed->GetStorage() == pSh->GetStorage() )
{ // TODO/LATER: faster creation of copy if ( !pSh->ConnectTmpStorage_Impl( pMed->GetStorage(), pMed ) ) return;
}
pMed->CloseAndRelease();
pMed->SetOpenMode( nOpenMode ); // We need to clear the SID_DOC_READONLY item from the set, to allow // MediaDescriptor::impl_openStreamWithURL (called indirectly by // SfxMedium::CompleteReOpen) to properly fill input stream of the // descriptor, even when the file can't be open in read-write mode. // Only then can following call to SfxMedium::LockOrigFileOnDemand // return proper information about who has locked the file, to show // in the SfxQueryOpenAsTemplate box below; otherwise it exits right // after call to SfxMedium::GetMedium_Impl. This mimics what happens // when the file is opened initially, when filter detection code also // calls MediaDescriptor::impl_openStreamWithURL without the item set.
pMed->GetItemSet().ClearItem(SID_DOC_READONLY);
pMed->CompleteReOpen();
pMed->GetItemSet().Put(
SfxBoolItem(SID_DOC_READONLY, !(nOpenMode & StreamMode::WRITE))); if ( nOpenMode & StreamMode::WRITE )
{ auto eResult = pMed->LockOrigFileOnDemand( true, true, bRetryIgnoringLock, &aLockData);
bRetryIgnoringLock
= eResult == SfxMedium::LockFileResult::FailedLockFile;
}
// LockOrigFileOnDemand might set the readonly flag itself, it should be set back
pMed->GetItemSet().Put( SfxBoolItem( SID_DOC_READONLY, !( nOpenMode & StreamMode::WRITE ) ) );
if ( !pMed->GetErrorCode() )
bOK = true;
}
if( !bOK )
{ if (nOpenMode == SFX_STREAM_READWRITE && !rReq.IsAPI())
{ // css::sdbcx::User offering to open it as a template
SfxQueryOpenAsTemplate aBox(GetWindow().GetFrameWeld(),
bRetryIgnoringLock, aLockData);
short nUserAnswer = aBox.run();
bOpenTemplate = RET_YES == nUserAnswer; // Always reset this here to avoid infinite loop
bRetryIgnoringLock = RET_IGNORE == nUserAnswer; if (RET_CANCEL == nUserAnswer)
pMed->AddToCheckEditableWorkerList();
} else
bRetryIgnoringLock = false;
}
} while ( !bOK && bRetryIgnoringLock );
case SID_RELOAD:
{ // Due to Double occupancy in toolboxes (with or without Ctrl), // it is also possible that the slot is enabled, but Ctrl-click // despite this is not! if ( !pSh || !pSh->CanReload_Impl() ) break;
SfxApplication* pApp = SfxGetpApp(); const SfxBoolItem* pForceReloadItem = rReq.GetArg<SfxBoolItem>(SID_FORCERELOAD); if( pForceReloadItem && !pForceReloadItem->GetValue() &&
!pSh->GetMedium()->IsExpired() ) return; if( m_pImpl->bReloading || pSh->IsInModalMode() ) return;
// AutoLoad is prohibited if possible const SfxBoolItem* pAutoLoadItem = rReq.GetArg<SfxBoolItem>(SID_AUTOLOAD); if ( pAutoLoadItem && pAutoLoadItem->GetValue() &&
GetFrame().IsAutoLoadLocked_Impl() ) return;
SfxObjectShellLock xOldObj( pSh );
m_pImpl->bReloading = true; const SfxStringItem* pURLItem = rReq.GetArg<SfxStringItem>(SID_FILE_NAME); // Open as editable? bool bForEdit = !pSh->IsReadOnly();
// If possible ask the User bool bDo = GetViewShell()->PrepareClose(); const SfxBoolItem* pSilentItem = rReq.GetArg<SfxBoolItem>(SID_SILENT); if (getenv("SAL_NO_QUERYSAVE"))
bDo = true; elseif (bDo && GetFrame().DocIsModified_Impl() && !rReq.IsAPI()
&& (!pSilentItem || !pSilentItem->GetValue()))
{
std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(
GetWindow().GetFrameWeld(), VclMessageType::Question, VclButtonsType::YesNo,
SfxResId(STR_QUERY_LASTVERSION)));
bDo = RET_YES == xBox->run();
}
// Empty existing SfxMDIFrames for this Document // in native format or R/O, open it now for editing?
SfxObjectShellLock xNewObj;
// collect the views of the document // TODO: when UNO ViewFactories are available for SFX-based documents, the below code should // be UNOized, too typedef ::std::pair< Reference< XFrame >, SfxInterfaceId > ViewDescriptor;
::std::vector< ViewDescriptor > aViewFrames;
SfxViewFrame *pView = GetFirst( xOldObj ); while ( pView )
{
Reference< XFrame > xFrame( pView->GetFrame().GetFrameInterface() );
SAL_WARN_IF( !xFrame.is(), "sfx.view", "SfxViewFrame::ExecReload_Impl: no XFrame?!");
aViewFrames.emplace_back( xFrame, pView->GetCurViewId() );
// let the current security settings be checked again
pNewSet->Put( SfxUInt16Item( SID_MACROEXECMODE, document::MacroExecMode::USE_CONFIG ) );
if ( pSh->IsOriginallyReadOnlyMedium()
|| pSh->IsOriginallyLoadedReadOnlyMedium() ) // edit mode is switched or reload of readonly document
pNewSet->Put( SfxBoolItem( SID_DOC_READONLY, true ) ); else // Reload of file opened for writing
pNewSet->ClearItem( SID_DOC_READONLY );
}
// If a salvaged file is present, do not enclose the OrigURL // again, since the Template is invalid after reload. const SfxStringItem* pSalvageItem = SfxItemSet::GetItem<SfxStringItem>(&*pNewSet, SID_DOC_SALVAGE, false); if( pSalvageItem )
{
pNewSet->ClearItem( SID_DOC_SALVAGE );
}
#if HAVE_FEATURE_MULTIUSER_ENVIRONMENT // TODO/LATER: Temporary solution, the SfxMedium must know the original URL as aLogicName // SfxMedium::Transfer_Impl() will be forbidden then. if ( xOldObj->IsDocShared() )
pNewSet->Put( SfxStringItem( SID_FILE_NAME, xOldObj->GetSharedFileURL() ) ); #endif if ( pURLItem )
pNewSet->Put( SfxStringItem( SID_REFERER, pMedium->GetName() ) ); else
pNewSet->Put( SfxStringItem( SID_REFERER, OUString() ) );
if (!pInteractionItem)
{
Reference < task::XInteractionHandler2 > xHdl = task::InteractionHandler::createWithParent( ::comphelper::getProcessComponentContext(), nullptr ); if (xHdl.is())
pNewSet->Put( SfxUnoAnyItem(SID_INTERACTIONHANDLER,css::uno::Any(xHdl)) );
}
if (!pMacroExecItem)
pNewSet->Put( SfxUInt16Item(SID_MACROEXECMODE,css::document::MacroExecMode::USE_CONFIG) ); if (!pDocTemplateItem)
pNewSet->Put( SfxUInt16Item(SID_UPDATEDOCMODE,css::document::UpdateDocMode::ACCORDING_TO_CONFIG) );
xOldObj->SetModified( false ); // Do not cache the old Document! Is invalid when loading // another document.
#if HAVE_FEATURE_MULTIUSER_ENVIRONMENT if ( xNewObj->IsDocShared() )
{ // the file is shared but the closing can change the sharing control file
xOldObj->DoNotCleanShareControlFile();
} #endif // the Reload and Silent items were only temporary, remove them
xNewObj->GetMedium()->GetItemSet().ClearItem( SID_RELOAD );
xNewObj->GetMedium()->GetItemSet().ClearItem( SID_SILENT );
TransformItems( SID_OPENDOC, xNewObj->GetMedium()->GetItemSet(), aLoadArgs );
try
{ for (autoconst& viewFrame : aViewFrames)
{
LoadViewIntoFrame_Impl( *xNewObj, viewFrame.first, aLoadArgs, viewFrame.second, false);
}
aViewFrames.clear();
} catch( const Exception& )
{ // close the remaining frames // Don't catch exceptions herein, if this fails, then we're left in an indetermined state, and // crashing is better than trying to proceed for (autoconst& viewFrame : aViewFrames)
{
Reference< util::XCloseable > xClose( viewFrame.first, UNO_QUERY_THROW );
xClose->close( true );
}
aViewFrames.clear();
}
// tdf#126006 Calc needs to reload the notebookbar after closing the document if (!sReloadNotebookBar.isEmpty())
sfx2::SfxNotebookBar::ReloadNotebookBar(sReloadNotebookBar);
}
// Record as done
rReq.Done( true );
rReq.SetReturnValue(SfxBoolItem(rReq.GetSlot(), true)); return;
} else
{ // Record as not done
rReq.Done();
rReq.SetReturnValue(SfxBoolItem(rReq.GetSlot(), false));
m_pImpl->bReloading = false; return;
}
}
}
}
void SfxViewFrame::StateReload_Impl( SfxItemSet& rSet )
{
SfxObjectShell* pSh = GetObjectShell(); if ( !pSh )
{ // I'm just on reload and am yielding myself ... return;
}
case SID_RELOAD:
{ if ( !pSh->CanReload_Impl() || pSh->GetCreateMode() == SfxObjectCreateMode::EMBEDDED )
rSet.DisableItem(nWhich); else
{ // If any ChildFrame is reloadable, the slot is enabled, // so you can perform CTRL-Reload
rSet.Put( SfxBoolItem( nWhich, false));
}
break;
}
}
}
}
void SfxViewFrame::ExecHistory_Impl( SfxRequest &rReq )
{ // Is there an Undo-Manager on the top Shell?
SfxShell *pSh = GetDispatcher()->GetShell(0); if (!pSh) return;
SfxUndoManager* pShUndoMgr = pSh->GetUndoManager(); bool bOK = false; if ( pShUndoMgr )
{ switch ( rReq.GetSlot() )
{ case SID_CLEARHISTORY:
pShUndoMgr->Clear();
bOK = true; break;
case SID_UNDO:
pShUndoMgr->Undo();
GetBindings().InvalidateAll(false);
bOK = true; break;
case SID_REDO:
pShUndoMgr->Redo();
GetBindings().InvalidateAll(false);
bOK = true; break;
case SID_REPEAT: if ( pSh->GetRepeatTarget() )
pShUndoMgr->Repeat( *pSh->GetRepeatTarget() );
bOK = true; break;
}
} elseif ( GetViewShell() )
{ // The SW has its own undo in the View const SfxPoolItemHolder& rResult(GetViewShell()->ExecuteSlot(rReq)); if (rResult)
bOK = static_cast<const SfxBoolItem*>(rResult.getItem())->GetValue();
}
rReq.SetReturnValue( SfxBoolItem( rReq.GetSlot(), bOK ) );
rReq.Done();
}
void SfxViewFrame::StateHistory_Impl( SfxItemSet &rSet )
{ // Search for Undo-Manager
SfxShell *pSh = GetDispatcher()->GetShell(0); if ( !pSh ) // I'm just on reload and am yielding myself ... return;
SfxUndoManager *pShUndoMgr = pSh->GetUndoManager(); if ( !pShUndoMgr )
{ // The SW has its own undo in the View
SfxWhichIter aIter( rSet );
SfxViewShell *pViewSh = GetViewShell(); if( !pViewSh ) return; for ( sal_uInt16 nSID = aIter.FirstWhich(); nSID; nSID = aIter.NextWhich() )
pViewSh->GetSlotState( nSID, nullptr, &rSet ); return;
}
DBG_ASSERT( GetFrame().IsClosing_Impl() || !GetFrame().GetFrameInterface().is(), "ViewFrame closed too early!" );
// If no saving have been made up until now, then embedded Objects should // not be saved automatically anymore. if ( GetViewShell() )
GetViewShell()->DisconnectAllClients();
Broadcast( SfxHint( SfxHintId::Dying ) );
if (SfxViewFrame::Current() == this)
SfxViewFrame::SetViewFrame( nullptr );
// Since the Dispatcher is emptied, it can not be used in any reasonable // manner, thus it is better to let the dispatcher be.
GetDispatcher()->Lock(true); deletethis;
}
auto pInfoBar = AppendInfoBar(u"readonly"_ustr, u""_ustr,
SfxResId(bSignPDF ? STR_READONLY_PDF : STR_READONLY_DOCUMENT),
InfobarType::INFO); if (!pInfoBar) return;
if (bSignPDF)
{ // SID_SIGNPDF opened a read-write PDF // read-only for signing purposes.
weld::Button& rSignButton = pInfoBar->addButton(); if (bSignWithCert)
{
rSignButton.set_label(SfxResId(STR_READONLY_FINISH_SIGN));
} else
{
rSignButton.set_label(SfxResId(STR_READONLY_SIGN));
}
void SfxViewFrame::HandleSecurityInfobar(const OUString& sSecondaryMessage)
{ if (!HasInfoBarWithID(u"securitywarn"))
{ // new info bar if (!sSecondaryMessage.isEmpty())
{ auto pInfoBar = AppendInfoBar(u"securitywarn"_ustr, SfxResId(STR_HIDDENINFO_CONTAINS).replaceAll("\n\n", " "),
sSecondaryMessage, InfobarType::WARNING); if (!pInfoBar) return;
auto aResId = STR_CONTAINS_MACROS; if (SvtSecurityOptions::IsMacroDisabled())
aResId = STR_MACROS_DISABLED; elseif (pObjImpl->aMacroMode.hasUnsignedContentError())
aResId = STR_MACROS_DISABLED_CONTENT_UNSIGNED; elseif(pObjImpl->aMacroMode.hasInvalidSignaturesError())
aResId = STR_MACROS_DISABLED_SIGNATURE_INVALID; // The idea here is to always present an infobar is there was some // macro/script related potential hazard disabled in the source document auto pInfoBar = AppendInfoBar(u"macro"_ustr, SfxResId(STR_MACROS_DISABLED_TITLE),
SfxResId(aResId), InfobarType::WARNING); if (!pInfoBar) return;
// Then show buttons to help navigate to whatever that hazard is. Whether // that is included macros, so the user could delete them. Or events bound // to scripts which could be cleared. But there are likely other cases not // captured here, which could be added, various blocked features where its // likely still worth displaying the infobar that they have been disabled, // even if we don't currently provide a way to indicate what exactly those // are and how to remove them.
// No access to macro dialog when macros are disabled globally, so return // early without adding buttons to help explore what the macros/script/events // might be. if (SvtSecurityOptions::IsMacroDisabled()) return;
// what's the difference between pObjImpl->documentStorageHasMacros() and pObjImpl->aMacroMode.hasMacroLibrary() ? bool bHasDocumentMacros = pObjImpl->aMacroMode.hasMacroLibrary();
bool SfxApplication::IsHeadlessOrUITest()
{ if (Application::IsHeadlessModeEnabled()) returntrue;
bool bRet = o3tl::IsRunningUITest(); //uitest.uicheck fails when the dialog is open for (sal_uInt16 i = 0, nCount = Application::GetCommandLineParamCount(); i < nCount; ++i)
{ if (Application::GetCommandLineParam(i) == "--nologo")
{
bRet = true; break;
}
} return bRet;
}
bool SfxApplication::IsTipOfTheDayDue()
{ constbool bShowTipOfTheDay = officecfg::Office::Common::Misc::ShowTipOfTheDay::get(); if (!bShowTipOfTheDay) returnfalse;
// show tip-of-the-day dialog ? const sal_Int32 nLastTipOfTheDay = officecfg::Office::Common::Misc::LastTipOfTheDayShown::get(); const sal_Int32 nDay = std::chrono::duration_cast<std::chrono::hours>(t0).count()/24; // days since 1970-01-01 return nDay - nLastTipOfTheDay > 0; //only once per day
}
// we know only SfxEventHint or simple SfxHint if (rHint.GetId() == SfxHintId::ThisIsAnSfxEventHint)
{ // When the Document is loaded asynchronously, was the Dispatcher // set as ReadOnly, to what must be returned when the document itself // is not read only, and the loading is finished. switch (static_cast<const SfxEventHint&>(rHint).GetEventId())
{ case SfxEventHintId::ModifyChanged:
{
SfxBindings& rBind = GetBindings();
rBind.Invalidate( SID_DOC_MODIFIED );
rBind.Invalidate( SID_RELOAD );
rBind.Invalidate( SID_EDITDOC ); break;
}
case SfxEventHintId::OpenDoc: case SfxEventHintId::CreateDoc:
{ if ( !m_xObjSh.is() ) break;
if (vcl::CommandInfoProvider::GetModuleIdentifier(GetFrame().GetFrameInterface()) == "com.sun.star.text.TextDocument")
sfx2::SfxNotebookBar::ReloadNotebookBar(u"modules/swriter/ui/");
if (SfxClassificationHelper::IsClassified(m_xObjSh->getDocProperties()))
{ // Document has BAILS properties, display an infobar accordingly.
SfxClassificationHelper aHelper(m_xObjSh->getDocProperties());
aHelper.UpdateInfobar(*this);
}
// don't show Track Changes infobar, if Track Changes toolbar is visible if (aInfobarData.msId == "hiddentrackchanges")
{ if (auto xLayoutManager = getLayoutManager(GetFrame()))
{ if ( xLayoutManager->getElement(CHANGES_STR).is() )
{
aPendingInfobars.pop_back(); continue;
}
}
}
// Track Changes infobar: add a button to show/hide Track Changes functions // Hyphenation infobar: add a button to get more information // tdf#148913 limit VclPtr usage for these bool bTrackChanges = aInfobarData.msId == "hiddentrackchanges"; if ( bTrackChanges || aInfobarData.msId == "hyphenationmissing" )
{
VclPtr<SfxInfoBarWindow> pInfoBar =
AppendInfoBar(aInfobarData.msId, aInfobarData.msPrimaryMessage,
aInfobarData.msSecondaryMessage, aInfobarData.maInfobarType,
aInfobarData.mbShowCloseButton);
bIsInfobarShown = true;
// tdf#148913 don't extend this condition to keep it thread-safe if (pInfoBar)
{
weld::Button& rButton = pInfoBar->addButton();
rButton.set_label(SfxResId(bTrackChanges
? STR_TRACK_CHANGES_BUTTON
: STR_HYPHENATION_BUTTON)); if (bTrackChanges)
{
rButton.connect_clicked(LINK(this,
SfxViewFrame, HiddenTrackChangesHandler));
} else
{
rButton.connect_clicked(LINK(this,
SfxViewFrame, HyphenationMissingHandler));
}
}
} else
{
AppendInfoBar(aInfobarData.msId, aInfobarData.msPrimaryMessage,
aInfobarData.msSecondaryMessage, aInfobarData.maInfobarType,
aInfobarData.mbShowCloseButton);
bIsInfobarShown = true;
}
aPendingInfobars.pop_back();
}
#if !ENABLE_WASM_STRIP_PINGUSER if (!SfxApplication::IsHeadlessOrUITest()) //uitest.uicheck fails when the dialog is open
{ bool bIsWhatsNewShown = false; //suppress tipoftheday if whatsnew was shown
// show tip-of-the-day dialog if it due, but not if there is the impress modal template dialog // open where SdModule::ExecuteNewDocument will launch it instead when that dialog is dismissed if (SfxApplication::IsTipOfTheDayDue() && !IsInModalMode() && !bIsWhatsNewShown)
{ bool bIsBaseFormOpen = false;
constauto xCurrentFrame = GetFrame().GetFrameInterface(); constauto& xContext = comphelper::getProcessComponentContext(); constauto xModuleManager = css::frame::ModuleManager::create(xContext); switch (vcl::EnumContext::GetApplicationEnum(
vcl::CommandInfoProvider::GetModuleIdentifier(xCurrentFrame)))
{ case vcl::EnumContext::Application::WriterForm: case vcl::EnumContext::Application::WriterReport:
bIsBaseFormOpen = true; break; default: break;
} if (!bIsBaseFormOpen)
{ // tdf#127946 pass in argument for dialog parent
SfxUnoFrameItem aDocFrame(SID_FILLFRAME, xCurrentFrame);
GetDispatcher()->ExecuteList(SID_TIPOFTHEDAY, SfxCallMode::SLOT, {},
{ &aDocFrame });
}
}
// inform about the community involvement constauto t0 = std::chrono::system_clock::now().time_since_epoch(); const sal_Int64 nLastGetInvolvedShown = officecfg::Setup::Product::LastTimeGetInvolvedShown::get(); const sal_Int64 nNow = std::chrono::duration_cast<std::chrono::seconds>(t0).count(); const sal_Int64 nPeriodSec(60 * 60 * 24 * 180); // 180 days in seconds bool bUpdateLastTimeGetInvolvedShown = false;
// Only force and Dispatcher-Update, if it is done next // anyway, otherwise flickering or GPF is possible since // the Writer for example prefers in Resize perform some // actions which has a SetReadOnlyUI in Dispatcher as a // result!
if ( pDispat->IsUpdated_Impl() )
pDispat->Update_Impl(true);
}
case SfxHintId::DocumentRepair:
{
GetBindings().Invalidate( SID_DOC_REPAIR ); break;
}
case SfxHintId::Deinitializing:
{
vcl::Window* pFrameWin = GetWindow().GetFrameWindow(); if (pFrameWin && pFrameWin->GetLOKNotifier())
pFrameWin->ReleaseLOKNotifier();
GetFrame().DoClose(); break;
} case SfxHintId::Dying: // when the Object is being deleted, destroy the view too if ( m_xObjSh.is() )
ReleaseObjectShell_Impl(); else
GetFrame().DoClose(); break; default: break;
}
}
}
IMPL_LINK(SfxViewFrame, HiddenTrackChangesHandler, weld::Button&, rButton, void)
{ // enable Track Changes toolbar, if it is disabled. // Otherwise disable the toolbar, and close the infobar auto xLayoutManager = getLayoutManager(GetFrame()); if (!xLayoutManager) return;
if ( SfxViewFrame::Current() == this )
SfxViewFrame::SetViewFrame( nullptr );
ReleaseObjectShell_Impl();
if ( GetFrame().OwnsBindings_Impl() ) // The Bindings delete the Frame!
KillDispatcher_Impl();
m_pImpl->pWindow.disposeAndClear();
if ( GetFrame().GetCurrentViewFrame() == this )
GetFrame().SetCurrentViewFrame_Impl( nullptr );
// Unregister from the Frame List.
SfxApplication *pSfxApp = SfxApplication::Get(); if (pSfxApp)
{ auto &rFrames = pSfxApp->GetViewFrames_Impl(); auto it = std::find( rFrames.begin(), rFrames.end(), this );
rFrames.erase( it );
}
SfxViewFrame* SfxViewFrame::Current()
{
SfxApplication* pApp = SfxApplication::Get(); return pApp ? pApp->Get_Impl()->pViewFrame : nullptr;
}
// returns the first window of spec. type viewing the specified doc.
SfxViewFrame* SfxViewFrame::GetFirst
( const SfxObjectShell* pDoc, bool bOnlyIfVisible
)
{
SfxApplication *pSfxApp = SfxApplication::Get(); if (!pSfxApp) return nullptr;
// search for a SfxDocument of the specified type for (SfxViewFrame* pFrame : pSfxApp->GetViewFrames_Impl())
{ if ( ( !pDoc || pDoc == pFrame->GetObjectShell() )
&& ( !bOnlyIfVisible || pFrame->IsVisible() )
) return pFrame;
}
return nullptr;
}
// returns the next window of spec. type viewing the specified doc.
SfxViewFrame* SfxViewFrame::GetNext
( const SfxViewFrame& rPrev, const SfxObjectShell* pDoc, bool bOnlyIfVisible
)
{
SfxApplication *pSfxApp = SfxApplication::Get(); if (!pSfxApp) return nullptr;
auto &rFrames = pSfxApp->GetViewFrames_Impl();
// refind the specified predecessor
size_t nPos; for ( nPos = 0; nPos < rFrames.size(); ++nPos ) if ( rFrames[nPos] == &rPrev ) break;
// search for a Frame of the specified type for ( ++nPos; nPos < rFrames.size(); ++nPos )
{
SfxViewFrame *pFrame = rFrames[nPos]; if ( ( !pDoc || pDoc == pFrame->GetObjectShell() )
&& ( !bOnlyIfVisible || pFrame->IsVisible() )
) return pFrame;
} return nullptr;
}
vcl::Window *pWindow = &GetFrame().GetWindow(); if ( !bEnable )
m_pImpl->bWindowWasEnabled = pWindow->IsInputEnabled(); if ( !bEnable || m_pImpl->bWindowWasEnabled )
pWindow->EnableInput( bEnable );
// cursor and focus
SfxViewShell* pViewSh = GetViewShell(); if ( bEnable )
{ // show cursor if ( pViewSh )
pViewSh->ShowCursor();
} else
{ // hide cursor if ( pViewSh )
pViewSh->ShowCursor(false);
}
}
/* [Description]
ThismethodmakestheFrame-Windowvisibleandbeforetransmitsthe windowname.Inaddition,thedocumentisheld.Ingeneralonecannever showthewindowdirectly!
*/ void SfxViewFrame::Show()
{ // First lock the objectShell so that UpdateTitle() is valid: // IsVisible() == true (:#) if ( m_xObjSh.is() )
{
m_xObjSh->GetMedium()->GetItemSet().ClearItem( SID_HIDDEN ); if ( !m_pImpl->bObjLocked )
LockObjectShell_Impl();
// Adjust Doc-Shell title number, get unique view-no if ( 0 == m_pImpl->nDocViewNo )
{
GetDocNumber_Impl();
UpdateTitle();
}
} else
UpdateTitle();
// Display Frame-window, but only if the ViewFrame has no window of its // own or if it does not contain a Component
GetWindow().Show();
GetFrame().GetWindow().Show();
}
if ( !i_bHidden )
{ try
{ // if there is a backing component, use it
::framework::FrameListAnalyzer aAnalyzer( xDesktop, Reference< XFrame >(), FrameAnalyzerFlags::BackingComponent );
void SfxViewFrame::SaveCurrentViewData_Impl( const SfxInterfaceId i_nNewViewId )
{
SfxViewShell* pCurrentShell = GetViewShell();
ENSURE_OR_RETURN_VOID( pCurrentShell != nullptr, "SfxViewFrame::SaveCurrentViewData_Impl: no current view shell -> no current view data!" );
// determine the logical (API) view name const SfxObjectFactory& rDocFactory( pCurrentShell->GetObjectShell()->GetFactory() ); const sal_uInt16 nCurViewNo = rDocFactory.GetViewNo_Impl( GetCurViewId(), 0 ); const OUString sCurrentViewName = rDocFactory.GetViewFactory( nCurViewNo ).GetAPIViewName(); const sal_uInt16 nNewViewNo = rDocFactory.GetViewNo_Impl( i_nNewViewId, 0 ); const OUString sNewViewName = rDocFactory.GetViewFactory( nNewViewNo ).GetAPIViewName(); if ( sCurrentViewName.isEmpty() || sNewViewName.isEmpty() )
{ // can't say anything about the view, the respective application did not yet migrate its code to // named view factories => bail out
OSL_FAIL( "SfxViewFrame::SaveCurrentViewData_Impl: views without API names? Shouldn't happen anymore?" ); return;
}
SAL_WARN_IF(sNewViewName == sCurrentViewName, "sfx.view", "SfxViewFrame::SaveCurrentViewData_Impl: suspicious: new and old view name are identical!");
// save the view data only when we're moving from a non-print-preview to the print-preview view if ( sNewViewName != "PrintPreview" ) return;
// retrieve the view data from the view
Sequence< PropertyValue > aViewData;
pCurrentShell->WriteUserDataSequence( aViewData );
try
{ // retrieve view data (for *all* views) from the model const Reference< XController > xController( pCurrentShell->GetController(), UNO_SET_THROW ); const Reference< XViewDataSupplier > xViewDataSupplier( xController->getModel(), UNO_QUERY_THROW ); const Reference< XIndexContainer > xViewData( xViewDataSupplier->getViewData(), UNO_QUERY_THROW );
// look up the one view data item which corresponds to our current view, and remove it const sal_Int32 nCount = xViewData->getCount(); for ( sal_Int32 i=0; i<nCount; ++i )
{ const ::comphelper::NamedValueCollection aCurViewData( xViewData->getByIndex(i) ); const OUString sViewId( aCurViewData.getOrDefault( u"ViewId"_ustr, OUString() ) ); if ( sViewId.isEmpty() ) continue;
// then replace it with the most recent view data we just obtained
xViewData->insertByIndex( 0, Any( aViewData ) );
} catch( const Exception& )
{
DBG_UNHANDLED_EXCEPTION("sfx.view");
}
}
bool bIsIndex /* true 'nViewIdOrNo'isnoRegistration-Idinstead anIndexof<SfxViewFrame>in<SfxObjectShell>.
*/
)
{ try
{
ENSURE_OR_THROW( GetObjectShell() != nullptr, "not possible without a document" );
// if we already have a view shell, remove it
SfxViewShell* pOldSh = GetViewShell();
OSL_PRECOND( pOldSh, "SfxViewFrame::SwitchToViewShell_Impl: that's called *switch* (not for *initial-load*) for a reason" ); if ( pOldSh )
{ // ask whether it can be closed if ( !pOldSh->PrepareClose() ) returnfalse;
// remove sub shells from Dispatcher before switching to new ViewShell
PopShellAndSubShells_Impl( *pOldSh );
}
// ID of the new view
SfxObjectFactory& rDocFact = GetObjectShell()->GetFactory(); const SfxInterfaceId nViewId = ( bIsIndex || !nViewIdOrNo ) ? rDocFact.GetViewFactory( nViewIdOrNo ).GetOrdinal() : SfxInterfaceId(nViewIdOrNo);
// save the view data of the old view, so it can be restored later on (when needed)
SaveCurrentViewData_Impl( nViewId );
if (pOldSh)
pOldSh->SetDying();
// create and load new ViewShell
SfxViewShell* pNewSh = LoadViewIntoFrame_Impl(
*GetObjectShell(),
GetFrame().GetFrameInterface(),
Sequence< PropertyValue >(), // means "reuse existing model's args"
nViewId, false
);
// allow resize events to be processed
UnlockAdjustPosSizePixel();
if ( GetWindow().IsReallyVisible() )
DoAdjustPosSizePixel( pNewSh, Point(), GetWindow().GetOutputSizePixel(), false );
GetBindings().LEAVEREGISTRATIONS(); delete pOldSh;
} catch ( const css::uno::Exception& )
{ // the SfxCode is not able to cope with exceptions thrown while creating views // the code will crash in the stack unwinding procedure, so we shouldn't let exceptions go through here
DBG_UNHANDLED_EXCEPTION("sfx.view"); returnfalse;
}
case SID_VIEWSHELL0: case SID_VIEWSHELL1: case SID_VIEWSHELL2: case SID_VIEWSHELL3: case SID_VIEWSHELL4:
{ const sal_uInt16 nViewNo = rReq.GetSlot() - SID_VIEWSHELL0; bool bSuccess = SwitchToViewShell_Impl( nViewNo, true );
rReq.SetReturnValue( SfxBoolItem( 0, bSuccess ) ); break;
}
case SID_NEWWINDOW:
{ // Hack. at the moment a virtual Function if ( !GetViewShell()->NewWindowAllowed() )
{
OSL_FAIL( "You should have disabled the 'Window/New Window' slot!" ); return;
}
// Get ViewData of FrameSets recursively.
GetFrame().GetViewData_Impl();
SfxMedium* pMed = GetObjectShell()->GetMedium();
// do not open the new window hidden
pMed->GetItemSet().ClearItem( SID_HIDDEN );
// the view ID (optional arg. TODO: this is currently not supported in the slot definition ...) const SfxUInt16Item* pViewIdItem = rReq.GetArg<SfxUInt16Item>(SID_VIEW_ID); const SfxInterfaceId nViewId = pViewIdItem ? SfxInterfaceId(pViewIdItem->GetValue()) : GetCurViewId();
Reference < XFrame > xFrame; // the frame (optional arg. TODO: this is currently not supported in the slot definition ...) const SfxUnoFrameItem* pFrameItem = rReq.GetArg<SfxUnoFrameItem>(SID_FILLFRAME); if ( pFrameItem )
xFrame = pFrameItem->GetFrame();
for (i=0; i<c; ++i)
{ try
{
css::uno::Reference< css::frame::XFrame > xFrame;
xCont->getByIndex(i) >>= xFrame; if ( ! xFrame.is()) continue;
// a) do not count the help window if ( xFrame->getName() == "OFFICE_HELP_TASK" ) continue;
// b) count all other frames
++nOpenDocs;
} catch(const css::uno::Exception&) // An IndexOutOfBoundsException can happen in multithreaded // environments, where any other thread can change this // container !
{ continue; }
}
//seen in tdf#122598, no parent for subsequent dialog
SfxAllItemSet aSet(rPool);
aSet.Put(SfxUnoFrameItem(SID_FILLFRAME,
GetFrame().GetFrameInterface()));
aReq.SetInternalArgs_Impl(aSet);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.