class SdOutliner::Implementation
{ public: /** The original edit mode directly after switching to a different view mode.Usedforrestoringtheeditmodewhenleavingthatviewmode again.
*/
EditMode meOriginalEditMode;
Implementation();
~Implementation();
/** Return the OutlinerView that was provided by the last call to ProvideOutlinerView()(orNULLwhentherewasnosuchcall.)
*/
OutlinerView* GetOutlinerView() { return mpOutlineView;}
/** Provide in the member mpOutlineView an instance of OutlinerView that iseithertakenfromtheViewShell,whenitisanOutlineViewShell, oriscreated.WhenanOutlinerViewalreadyexistsitisinitialized.
*/ void ProvideOutlinerView (
Outliner& rOutliner, const std::shared_ptr<sd::ViewShell>& rpViewShell,
vcl::Window* pWindow);
/** This method is called when the OutlinerView is no longer used.
*/ void ReleaseOutlinerView();
private: /** Flag that specifies whether we own the outline view pointed to by <member>mpOutlineView</member>andthushaveto deleteitin<member>EndSpelling()</member>.
*/ bool mbOwnOutlineView;
/** The outline view used for searching and spelling. If searching or spellcheckinganoutlineviewthisdatamemberpointstothatview. Forallotherviewsaninstanceiscreated.The <member>mbOwnOutlineView</member>distinguishesbetweenbothcases.
*/
OutlinerView* mpOutlineView;
std::shared_ptr<sd::ViewShell> pViewShell (mpWeakViewShell.lock()); if (pViewShell)
{
mbStringFound = false;
// Supposed that we are not located at the very beginning/end of // the document then there may be a match in the document // prior/after the current position.
mbMatchMayExist = true;
/** Free all resources acquired during the search/spell check. After a spellcheckthestartpositionisrestoredhere.
*/ void SdOutliner::EndSpelling()
{ // Keep old view shell alive until we release the outliner view.
std::shared_ptr<sd::ViewShell> pViewShell (mpWeakViewShell.lock());
std::shared_ptr<sd::ViewShell> pOldViewShell (pViewShell);
// When in <member>PrepareSpelling()</member> a new outline view has // been created then delete it here. bool bViewIsDrawViewShell(dynamic_cast< const sd::DrawViewShell *>( pViewShell.get() )); if (bViewIsDrawViewShell)
{
SetStatusEventHdl(Link<EditStatus&,void>());
mpView = pViewShell->GetView();
mpView->UnmarkAllObj (mpView->GetSdrPageView());
mpView->SdrEndTextEdit(); // Make FuSelection the current function.
pViewShell->GetDispatcher()->Execute(
SID_OBJECT_SELECT,
SfxCallMode::SYNCHRON | SfxCallMode::RECORD);
// Remove and, if previously created by us, delete the outline // view.
OutlinerView* pOutlinerView = getOutlinerView(); if (pOutlinerView != nullptr)
{
RemoveView(pOutlinerView);
mpImpl->ReleaseOutlinerView();
}
SetUpdateLayout(true);
}
// Before clearing the modify flag use it as a hint that // changes were done at SpellCheck if(IsModified())
{ if(auto pOutlineView = dynamic_cast<sd::OutlineView *>( mpView ))
pOutlineView->PrepareClose(); if(!mrDrawDocument.IsChanged())
mrDrawDocument.SetChanged();
}
// Now clear the modify flag to have a specified state of // Outliner
ClearModifyFlag();
// When spell checking then restore the start position. if (meMode==SPELL || meMode==TEXT_CONVERSION)
RestoreStartPosition ();
DetectChange(); // Iterate over sentences and text shapes until a sentence with a // spelling error has been found. If no such sentence can be // found the loop is left through a break. // It is the responsibility of the sd outliner object to correctly // iterate over all text shapes, i.e. switch between views, wrap // around at the end of the document, stop when all text shapes // have been examined exactly once. bool bFoundNextSentence = false; while ( ! bFoundNextSentence)
{
OutlinerView* pOutlinerView = GetView(0); if (pOutlinerView != nullptr)
{
ESelection aCurrentSelection (pOutlinerView->GetSelection()); if ( ! mbMatchMayExist
&& maStartSelection < aCurrentSelection)
EndOfSearch();
// Advance to the next sentence.
bFoundNextSentence = SpellSentence( pOutlinerView->GetEditView(), aResult);
}
// When no sentence with spelling errors has been found in the // currently selected text shape or there is no selected text // shape then advance to the next text shape. if ( ! bFoundNextSentence) if ( ! SpellNextDocument()) // All text objects have been processed so exit the // loop and return an empty portions list. break;
}
return aResult;
}
/** Go to next match.
*/ bool SdOutliner::StartSearchAndReplace (const SvxSearchItem* pSearchItem)
{ bool bEndOfSearch = true;
// clear the search toolbar entry
SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::Empty);
mrDrawDocument.GetDocSh()->SetWaitCursor( true );
// Since REPLACE is really a replaceAndSearchNext instead of a searchAndReplace, // make sure that the search portion has not changed since the last FIND. if (!mbPrepareSpellingPending && mpSearchItem
&& pSearchItem->GetCommand() == SvxSearchCmd::REPLACE
&& !mpSearchItem->equalsIgnoring(*pSearchItem, /*bIgnoreReplace=*/true, /*bIgnoreCommand=*/true))
{
EndSpelling();
mbPrepareSpellingPending = true;
}
if (mbPrepareSpellingPending)
PrepareSpelling();
sd::ViewShellBase* pBase = getViewShellBase(); // Determine whether we have to abort the search. This is necessary // when the main view shell does not support searching. bool bAbort = false; if (pBase != nullptr)
{
std::shared_ptr<sd::ViewShell> pShell (pBase->GetMainViewShell());
SetViewShell(pShell); if (pShell == nullptr)
bAbort = true; else switch (pShell->GetShellType())
{ case sd::ViewShell::ST_DRAW: case sd::ViewShell::ST_IMPRESS: case sd::ViewShell::ST_NOTES: case sd::ViewShell::ST_HANDOUT: case sd::ViewShell::ST_OUTLINE:
bAbort = false; break; default:
bAbort = true; break;
}
}
// In case we are searching in an outline view then first remove the // current selection and place cursor at its start or end. if( nullptr != dynamic_cast< const sd::OutlineViewShell *>( pViewShell.get() ))
{
ESelection aSelection = getOutlinerView()->GetSelection (); if (mbDirectionIsForward)
{
aSelection.CollapseToStart();
} else
{
aSelection.CollapseToEnd();
}
getOutlinerView()->SetSelection (aSelection);
}
// When not beginning the search at the beginning of the search area // then there may be matches before the current position.
mbMatchMayExist = (maObjectIterator!=sd::outliner::OutlinerContainer(this).begin());
} elseif (bOldDirectionIsForward != mbDirectionIsForward)
{ // Requested iteration direction has changed. Turn around the iterator.
maObjectIterator.Reverse(); if (bIsAtEnd)
{ // The iterator has pointed to end(), which after the search // direction is reversed, becomes begin().
maObjectIterator = sd::outliner::OutlinerContainer(this).begin();
} else
{ // The iterator has pointed to the object one ahead/before the current // one. Now move it to the one before/ahead the current one.
++maObjectIterator; if (maObjectIterator != sd::outliner::OutlinerContainer(this).end())
{
++maObjectIterator;
}
}
mbMatchMayExist = true;
}
// Initialize the last valid position with where the search starts so // that it always points to a valid position.
maLastValidPosition = *sd::outliner::OutlinerContainer(this).current();
}
std::vector<sd::SearchSelection> aSelections; if( nullptr != dynamic_cast< const sd::OutlineViewShell *>( pViewShell.get() ))
{ // Put the cursor to the beginning/end of the outliner.
getOutlinerView()->SetSelection (GetSearchStartPosition ());
// The outliner does all the work for us when we are in this mode.
SearchAndReplaceOnce();
} elseif( nullptr != dynamic_cast< const sd::DrawViewShell *>( pViewShell.get() ))
{ // Disable selection change notifications during search all.
SfxViewShell& rSfxViewShell = pViewShell->GetViewShellBase();
rSfxViewShell.setTiledSearching(true);
comphelper::ScopeGuard aGuard([&rSfxViewShell]()
{
rSfxViewShell.setTiledSearching(false);
});
// Go to beginning/end of document.
maObjectIterator = sd::outliner::OutlinerContainer(this).begin(); // Switch to the first object which contains the search string.
ProvideNextTextObject(); if( !mbStringFound )
{
RestoreStartPosition ();
mnStartPageIndex = sal_uInt16(-1); returntrue;
} // Reset the iterator back to the beginning
maObjectIterator = sd::outliner::OutlinerContainer(this).begin();
// Search/replace until the end of the document is reached. bool bFoundMatch; do
{
bFoundMatch = ! SearchAndReplaceOnce(&aSelections); if (mpSearchItem->GetCommand() == SvxSearchCmd::FIND_ALL && comphelper::LibreOfficeKit::isActive() && bFoundMatch && aSelections.size() == 1)
{ // Without this, RememberStartPosition() will think it already has a remembered position.
mnStartPageIndex = sal_uInt16(-1);
RememberStartPosition();
// So when RestoreStartPosition() restores the first match, then spellchecker doesn't kill the selection.
bRet = false;
}
} while (bFoundMatch);
if (mpSearchItem->GetCommand() == SvxSearchCmd::FIND_ALL && comphelper::LibreOfficeKit::isActive() && !bRet)
{ // Find-all, tiled rendering and we have at least one match.
OString aPayload = OString::number(mnStartPageIndex);
SfxViewShell& rSfxViewShell = pViewShell->GetViewShellBase();
rSfxViewShell.libreOfficeKitViewCallback(LOK_CALLBACK_SET_PART, aPayload);
// Emit a selection callback here: // 1) The original one is no longer valid, as we there was a SET_PART in between // 2) The underlying editeng will only talk about the first match till // it doesn't support multi-selection.
std::vector<OString> aRectangles; for (const sd::SearchSelection& rSelection : aSelections)
{ if (rSelection.m_nPage == mnStartPageIndex)
aRectangles.push_back(rSelection.m_aRectangles);
}
OString sRectangles = comphelper::string::join("; ", aRectangles);
rSfxViewShell.libreOfficeKitViewCallback(LOK_CALLBACK_TEXT_SELECTION, sRectangles);
}
// convert to twips if in 100thmm (seems as if LibreOfficeKit is based on twips?). Do this // here where we have the only place needing this, *not* in ImpEditView::GetSelectionRectangles // which makes that method unusable for others if (pOutlinerView->GetWindow() && MapUnit::Map100thMM == pOutlinerView->GetWindow()->GetMapMode().GetMapUnit())
{ for (tools::Rectangle& rRectangle : aLogicRects)
{
rRectangle = o3tl::convert(rRectangle, o3tl::Length::mm100, o3tl::Length::twip);
}
}
}
if (!pSelections)
{ // notify LibreOfficeKit about changed page
OString aPayload = OString::number(maCurrentPosition.mnPageIndex);
SfxViewShell& rSfxViewShell = pViewShell->GetViewShellBase();
rSfxViewShell.libreOfficeKitViewCallback(LOK_CALLBACK_SET_PART, aPayload);
// also about search result selections
boost::property_tree::ptree aTree;
aTree.put("searchString", mpSearchItem->GetSearchString().toUtf8().getStr());
aTree.put("highlightAll", false);
if (!getOutlinerView() || !GetEditEngine().HasView(&getOutlinerView()->GetEditView()))
{
std::shared_ptr<sd::DrawViewShell> pDrawViewShell (
std::dynamic_pointer_cast<sd::DrawViewShell>(pViewShell));
// Perhaps the user switched to a different page/slide between searches. // If so, reset the starting search position to the current slide like DetectChange does if (pDrawViewShell && pDrawViewShell->GetCurPagePos() != maCurrentPosition.mnPageIndex)
maObjectIterator = sd::outliner::OutlinerContainer(this).current();
std::vector<basegfx::B2DRectangle> aSubSelections;
basegfx::B2DRectangle aSubSelection = getPDFSelection(rVectorGraphicSearchContext.mpVectorGraphicSearch, mpObj); if (!aSubSelection.isEmpty())
aSubSelections.push_back(aSubSelection);
mpView->MarkObj(mpObj, pPageView, false, false, std::move(aSubSelections));
} else
{
rVectorGraphicSearchContext.reset();
}
} else
{ // When replacing we first check if there is a selection // indicating a match. If there is then replace it. The // following call to StartSearchAndReplace will then search for // the next match. if (meMode == SEARCH && mpSearchItem->GetCommand() == SvxSearchCmd::REPLACE)
{ if (getOutlinerView()->GetSelection().HasRange())
getOutlinerView()->StartSearchAndReplace(*mpSearchItem);
}
// Search for the next match. if (mpSearchItem->GetCommand() != SvxSearchCmd::REPLACE_ALL)
{
nMatchCount = getOutlinerView()->StartSearchAndReplace(*mpSearchItem); if (nMatchCount && maCurrentPosition.meEditMode == EditMode::Page
&& maCurrentPosition.mePageKind == PageKind::Notes)
{ if(auto pNotesPaneOutliner = lclGetNotesPaneOutliner(pViewShell))
{
pNotesPaneOutliner->SetSelection(getOutlinerView()->GetSelection());
}
}
}
}
// Go to the next text object when there have been no matches in // the current object or the whole object has already been // processed. if (nMatchCount==0 || mpSearchItem->GetCommand()==SvxSearchCmd::REPLACE_ALL)
{
ProvideNextTextObject ();
if (!mbEndOfSearch && !rVectorGraphicSearchContext.mbCurrentIsVectorGraphic)
{ // Remember the current position as the last one with a // text object.
maLastValidPosition = maCurrentPosition;
// Now that the mbEndOfSearch flag guards this block the // following assertion and return should not be // necessary anymore.
DBG_ASSERT(GetEditEngine().HasView(&getOutlinerView()->GetEditView() ), "SearchAndReplace without valid view!" ); if ( ! GetEditEngine().HasView( &getOutlinerView()->GetEditView() )
&& maCurrentPosition.mePageKind != PageKind::Notes )
{
mrDrawDocument.GetDocSh()->SetWaitCursor( false ); returntrue;
}
if (meMode == SEARCH)
{ auto nMatch = getOutlinerView()->StartSearchAndReplace(*mpSearchItem); if (nMatch && maCurrentPosition.meEditMode == EditMode::Page
&& maCurrentPosition.mePageKind == PageKind::Notes)
{ if(auto pNotesPaneOutliner = lclGetNotesPaneOutliner(pViewShell))
{
pNotesPaneOutliner->SetSelection(getOutlinerView()->GetSelection());
}
}
}
}
}
} elseif (nullptr != dynamic_cast<const sd::OutlineViewShell*>(pViewShell.get()))
{
mrDrawDocument.GetDocSh()->SetWaitCursor(false); // The following loop is executed more than once only when a // wrap around search is done. while (true)
{ int nResult = getOutlinerView()->StartSearchAndReplace(*mpSearchItem); if (nResult == 0)
{ if (HandleFailedSearch ())
{
getOutlinerView()->SetSelection (GetSearchStartPosition ()); continue;
}
} else
mbStringFound = true; break;
}
}
}
/** Try to detect whether the document or the view (shell) has changed since thelasttime<member>StartSearchAndReplace()</member>hasbeencalled.
*/ void SdOutliner::DetectChange()
{
sd::outliner::IteratorPosition aPosition (maCurrentPosition);
// Detect whether the view has been switched from the outside. if( bViewChanged )
{ // Either the edit mode or the page kind has changed.
SetStatusEventHdl(Link<EditStatus&,void>());
// Detect change of the set of selected objects. If their number has // changed start again with the first selected object. elseif (DetectSelectionChange())
{
HandleChangedSelection ();
maObjectIterator = sd::outliner::OutlinerContainer(this).current();
}
// Detect change of page count. Restart search at first/last page in // that case. elseif (aPosition.meEditMode == EditMode::Page
&& mrDrawDocument.GetSdPageCount(aPosition.mePageKind) != mnPageCount)
{ // The number of pages has changed.
mnPageCount = mrDrawDocument.GetSdPageCount(aPosition.mePageKind);
maObjectIterator = sd::outliner::OutlinerContainer(this).current();
} elseif (aPosition.meEditMode == EditMode::MasterPage
&& mrDrawDocument.GetSdPageCount(aPosition.mePageKind) != mnPageCount)
{ // The number of master pages has changed.
mnPageCount = mrDrawDocument.GetSdPageCount(aPosition.mePageKind);
maObjectIterator = sd::outliner::OutlinerContainer(this).current();
}
}
// If mpObj is NULL then we have not yet found our first match. // Detecting a change makes no sense. if (mpObj != nullptr)
{ const size_t nMarkCount = mpView ? mpView->GetMarkedObjectList().GetMarkCount() : 0; switch (nMarkCount)
{ case0: // The selection has changed when previously there have been // selected objects.
bSelectionHasChanged = mbRestrictSearchToSelection; break; case1: // Check if the only selected object is not the one that we // had selected. if (mpView != nullptr)
{
SdrMark* pMark = mpView->GetMarkedObjectList().GetMark(0); if (pMark != nullptr)
bSelectionHasChanged = (mpObj != pMark->GetMarkedSdrObj ());
} break; default: // We had selected exactly one object.
bSelectionHasChanged = true; break;
}
}
if (mpView != nullptr)
{
mpStartEditedObject = mpView->GetTextEditObject(); if (mpStartEditedObject != nullptr)
{ // Try to retrieve current caret position only when there is an // edited object.
::Outliner* pOutliner = static_cast<sd::DrawView*>(mpView)->GetTextEditOutliner(); if (pOutliner!=nullptr && pOutliner->GetViewCount()>0)
{
OutlinerView* pOutlinerView = pOutliner->GetView(0);
maStartSelection = pOutlinerView->GetSelection();
}
}
}
} elseif( nullptr != dynamic_cast< const sd::OutlineViewShell *>( pViewShell.get() ))
{ // Remember the current cursor position.
OutlinerView* pView = GetView(0); if (pView != nullptr)
pView->GetSelection();
}
}
void SdOutliner::RestoreStartPosition()
{ bool bRestore = true; // Take a negative start page index as indicator that restoring the // start position is not requested. if (mnStartPageIndex == sal_uInt16(-1) )
bRestore = false; // Don't restore when the view shell is not valid.
std::shared_ptr<sd::ViewShell> pViewShell (mpWeakViewShell.lock()); if (pViewShell == nullptr)
bRestore = false;
if (!bRestore) return;
if( nullptr != dynamic_cast< const sd::DrawViewShell *>( pViewShell.get() ))
{
std::shared_ptr<sd::DrawViewShell> pDrawViewShell (
std::dynamic_pointer_cast<sd::DrawViewShell>(pViewShell));
SetViewMode (meStartViewMode); if (pDrawViewShell != nullptr)
{
SetPage (meStartEditMode, mnStartPageIndex);
mpObj = mpStartEditedObject; if (mpObj)
{
PutTextIntoOutliner();
EnterEditMode(false); if (getOutlinerView())
getOutlinerView()->SetSelection(maStartSelection);
}
}
} elseif( nullptr != dynamic_cast< const sd::OutlineViewShell *>( pViewShell.get() ))
{ // Set cursor to its old position.
OutlinerView* pView = GetView(0); if (pView != nullptr)
pView->SetSelection (maStartSelection);
}
}
/** The main purpose of this method is to iterate over all shape objects of thesearcharea(currentselection,currentview,orwholedocument) untilatextobjecthasbeenfoundthatcontainsatleastonematchor untilnosuchobjectcanbefoundanymore.Thesetwoconditionsare expressedbysettingoneoftheflags<member>mbFoundObject</member>or <member>mbEndOfSearch</member>to<TRUE/>.
*/ void SdOutliner::ProvideNextTextObject()
{
mbEndOfSearch = false;
mbFoundObject = false;
// reset the vector search auto& rVectorGraphicSearchContext = mpImpl->getVectorGraphicSearchContext();
rVectorGraphicSearchContext.reset();
// Iterate until a valid text object has been found or the search ends. do
{
mpObj = nullptr;
mpParaObj = nullptr;
if (maObjectIterator != sd::outliner::OutlinerContainer(this).end())
{
maCurrentPosition = *maObjectIterator;
// LOK: do not descent to notes or master pages when searching bool bForbiddenPage = comphelper::LibreOfficeKit::isActive() && (maCurrentPosition.mePageKind != PageKind::Standard || maCurrentPosition.meEditMode != EditMode::Page);
rVectorGraphicSearchContext.reset();
if (!bForbiddenPage)
{ // Switch to the current object only if it is a valid text object. if (lclIsValidTextObject(maCurrentPosition))
{ // Don't set yet in case of searching: the text object may not match. if (meMode != SEARCH)
mpObj = SetObject(maCurrentPosition); else
mpObj = maCurrentPosition.mxObject.get().get();
} // Or if the object is a valid graphic object which contains vector graphic elseif (meMode == SEARCH && isValidVectorGraphicObject(maCurrentPosition))
{
mpObj = maCurrentPosition.mxObject.get().get();
rVectorGraphicSearchContext.mbCurrentIsVectorGraphic = true;
}
}
// Advance to the next object
++maObjectIterator;
if (mpObj)
{ if (rVectorGraphicSearchContext.mbCurrentIsVectorGraphic)
{ // We know here the object is a SdrGrafObj and that it // contains a vector graphic auto* pGraphicObject = static_cast<SdrGrafObj*>(mpObj);
OUString const & rString = mpSearchItem->GetSearchString(); bool bBackwards = mpSearchItem->GetBackward();
std::shared_ptr<sd::ViewShell> pViewShell (mpWeakViewShell.lock()); if (pViewShell != nullptr)
{ switch (meMode)
{ case SEARCH:
PrepareSearchAndReplace (); break; case SPELL:
PrepareSpellCheck (); break; case TEXT_CONVERSION:
PrepareConversion(); break;
}
}
}
}
} else
{
rVectorGraphicSearchContext.reset();
if (meMode == SEARCH) // Instead of doing a full-blown SetObject(), which would do the same -- but would also possibly switch pages.
mbStringFound = false;
// Before we display a dialog we first jump to where the last valid text // object was found. All page and view mode switching since then was // temporary and should not be visible to the user. if( nullptr == dynamic_cast< const sd::OutlineViewShell *>( pViewShell.get() ))
SetObject (maLastValidPosition);
if (mbRestrictSearchToSelection)
ShowEndOfSearchDialog (); else
{ // When no match has been found so far then terminate the search. if ( ! mbMatchMayExist)
{
ShowEndOfSearchDialog ();
mbEndOfSearch = true;
} // Ask the user whether to wrap around and continue the search or // to terminate. elseif (meMode==TEXT_CONVERSION || ShowWrapAroundDialog ())
{
mbMatchMayExist = false; // Everything back to beginning (or end?) of the document.
maObjectIterator = sd::outliner::OutlinerContainer(this).begin(); if( nullptr != dynamic_cast< const sd::OutlineViewShell *>( pViewShell.get() ))
{ // Set cursor to first character of the document.
OutlinerView* pOutlinerView = getOutlinerView(); if (pOutlinerView != nullptr)
pOutlinerView->SetSelection (GetSearchStartPosition ());
}
// Show the message in an info box that is modal with respect to the whole application.
weld::Window* pParent = GetMessageBoxParent();
std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(pParent,
VclMessageType::Info, VclButtonsType::Ok, aString));
xInfoBox->run();
}
bool SdOutliner::ShowWrapAroundDialog()
{ // Determine whether to show the dialog. if (mpSearchItem)
{ // When searching display the dialog only for single find&replace. const SvxSearchCmd nCommand(mpSearchItem->GetCommand()); if (nCommand == SvxSearchCmd::REPLACE || nCommand == SvxSearchCmd::FIND)
{ if (mbDirectionIsForward)
SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::End); else
SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::Start);
returntrue;
} else returnfalse;
}
// show dialog only for spelling if (meMode != SPELL) returnfalse;
// The question text depends on the search direction. bool bImpress = mrDrawDocument.GetDocumentType() == DocumentType::Impress;
// Pop up question box that asks the user whether to wrap around. // The dialog is made modal with respect to the whole application.
weld::Window* pParent = GetMessageBoxParent();
std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(pParent,
VclMessageType::Question, VclButtonsType::YesNo, SdResId(pStringId)));
sal_uInt16 nBoxResult = xQueryBox->run();
// When spell checking we have to test whether we have processed the // whole document and have reached the start page again. if (meMode == SPELL)
{ if (maSearchStartPosition == sd::outliner::Iterator()) // Remember the position of the first text object so that we // know when we have processed the whole document.
maSearchStartPosition = maObjectIterator; elseif (maSearchStartPosition == maObjectIterator)
{
mbEndOfSearch = true;
}
}
EnterEditMode( false );
}
void SdOutliner::PrepareSearchAndReplace()
{ if (!HasText( *mpSearchItem )) return;
// Set the object now that we know it matches.
mpObj = SetObject(maCurrentPosition);
mbStringFound = true;
mbMatchMayExist = true;
EnterEditMode(false);
mrDrawDocument.GetDocSh()->SetWaitCursor(false);
OutlinerView* pOutlinerView = getOutlinerView(); if (pOutlinerView != nullptr)
{
pOutlinerView->SetSelection (GetSearchStartPosition ()); if (lclIsValidTextObject(maCurrentPosition) && maCurrentPosition.mePageKind == PageKind::Notes)
{ if (auto pNotesPaneOutliner = lclGetNotesPaneOutliner(mpWeakViewShell.lock()))
{
pNotesPaneOutliner->SetSelection(getOutlinerView()->GetSelection());
}
}
}
}
// Restore old edit mode.
pDrawViewShell->ChangeEditMode(mpImpl->meOriginalEditMode, false);
SetStatusEventHdl(Link<EditStatus&,void>());
OUString sViewURL; switch (ePageKind)
{ case PageKind::Standard: default:
sViewURL = sd::framework::FrameworkHelper::msImpressViewURL; break; case PageKind::Notes:
sViewURL = sd::framework::FrameworkHelper::msNotesViewURL; break; case PageKind::Handout:
sViewURL = sd::framework::FrameworkHelper::msHandoutViewURL; break;
} // The text object iterator is destroyed when the shells are // switched but we need it so save it and restore it afterwards.
sd::outliner::Iterator aIterator (maObjectIterator); bool bMatchMayExist = mbMatchMayExist;
// Force (well, request) a synchronous update of the configuration. // In a better world we would handle the asynchronous view update // instead. But that would involve major restructuring of the // Outliner code.
sd::framework::FrameworkHelper::Instance(rBase)->RequestSynchronousUpdate();
auto pNewViewShell = rBase.GetMainViewShell();
SetViewShell(pNewViewShell); if (xFuSearch.is() && pNewViewShell->GetView())
pNewViewShell->GetView()->getSearchContext().setSearchFunction(xFuSearch);
// Switching to another view shell has intermediatly called // EndSpelling(). A PrepareSpelling() is pending, so call that now.
PrepareSpelling();
// Update the number of pages so that // <member>DetectChange()</member> has the correct value to compare // to.
mnPageCount = mrDrawDocument.GetSdPageCount(ePageKind);
// Save edit mode so that it can be restored when switching the view // shell again.
pDrawViewShell = std::dynamic_pointer_cast<sd::DrawViewShell>(pViewShell);
OSL_ASSERT(pDrawViewShell != nullptr); if (pDrawViewShell != nullptr)
mpImpl->meOriginalEditMode = pDrawViewShell->GetEditMode();
}
// Make FuText the current function.
SfxUInt16Item aItem (SID_TEXTEDIT, 1);
std::shared_ptr<sd::ViewShell> pViewShell (mpWeakViewShell.lock()); if (!(pViewShell && pViewShell->GetDispatcher())) return;
if (mpView->IsTextEdit())
{ // end text edition before starting it again
mpView->SdrEndTextEdit();
}
// To be consistent with the usual behaviour in the Office the text // object that is put into edit mode would have also to be selected. // Starting the text edit mode is not enough so we do it here by // hand.
mpView->UnmarkAllObj(pPV);
mpView->MarkObj(mpSearchSpellTextObj, pPV);
mpSearchSpellTextObj->setActiveText(mnText);
// Turn on the edit mode for the text object.
SetUpdateLayout(true);
ESelection SdOutliner::GetSearchStartPosition() const
{ // The default constructor uses the beginning of the text as default.
ESelection aPosition; if (!mbDirectionIsForward)
{ // Retrieve the position after the last character in the last // paragraph.
sal_Int32 nParagraphCount = GetParagraphCount(); if (nParagraphCount != 0)
{
sal_Int32 nLastParagraphLength = GetEditEngine().GetTextLen (
nParagraphCount-1);
aPosition = ESelection (nParagraphCount-1, nLastParagraphLength);
}
}
assert(pOutlinerView && "outline view in SdOutliner::HasNoPreviousMatch is NULL");
// Detect whether the cursor stands at the beginning // resp. at the end of the text. return pOutlinerView->GetSelection() == GetSearchStartPosition();
}
OutlinerView* pOutlinerView = getOutlinerView(); if (pOutlinerView && mpSearchItem)
{ // Detect whether there is/may be a prior match. If there is then // ask the user whether to wrap around. Otherwise tell the user // that there is no match. if (HasNoPreviousMatch ())
{ // No match found in the whole presentation.
SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::NotFound);
}
else
{ // No further matches found. Ask the user whether to wrap // around and start again.
bContinueSearch = ShowWrapAroundDialog();
}
}
// Set the new view shell.
mpWeakViewShell = rpViewShell; // When the outline view is not owned by us then we have to clear // that pointer so that the current one for the new view shell will // be used (in ProvideOutlinerView). if (rpViewShell)
{
mpView = rpViewShell->GetView();
// Make a copy of the current mark list. const size_t nCount = rMarkList.GetMarkCount(); if (nCount > 0)
{
maMarkListCopy.clear();
maMarkListCopy.reserve (nCount); for (size_t i=0; i<nCount; ++i)
maMarkListCopy.emplace_back(rMarkList.GetMark(i)->GetMarkedSdrObj ());
} else // No marked object. Is this case possible?
mbRestrictSearchToSelection = false;
}
/** Prepare to do a text conversion on the current text object. This includesputtingitintoeditmode.
*/ void SdOutliner::PrepareConversion()
{
SetUpdateLayout(true); if( HasConvertibleTextPortion( mnConversionLanguage ) )
{
SetUpdateLayout(false);
mbStringFound = true;
mbMatchMayExist = true;
EnterEditMode(true);
mrDrawDocument.GetDocSh()->SetWaitCursor( false ); // Start search at the right end of the current object's text // depending on the search direction.
} else
{
SetUpdateLayout(false);
}
}
sd::ViewShellBase* pBase = getViewShellBase(); if (pBase != nullptr)
SetViewShell (pBase->GetMainViewShell());
std::shared_ptr<sd::ViewShell> pViewShell (mpWeakViewShell.lock()); if (pViewShell)
{
mbStringFound = false;
// Supposed that we are not located at the very beginning/end of the // document then there may be a match in the document prior/after // the current position.
mbMatchMayExist = true;
// for text conversion we automatically wrap around one // time and stop at the start shape if( mpFirstObj )
{ if( (mnText == 0) && (mpFirstObj == mpObj) ) returnfalse;
} else
{
mpFirstObj = mpObj;
}
return !mbEndOfSearch;
}
weld::Window* SdOutliner::GetMessageBoxParent()
{ // We assume that the parent of the given message box is NULL, i.e. it is // modal with respect to the top application window. However, this // does not affect the search dialog. Therefore we have to lock it here // while the message box is being shown. We also have to take into // account that we are called during a spell check and the search dialog // is not available.
weld::Window* pSearchDialog = nullptr;
SfxChildWindow* pChildWindow = nullptr; switch (meMode)
{ case SEARCH: if (SfxViewFrame* pViewFrm = SfxViewFrame::Current())
pChildWindow = pViewFrm->GetChildWindow(
SvxSearchDialogWrapper::GetChildWindowId()); break;
case SPELL: if (SfxViewFrame* pViewFrm = SfxViewFrame::Current())
pChildWindow = pViewFrm->GetChildWindow(
sd::SpellDialogChildWindow::GetChildWindowId()); break;
case TEXT_CONVERSION: // There should no messages boxes be displayed while doing the // hangul hanja conversion. break;
}
if (pChildWindow != nullptr)
{ auto xController = pChildWindow->GetController();
pSearchDialog = xController ? xController->getDialog() : nullptr;
}
/** We try to create a new OutlinerView only when there is none available, eitherfromanOutlinerViewShellorapreviouscallto ProvideOutlinerView().Thisisnecessarytosupportthespellchecker whichcannotcopewithexchangingtheOutlinerView.
*/ void SdOutliner::Implementation::ProvideOutlinerView (
Outliner& rOutliner, const std::shared_ptr<sd::ViewShell>& rpViewShell,
vcl::Window* pWindow)
{ if (rpViewShell == nullptr) return;
switch (rpViewShell->GetShellType())
{ case sd::ViewShell::ST_DRAW: case sd::ViewShell::ST_IMPRESS: case sd::ViewShell::ST_NOTES: case sd::ViewShell::ST_HANDOUT:
{ // Create a new outline view to do the search on. bool bInsert = false; if (mpOutlineView != nullptr && !mbOwnOutlineView)
mpOutlineView = nullptr;
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.