/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
// take the Controls of the dialog into account for TabPages if ( pWindow->GetType() == WindowType::TABPAGE )
{
vcl::Window* pParent = pWindow->GetParent(); if (pParent && pParent->GetType() == WindowType::TABCONTROL )
pParent = pParent->GetParent();
//we can't change sizeable after the fact, so need to defer until we know and then do the init. void Dialog::ImplDeferredInit(vcl::Window* pParent, WinBits nBits)
{
ImplInitDialog(pParent, nBits | WB_BORDER, mnInitFlag);
}
bool Dialog::EventNotify( NotifyEvent& rNEvt )
{ // first call the base class due to Tab control bool bRet = SystemWindow::EventNotify( rNEvt ); if ( !bRet )
{ if ( rNEvt.GetType() == NotifyEventType::KEYINPUT )
{ const KeyEvent* pKEvt = rNEvt.GetKeyEvent();
vcl::KeyCode aKeyCode = pKEvt->GetKeyCode();
sal_uInt16 nKeyCode = aKeyCode.GetCode();
if ( (nKeyCode == KEY_ESCAPE) &&
((GetStyle() & WB_CLOSEABLE) || ImplGetCancelButton( this ) || ImplGetOKButton( this )) )
{ // #i89505# for the benefit of slightly mentally challenged implementations // like e.g. SfxModelessDialog which destroy themselves inside Close() // post this Close asynchronous so we can leave our key handler before // we get destroyed
PostUserEvent( LINK( this, Dialog, ImplAsyncCloseHdl ), nullptr, true); returntrue;
}
} elseif ( rNEvt.GetType() == NotifyEventType::GETFOCUS )
{ // make sure the dialog is still modal // changing focus between application frames may // have re-enabled input for our parent if( mbInExecute && mbModalMode )
{
ImplSetModalInputMode( false );
ImplSetModalInputMode( true );
// #93022# def-button might have changed after show if( !mnMousePositioned )
{
mnMousePositioned = 1;
ImplMouseAutoPos( this );
}
}
}
}
return bRet;
}
//What we really want here is something that gives the available width and //height of a users screen, taking away the space taken up the OS //taskbar, menus, etc.
Size bestmaxFrameSizeForScreenSize(const Size &rScreenSize)
{ #ifndef IOS
tools::Long w = rScreenSize.Width(); if (w <= 800)
w -= 15; elseif (w <= 1024)
w -= 65; else
w -= 115;
tools::Long h = rScreenSize.Height(); if (h <= 768)
h -= 50; else
h -= 100;
return Size(std::max<tools::Long>(w, 640 - 15),
std::max<tools::Long>(h, 480 - 50)); #else // Don't bother with ancient magic numbers of unclear relevance on non-desktop apps anyway. It // seems that at least currently in the iOS app, this function is called just once per dialog, // with a rScreenSize parameter of 1x1 (!). This would lead to always returning 625x430 which is // a bit random and needlessly small on an iPad at least. We want something that closely will // just fit on the display in either orientation.
// We ignore the rScreenSize as it will be the dummy 1x1 from iosinst.cxx (see "Totally wrong of course").
(void) rScreenSize;
if ( mpWindowImpl->mxWindowPeer.is() && IsCreatedWithToolkit() && !IsInExecute() ) returnfalse;
// If there's a cancel button with a custom handler, then always give it a chance to // handle Dialog::Close
PushButton* pCustomCancelButton;
PushButton* pCancelButton = dynamic_cast<PushButton*>(get_widget_for_response(RET_CANCEL)); if (!mbInClose && pCancelButton && pCancelButton->GetClickHdl().IsSet())
pCustomCancelButton = pCancelButton; else
pCustomCancelButton = nullptr;
mbInClose = true;
if (pCustomCancelButton)
{
pCustomCancelButton->Click(); if (xWindow->isDisposed()) returntrue;
mbInClose = false; returnfalse;
}
if ( !(GetStyle() & WB_CLOSEABLE) )
{ bool bRet = true;
PushButton* pButton = ImplGetCancelButton( this ); if ( pButton )
pButton->Click(); else
{
pButton = ImplGetOKButton( this ); if ( pButton )
pButton->Click(); else
bRet = false;
} if ( xWindow->isDisposed() ) returntrue; return bRet;
}
if (bModal)
{ if (bKitActive && !GetLOKNotifier())
{ if (auto pNotifier = mpDialogImpl->m_aInstallLOKNotifierHdl.Call(nullptr))
SetLOKNotifier(pNotifier); else
{ // gh#5908 handle pasting disallowed clipboard contents on iOS // When another app owns the current clipboard contents, pasting // will display a "allow or disallow" dialog. If the disallow // option is selected, the data from the UIPasteboard will be // garbage and we will find ourselves here. Since calling // SetLOKNotifier() with a nullptr aborts in an assert(), fix // the crash by failing gracefully.
// Also pNotifier may be nullptr when a dialog (e.g., "update // links?") is to be shown when loading a document. // Never crash in release builds (assume "cancel"), but allow // to see the not yet async / not properly set up dialogs in // debug builds.
assert(!"A dialog without a notifier: make me async / properly set up"); returnfalse;
}
} if (!async && Application::IsUseSystemEventLoop())
{ // As long as Application::Yield deliberately calls std::abort when trying to // synchronously execute modal dialogs, better cancel them here for now as a hack:
SAL_WARN( "vcl", "cancel synchronous execution of modal dialog " << ImplGetDialogText(this)); returnfalse;
}
switch ( Application::GetDialogCancelMode() )
{ case DialogCancelMode::Off: break; case DialogCancelMode::Silent: if (bModal && GetLOKNotifier())
{ // check if there's already some dialog being ::Execute()d constbool bDialogExecuting = std::any_of(pSVData->mpWinData->mpExecuteDialogs.begin(),
pSVData->mpWinData->mpExecuteDialogs.end(),
[](const Dialog* pDialog) { return pDialog->IsInSyncExecute();
}); if (!(bDialogExecuting && IsInSyncExecute())) break; else
SAL_WARN("lok.dialog", "Dialog \"" << ImplGetDialogText(this) << "\" is being synchronously executed over an existing synchronously executing dialog.");
}
if (o3tl::IsRunningUnitTest())
{ // helps starbasic unit tests show their errors
std::cerr << "Dialog \"" << ImplGetDialogText(this)
<< "\" cancelled in silent mode\n";
}
default: // default cannot happen case DialogCancelMode::Fatal:
std::abort();
}
#ifdef DBG_UTIL
vcl::Window* pParent = GetParent(); if ( pParent )
{
pParent = pParent->ImplGetFirstOverlapWindow(); if (pParent)
{
SAL_WARN_IF( !pParent->IsReallyVisible(), "vcl", "Dialog::StartExecuteModal() - Parent not visible" );
SAL_WARN_IF( !pParent->IsInputEnabled(), "vcl", "Dialog::StartExecuteModal() - Parent input disabled, use another parent to ensure modality!" );
SAL_WARN_IF( pParent->IsInModalMode(), "vcl", "Dialog::StartExecuteModal() - Parent already modally disabled, use another parent to ensure modality!" );
}
} #endif
// link all dialogs which are being executed
pSVData->mpWinData->mpExecuteDialogs.push_back(this);
// stop capturing, in order to have control over the dialog if (pSVData->mpWinData->mpTrackWin)
pSVData->mpWinData->mpTrackWin->EndTracking(TrackingEventFlags::Cancel); if (pSVData->mpWinData->mpCaptureWin)
pSVData->mpWinData->mpCaptureWin->ReleaseMouse();
EnableInput();
}
mbInExecute = true; // no real modality in LibreOfficeKit if (!bKitActive && bModal)
SetModalInputMode(true);
// FIXME: no layouting, workaround some clipping issues
ImplAdjustNWFSizes();
bool bTunnelingEnabled = mpDialogImpl->m_bLOKTunneling; if (comphelper::LibreOfficeKit::isActive() && bTunnelingEnabled)
{ if (const vcl::ILibreOfficeKitNotifier* pNotifier = GetLOKNotifier())
{ // Dialog boxes don't get the Resize call and they // can have invalid size at 'created' message above. // If there is no difference, the client should detect it and ignore us, // otherwise, this should make sure that the window has the correct size.
std::vector<vcl::LOKPayloadItem> aItems;
aItems.emplace_back("size", GetSizePixel().toString());
aItems.emplace_back("unique_id", this->get_id().toUtf8());
pNotifier->notifyWindow(GetLOKWindowId(), u"size_changed"_ustr, aItems);
}
}
// Yield util EndDialog is called or dialog gets destroyed // (the latter should not happen, but better safe than sorry while ( !xWindow->isDisposed() && mbInExecute && !Application::IsQuit() )
Application::Yield();
// remove dialog from the list of dialogs which are being executed
std::erase_if(rExecuteDialogs, [this](VclPtr<Dialog>& dialog){ return dialog.get() == this; });
}
if (comphelper::LibreOfficeKit::isActive())
{ if(const vcl::ILibreOfficeKitNotifier* pNotifier = GetLOKNotifier())
{ if (mpDialogImpl->m_bLOKTunneling)
pNotifier->notifyWindow(GetLOKWindowId(), u"close"_ustr);
ReleaseLOKNotifier();
}
}
if (bModal)
{
SetModalInputMode(false);
RemoveFromDlgList();
// set focus to previous modal dialog if it is modal for // the same frame parent (or NULL)
ImplSVData* pSVData = ImplGetSVData(); if (!pSVData->mpWinData->mpExecuteDialogs.empty())
{
VclPtr<Dialog> pPrevious = pSVData->mpWinData->mpExecuteDialogs.back();
if ( mpDialogImpl->mbStartedModal )
ImplEndExecuteModal();
if ( mpDialogImpl->maEndCtx.isSet() )
{ // We have a special case with async-dialogs that re-execute themselves. // In order to prevent overwriting state we need here, we need to extract // all the state we need before calling maEndDialogFn, because // maEndDialogFn might itself call StartExecuteAsync and store new state.
std::shared_ptr<weld::DialogController> xOwnerDialogController = std::move(mpDialogImpl->maEndCtx.mxOwnerDialogController);
std::shared_ptr<weld::Dialog> xOwnerSelf = std::move(mpDialogImpl->maEndCtx.mxOwnerSelf); auto xOwner = std::move(mpDialogImpl->maEndCtx.mxOwner); if ( mpDialogImpl->mbStartedModal )
{
mpDialogImpl->mbStartedModal = false;
mpDialogImpl->mnResult = -1;
}
mbInExecute = false; auto fn = std::move(mpDialogImpl->maEndCtx.maEndDialogFn);
// std::move leaves maEndDialogFn in a valid state with unspecified // value. For the SwSyncBtnDlg case gcc and msvc left maEndDialogFn // unset, but clang left maEndDialogFn at its original value, keeping // an extra reference to the DialogController in its lambda giving // an inconsistent lifecycle for the dialog. Force it to be unset.
mpDialogImpl->maEndCtx.maEndDialogFn = nullptr;
fn(nResult);
// Destroy ourselves, if we have a context with VclPtr owner, and // we have not been re-executed. if (!mpDialogImpl->maEndCtx.isSet())
xOwner.disposeAndClear();
xOwnerDialogController.reset();
xOwnerSelf.reset();
} else
{ if ( mpDialogImpl->mbStartedModal )
{
mpDialogImpl->mbStartedModal = false;
mpDialogImpl->mnResult = -1;
}
mbInExecute = false; // Destroy ourselves (if we have a context with VclPtr owner)
std::shared_ptr<weld::DialogController> xOwnerDialogController = std::move(mpDialogImpl->maEndCtx.mxOwnerDialogController);
std::shared_ptr<weld::Dialog> xOwnerSelf = std::move(mpDialogImpl->maEndCtx.mxOwnerSelf);
mpDialogImpl->maEndCtx.mxOwner.disposeAndClear();
}
}
// previously Execute()'d dialog - the one below the top-most one
VclPtr<Dialog> pPrevious;
ImplSVData* pSVData = ImplGetSVData(); auto& rExecuteDialogs = pSVData->mpWinData->mpExecuteDialogs; if (rExecuteDialogs.size() > 1)
pPrevious = rExecuteDialogs[rExecuteDialogs.size() - 2];
mbModalMode = bModal; if ( bModal )
{ // Disable the prev Modal Dialog, because our dialog must close at first, // before the other dialog can be closed (because the other dialog // is on stack since our dialog returns) if (pPrevious && !pPrevious->IsWindowOrChild(this, true))
pPrevious->EnableInput(false, this);
// determine next overlap dialog parent
vcl::Window* pParent = GetParent(); if ( pParent )
{ // #103716# dialogs should always be modal to the whole frame window // #115933# disable the whole frame hierarchy, useful if our parent // is a modeless dialog
mpDialogParent = pParent->mpWindowImpl->mpFrameWindow;
mpDialogParent->IncModalCount();
}
} else
{ if ( mpDialogParent )
{ // #115933# re-enable the whole frame hierarchy again (see above) // note that code in getfocus assures that we do not accidentally enable // windows that were disabled before
mpDialogParent->DecModalCount();
}
// Enable the prev Modal Dialog if (pPrevious && !pPrevious->IsWindowOrChild(this, true))
{
pPrevious->EnableInput(true, this);
// ensure continued modality of prev dialog // do not change modality counter
// #i119994# need find the last modal dialog before reactive it if (pPrevious->IsModalInputMode() || !pPrevious->IsWindowOrChild(this, true))
{
pPrevious->ImplSetModalInputMode(false);
pPrevious->ImplSetModalInputMode(true);
}
}
}
}
// find focus control, even if the dialog has focus if (!HasFocus() && pFirstOverlapWindow && pFirstOverlapWindow->mpWindowImpl)
{ // prefer a child window which had focus before
pFocusControl = ImplGetFirstOverlapWindow()->mpWindowImpl->mpLastFocusWindow; // find the control out of the dialog control if ( pFocusControl )
pFocusControl = ImplFindDlgCtrlWindow( pFocusControl );
} // no control had the focus before or the control is not // part of the tab-control, now give focus to the // first control in the tab-control if ( !pFocusControl ||
!(pFocusControl->GetStyle() & WB_TABSTOP) ||
!isVisibleInLayout(pFocusControl) ||
!isEnabledInLayout(pFocusControl) || !pFocusControl->IsInputEnabled() )
{
pFocusControl = ImplGetDlgWindow( 0, GetDlgWindowType::First );
}
IMPL_LINK(Dialog, ResponseHdl, Button*, pButton, void)
{ auto aFind = mpDialogImpl->maResponses.find(pButton); if (aFind == mpDialogImpl->maResponses.end()) return; short nResponse = aFind->second; if (nResponse == RET_HELP)
{
vcl::Window* pFocusWin = Application::GetFocusWindow(); if (!pFocusWin || comphelper::LibreOfficeKit::isActive())
pFocusWin = pButton;
HelpEvent aEvt(pFocusWin->GetPointerPosPixel(), HelpEventMode::CONTEXT);
pFocusWin->RequestHelp(aEvt); return;
}
EndDialog(nResponse);
}
void Dialog::add_button(PushButton* pButton, int response, bool bTransferOwnership)
{ if (bTransferOwnership)
mpDialogImpl->maOwnedButtons.push_back(pButton);
mpDialogImpl->maResponses[pButton] = response; switch (pButton->GetType())
{ case WindowType::PUSHBUTTON:
{ if (!pButton->GetClickHdl().IsSet())
pButton->SetClickHdl(LINK(this, Dialog, ResponseHdl)); break;
} //insist that the response ids match the default actions for those //widgets, and leave their default handlers in place case WindowType::OKBUTTON:
assert(mpDialogImpl->get_response(pButton) == RET_OK); break; case WindowType::CANCELBUTTON:
assert(mpDialogImpl->get_response(pButton) == RET_CANCEL || mpDialogImpl->get_response(pButton) == RET_CLOSE); break; case WindowType::HELPBUTTON:
assert(mpDialogImpl->get_response(pButton) == RET_HELP); break; default:
SAL_WARN("vcl.layout", "The type of widget " <<
pButton->GetHelpId() << " is currently not handled"); break;
}
}
void TopLevelWindowLocker::incBusy(const weld::Widget* pIgnore)
{ // lock any toplevel windows from being closed until busy is over
std::vector<VclPtr<vcl::Window>> aTopLevels;
vcl::Window *pTopWin = Application::GetFirstTopLevelWindow(); while (pTopWin)
{
vcl::Window* pCandidate = pTopWin; if (pCandidate->GetType() == WindowType::BORDERWINDOW)
pCandidate = pCandidate->GetWindow(GetWindowType::FirstChild); // tdf#125266 ignore HelpTextWindows if (pCandidate &&
pCandidate->GetType() != WindowType::HELPTEXTWINDOW &&
pCandidate->GetType() != WindowType::FLOATINGWINDOW &&
pCandidate->GetFrameWeld() != pIgnore)
{
aTopLevels.push_back(pCandidate);
}
pTopWin = Application::GetNextTopLevelWindow(pTopWin);
} for (auto& a : aTopLevels)
{
a->IncModalCount();
a->ImplGetFrame()->NotifyModalHierarchy(true);
}
m_xImpl->m_aBusyStack.push(aTopLevels);
}
void TopLevelWindowLocker::decBusy()
{ // unlock locked toplevel windows from being closed now busy is over for (auto& a : m_xImpl->m_aBusyStack.top())
{ if (a->isDisposed()) continue;
a->DecModalCount();
a->ImplGetFrame()->NotifyModalHierarchy(false);
}
m_xImpl->m_aBusyStack.pop();
}
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.