2023-12-07 03:18:10 -06:00
|
|
|
/* -*- 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/.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "QuickFindPanel.hxx"
|
|
|
|
#include <com/sun/star/lang/IllegalArgumentException.hpp>
|
2024-08-01 09:31:41 -05:00
|
|
|
|
|
|
|
#include <comphelper/scopeguard.hxx>
|
2023-12-07 03:18:10 -06:00
|
|
|
#include <svl/srchitem.hxx>
|
|
|
|
#include <view.hxx>
|
|
|
|
#include <swmodule.hxx>
|
|
|
|
#include <pam.hxx>
|
|
|
|
#include <node.hxx>
|
|
|
|
#include <ndtxt.hxx>
|
|
|
|
#include <edtwin.hxx>
|
2024-06-07 21:00:35 -05:00
|
|
|
#include <fmtanchr.hxx>
|
|
|
|
#include <cntfrm.hxx>
|
2024-06-12 15:59:05 -05:00
|
|
|
#include <strings.hrc>
|
|
|
|
#include <vcl/event.hxx>
|
2024-06-12 16:37:00 -05:00
|
|
|
#include <vcl/svapp.hxx>
|
|
|
|
#include <vcl/sysdata.hxx>
|
2024-06-12 21:16:06 -05:00
|
|
|
#include <swwait.hxx>
|
2023-12-07 03:18:10 -06:00
|
|
|
|
2024-06-12 16:37:00 -05:00
|
|
|
const int CharactersBeforeAndAfter = 40;
|
2023-12-07 03:18:10 -06:00
|
|
|
|
2024-06-07 21:00:35 -05:00
|
|
|
namespace
|
|
|
|
{
|
|
|
|
void getAnchorPos(SwPosition& rPos)
|
|
|
|
{
|
|
|
|
// get the top most anchor position of the position
|
|
|
|
if (SwFrameFormat* pFlyFormat = rPos.GetNode().GetFlyFormat())
|
|
|
|
{
|
|
|
|
SwNode* pAnchorNode;
|
|
|
|
SwFrameFormat* pTmp = pFlyFormat;
|
|
|
|
while (pTmp && (pAnchorNode = pTmp->GetAnchor().GetAnchorNode())
|
|
|
|
&& (pTmp = pAnchorNode->GetFlyFormat()))
|
|
|
|
{
|
|
|
|
pFlyFormat = pTmp;
|
|
|
|
}
|
|
|
|
if (const SwPosition* pPos = pFlyFormat->GetAnchor().GetContentAnchor())
|
|
|
|
rPos = *pPos;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-07 03:18:10 -06:00
|
|
|
namespace sw::sidebar
|
|
|
|
{
|
2024-06-12 21:16:06 -05:00
|
|
|
QuickFindPanel::SearchOptionsDialog::SearchOptionsDialog(weld::Window* pParent)
|
|
|
|
: GenericDialogController(pParent, u"modules/swriter/ui/sidebarquickfindoptionsdialog.ui"_ustr,
|
|
|
|
u"SearchOptionsDialog"_ustr)
|
|
|
|
, m_xMatchCaseCheckButton(m_xBuilder->weld_check_button(u"matchcase"_ustr))
|
|
|
|
, m_xWholeWordsOnlyCheckButton(m_xBuilder->weld_check_button(u"wholewordsonly"_ustr))
|
|
|
|
, m_xSimilarityCheckButton(m_xBuilder->weld_check_button(u"similarity"_ustr))
|
|
|
|
, m_xSimilaritySettingsDialogButton(m_xBuilder->weld_button(u"similaritysettingsdialog"_ustr))
|
|
|
|
{
|
|
|
|
m_xSimilarityCheckButton->connect_toggled(
|
|
|
|
LINK(this, SearchOptionsDialog, SimilarityCheckButtonToggledHandler));
|
|
|
|
m_xSimilaritySettingsDialogButton->connect_clicked(
|
|
|
|
LINK(this, SearchOptionsDialog, SimilaritySettingsDialogButtonClickedHandler));
|
|
|
|
}
|
|
|
|
|
|
|
|
short QuickFindPanel::SearchOptionsDialog::executeSubDialog(VclAbstractDialog* dialog)
|
|
|
|
{
|
|
|
|
assert(!m_executingSubDialog);
|
|
|
|
comphelper::ScopeGuard g([this] { m_executingSubDialog = false; });
|
|
|
|
m_executingSubDialog = true;
|
|
|
|
return dialog->Execute();
|
|
|
|
}
|
|
|
|
|
|
|
|
IMPL_LINK_NOARG(QuickFindPanel::SearchOptionsDialog, SimilarityCheckButtonToggledHandler,
|
|
|
|
weld::Toggleable&, void)
|
|
|
|
{
|
|
|
|
m_xSimilaritySettingsDialogButton->set_sensitive(m_xSimilarityCheckButton->get_active());
|
|
|
|
}
|
|
|
|
|
|
|
|
IMPL_LINK_NOARG(QuickFindPanel::SearchOptionsDialog, SimilaritySettingsDialogButtonClickedHandler,
|
|
|
|
weld::Button&, void)
|
|
|
|
{
|
|
|
|
SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
|
|
|
|
ScopedVclPtr<AbstractSvxSearchSimilarityDialog> pDlg(pFact->CreateSvxSearchSimilarityDialog(
|
|
|
|
m_xDialog.get(), m_bIsLEVRelaxed, m_nLEVOther, m_nLEVShorter, m_nLEVLonger));
|
|
|
|
|
|
|
|
if (executeSubDialog(pDlg.get()) == RET_OK)
|
|
|
|
{
|
|
|
|
m_bIsLEVRelaxed = pDlg->IsRelaxed();
|
|
|
|
m_nLEVOther = pDlg->GetOther();
|
|
|
|
m_nLEVShorter = pDlg->GetShorter();
|
|
|
|
m_nLEVLonger = pDlg->GetLonger();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::unique_ptr<PanelLayout>
|
|
|
|
QuickFindPanel::Create(weld::Widget* pParent,
|
|
|
|
const css::uno::Reference<css::frame::XFrame>& rxFrame)
|
2023-12-07 03:18:10 -06:00
|
|
|
{
|
|
|
|
if (pParent == nullptr)
|
2024-06-12 21:16:06 -05:00
|
|
|
throw lang::IllegalArgumentException("no parent Window given to QuickFindPanel::Create",
|
|
|
|
nullptr, 0);
|
|
|
|
if (!rxFrame.is())
|
|
|
|
throw lang::IllegalArgumentException("no XFrame given to QuickFindPanel::Create", nullptr,
|
|
|
|
0);
|
|
|
|
return std::make_unique<QuickFindPanel>(pParent, rxFrame);
|
2023-12-07 03:18:10 -06:00
|
|
|
}
|
|
|
|
|
2024-06-12 21:16:06 -05:00
|
|
|
QuickFindPanel::QuickFindPanel(weld::Widget* pParent, const uno::Reference<frame::XFrame>& rxFrame)
|
2024-06-03 07:37:41 -05:00
|
|
|
: PanelLayout(pParent, u"QuickFindPanel"_ustr, u"modules/swriter/ui/sidebarquickfind.ui"_ustr)
|
|
|
|
, m_xSearchFindEntry(m_xBuilder->weld_entry(u"Find"_ustr))
|
2024-06-12 21:16:06 -05:00
|
|
|
, m_xSearchOptionsToolbar(m_xBuilder->weld_toolbar(u"searchoptionstoolbar"_ustr))
|
|
|
|
, m_xFindAndReplaceToolbar(m_xBuilder->weld_toolbar(u"findandreplacetoolbar"_ustr))
|
|
|
|
, m_xFindAndReplaceToolbarDispatch(
|
|
|
|
new ToolbarUnoDispatcher(*m_xFindAndReplaceToolbar, *m_xBuilder, rxFrame))
|
2024-06-03 07:37:41 -05:00
|
|
|
, m_xSearchFindsList(m_xBuilder->weld_tree_view(u"searchfinds"_ustr))
|
2024-06-12 21:16:06 -05:00
|
|
|
, m_xSearchFindFoundTimesLabel(m_xBuilder->weld_label("numberofsearchfinds"))
|
2023-12-07 03:18:10 -06:00
|
|
|
, m_pWrtShell(::GetActiveWrtShell())
|
|
|
|
{
|
2024-06-12 21:16:06 -05:00
|
|
|
m_nMinimumPanelWidth
|
|
|
|
= m_xBuilder->weld_widget(u"box"_ustr)->get_preferred_size().getWidth() + (6 * 2) + 6;
|
|
|
|
m_xContainer->set_size_request(m_nMinimumPanelWidth, 1);
|
2024-06-12 16:37:00 -05:00
|
|
|
|
2023-12-07 03:18:10 -06:00
|
|
|
m_xSearchFindEntry->connect_activate(
|
|
|
|
LINK(this, QuickFindPanel, SearchFindEntryActivateHandler));
|
|
|
|
m_xSearchFindEntry->connect_changed(LINK(this, QuickFindPanel, SearchFindEntryChangedHandler));
|
2024-06-12 21:16:06 -05:00
|
|
|
|
|
|
|
m_xSearchOptionsToolbar->connect_clicked(
|
|
|
|
LINK(this, QuickFindPanel, SearchOptionsToolbarClickedHandler));
|
|
|
|
|
2024-08-25 15:50:41 -05:00
|
|
|
m_xFindAndReplaceToolbar->connect_clicked(
|
|
|
|
LINK(this, QuickFindPanel, FindAndReplaceToolbarClickedHandler));
|
|
|
|
|
2023-12-07 03:18:10 -06:00
|
|
|
m_xSearchFindsList->connect_custom_get_size(
|
|
|
|
LINK(this, QuickFindPanel, SearchFindsListCustomGetSizeHandler));
|
|
|
|
m_xSearchFindsList->connect_custom_render(LINK(this, QuickFindPanel, SearchFindsListRender));
|
|
|
|
m_xSearchFindsList->set_column_custom_renderer(1, true);
|
|
|
|
m_xSearchFindsList->connect_changed(
|
|
|
|
LINK(this, QuickFindPanel, SearchFindsListSelectionChangedHandler));
|
|
|
|
m_xSearchFindsList->connect_row_activated(
|
|
|
|
LINK(this, QuickFindPanel, SearchFindsListRowActivatedHandler));
|
2024-06-12 21:16:06 -05:00
|
|
|
m_xSearchFindsList->connect_mouse_press(
|
|
|
|
LINK(this, QuickFindPanel, SearchFindsListMousePressHandler));
|
|
|
|
}
|
|
|
|
|
|
|
|
IMPL_LINK_NOARG(QuickFindPanel, SearchOptionsToolbarClickedHandler, const OUString&, void)
|
|
|
|
{
|
|
|
|
SearchOptionsDialog aDlg(GetFrameWeld());
|
|
|
|
|
|
|
|
aDlg.m_xMatchCaseCheckButton->set_active(m_bMatchCase);
|
|
|
|
aDlg.m_xWholeWordsOnlyCheckButton->set_active(m_bWholeWordsOnly);
|
|
|
|
aDlg.m_xSimilarityCheckButton->set_active(m_bSimilarity);
|
|
|
|
aDlg.m_xSimilaritySettingsDialogButton->set_sensitive(m_bSimilarity);
|
|
|
|
if (m_bSimilarity)
|
|
|
|
{
|
|
|
|
aDlg.m_bIsLEVRelaxed = m_bIsLEVRelaxed;
|
|
|
|
aDlg.m_nLEVOther = m_nLEVOther;
|
|
|
|
aDlg.m_nLEVShorter = m_nLEVShorter;
|
|
|
|
aDlg.m_nLEVLonger = m_nLEVLonger;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aDlg.run() == RET_OK)
|
|
|
|
{
|
|
|
|
m_bMatchCase = aDlg.m_xMatchCaseCheckButton->get_active();
|
|
|
|
m_bWholeWordsOnly = aDlg.m_xWholeWordsOnlyCheckButton->get_active();
|
|
|
|
m_bSimilarity = aDlg.m_xSimilarityCheckButton->get_active();
|
|
|
|
if (m_bSimilarity)
|
|
|
|
{
|
|
|
|
m_bIsLEVRelaxed = aDlg.m_bIsLEVRelaxed;
|
|
|
|
m_nLEVOther = aDlg.m_nLEVOther;
|
|
|
|
m_nLEVShorter = aDlg.m_nLEVShorter;
|
|
|
|
m_nLEVLonger = aDlg.m_nLEVLonger;
|
|
|
|
}
|
|
|
|
FillSearchFindsList();
|
|
|
|
}
|
2023-12-07 03:18:10 -06:00
|
|
|
}
|
|
|
|
|
2024-08-25 15:50:41 -05:00
|
|
|
// tdf#162580 related: When upgrading from Find toolbar search to advanced Find and Replace
|
|
|
|
// search dialog, inherit (pre-fill) search field's term from current value of find bar's
|
|
|
|
// focused search entry
|
|
|
|
IMPL_LINK(QuickFindPanel, FindAndReplaceToolbarClickedHandler, const OUString&, rCommand, void)
|
|
|
|
{
|
|
|
|
if (!SwView::GetSearchDialog())
|
|
|
|
{
|
|
|
|
SvxSearchItem* pSearchItem = SwView::GetSearchItem();
|
|
|
|
if (!pSearchItem)
|
|
|
|
{
|
|
|
|
pSearchItem = new SvxSearchItem(SID_SEARCH_ITEM);
|
|
|
|
SwView::SetSearchItem(pSearchItem);
|
|
|
|
}
|
|
|
|
pSearchItem->SetSearchString(m_xSearchFindEntry->get_text());
|
|
|
|
}
|
|
|
|
m_xFindAndReplaceToolbarDispatch->Select(rCommand);
|
|
|
|
}
|
|
|
|
|
2023-12-07 03:18:10 -06:00
|
|
|
QuickFindPanel::~QuickFindPanel()
|
|
|
|
{
|
|
|
|
m_xSearchFindEntry.reset();
|
|
|
|
m_xSearchFindsList.reset();
|
|
|
|
}
|
|
|
|
|
2024-06-12 21:16:06 -05:00
|
|
|
IMPL_LINK_NOARG(QuickFindPanel, SearchFindEntryChangedHandler, weld::Entry&, void)
|
2024-06-12 15:59:05 -05:00
|
|
|
{
|
2024-06-12 21:16:06 -05:00
|
|
|
m_xSearchFindEntry->set_message_type(weld::EntryMessageType::Normal);
|
|
|
|
m_xSearchFindsList->clear();
|
|
|
|
m_xSearchFindFoundTimesLabel->set_label(OUString());
|
2024-06-12 15:59:05 -05:00
|
|
|
}
|
|
|
|
|
2023-12-07 03:18:10 -06:00
|
|
|
IMPL_LINK_NOARG(QuickFindPanel, SearchFindEntryActivateHandler, weld::Entry&, bool)
|
|
|
|
{
|
|
|
|
FillSearchFindsList();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2024-06-12 21:16:06 -05:00
|
|
|
IMPL_LINK(QuickFindPanel, SearchFindsListMousePressHandler, const MouseEvent&, rMEvt, bool)
|
|
|
|
{
|
|
|
|
if (std::unique_ptr<weld::TreeIter> xEntry(m_xSearchFindsList->make_iterator());
|
|
|
|
m_xSearchFindsList->get_dest_row_at_pos(rMEvt.GetPosPixel(), xEntry.get(), false, false))
|
|
|
|
{
|
|
|
|
return m_xSearchFindsList->get_id(*xEntry)[0] == '-';
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2024-06-12 16:37:00 -05:00
|
|
|
IMPL_LINK(QuickFindPanel, SearchFindsListCustomGetSizeHandler, weld::TreeView::get_size_args,
|
|
|
|
aPayload, Size)
|
2023-12-07 03:18:10 -06:00
|
|
|
{
|
2024-06-12 16:37:00 -05:00
|
|
|
vcl::RenderContext& rRenderContext = std::get<0>(aPayload);
|
|
|
|
const OUString& rId = std::get<1>(aPayload);
|
|
|
|
|
|
|
|
const bool bPageEntry = rId[0] == '-';
|
|
|
|
|
|
|
|
OUString aEntry(rId);
|
|
|
|
if (!bPageEntry)
|
|
|
|
{
|
|
|
|
int nIndex = m_xSearchFindsList->find_id(rId);
|
|
|
|
aEntry = m_xSearchFindsList->get_text(nIndex);
|
|
|
|
}
|
|
|
|
|
|
|
|
// To not have top and bottom clipping when the sidebar width is made smaller by the user
|
2024-06-24 17:43:51 -05:00
|
|
|
// calculate the text rectangle using the minimum width the rectangle can become.
|
2024-06-12 16:37:00 -05:00
|
|
|
int x, y, width, height;
|
|
|
|
m_xSearchFindsList->get_extents_relative_to(*m_xContainer, x, y, width, height);
|
|
|
|
|
|
|
|
const int leftTextMargin = 6;
|
|
|
|
const int rightTextMargin = 6 + 3;
|
|
|
|
tools::Long nScrollBarThickness
|
|
|
|
= Application::GetSettings().GetStyleSettings().GetScrollBarSize();
|
|
|
|
|
2024-06-12 21:16:06 -05:00
|
|
|
tools::Rectangle aInRect(Point(), Size(m_nMinimumPanelWidth - (x * 2) - leftTextMargin
|
2024-06-12 16:37:00 -05:00
|
|
|
- nScrollBarThickness - rightTextMargin,
|
|
|
|
1));
|
|
|
|
|
|
|
|
tools::Rectangle aRect;
|
|
|
|
if (!bPageEntry)
|
|
|
|
{
|
|
|
|
aRect = rRenderContext.GetTextRect(aInRect, aEntry,
|
|
|
|
DrawTextFlags::VCenter | DrawTextFlags::MultiLine
|
|
|
|
| DrawTextFlags::WordBreak);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
aRect = rRenderContext.GetTextRect(aInRect, aEntry,
|
|
|
|
DrawTextFlags::Center | DrawTextFlags::VCenter);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!bPageEntry)
|
|
|
|
{
|
|
|
|
aRect.AdjustTop(-3);
|
|
|
|
aRect.AdjustBottom(+3);
|
|
|
|
}
|
|
|
|
|
|
|
|
return Size(1, aRect.GetHeight());
|
2023-12-07 03:18:10 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
IMPL_LINK(QuickFindPanel, SearchFindsListRender, weld::TreeView::render_args, aPayload, void)
|
|
|
|
{
|
|
|
|
vcl::RenderContext& rRenderContext = std::get<0>(aPayload);
|
|
|
|
const ::tools::Rectangle& rRect = std::get<1>(aPayload);
|
|
|
|
const OUString& rId = std::get<3>(aPayload);
|
2024-06-12 15:59:05 -05:00
|
|
|
|
2024-06-12 16:37:00 -05:00
|
|
|
const bool bPageEntry = rId[0] == '-';
|
2024-06-12 15:59:05 -05:00
|
|
|
|
2024-06-12 16:37:00 -05:00
|
|
|
OUString aEntry(rId);
|
2024-06-12 15:59:05 -05:00
|
|
|
|
|
|
|
if (!bPageEntry)
|
|
|
|
{
|
2024-06-12 16:37:00 -05:00
|
|
|
int nIndex = m_xSearchFindsList->find_id(rId);
|
|
|
|
aEntry = m_xSearchFindsList->get_text(nIndex);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!bPageEntry)
|
|
|
|
{
|
|
|
|
const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
|
|
|
|
rRenderContext.SetFillColor(rStyleSettings.GetDialogColor());
|
|
|
|
rRenderContext.SetTextColor(rStyleSettings.GetDialogTextColor());
|
|
|
|
}
|
|
|
|
|
|
|
|
tools::Rectangle aRect(rRect.TopLeft(),
|
|
|
|
Size(rRenderContext.GetOutputSize().Width(), rRect.GetHeight()));
|
|
|
|
|
|
|
|
if (!bPageEntry)
|
|
|
|
{
|
|
|
|
aRect.AdjustTop(+3);
|
|
|
|
aRect.AdjustBottom(-3);
|
|
|
|
}
|
|
|
|
|
|
|
|
// adjust for scrollbar when not using gtk
|
|
|
|
if (m_pWrtShell->GetWin()->GetSystemData()->toolkit != SystemEnvData::Toolkit::Gtk)
|
|
|
|
{
|
|
|
|
tools::Long nScrollBarThickness
|
|
|
|
= Application::GetSettings().GetStyleSettings().GetScrollBarSize();
|
|
|
|
aRect.AdjustRight(-nScrollBarThickness);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!bPageEntry)
|
|
|
|
{
|
|
|
|
aRect.AdjustRight(-3);
|
2024-06-12 21:16:06 -05:00
|
|
|
rRenderContext.DrawRect(aRect, 6, 6);
|
2024-06-12 16:37:00 -05:00
|
|
|
|
|
|
|
aRect.AdjustLeft(+6);
|
2024-06-12 15:59:05 -05:00
|
|
|
rRenderContext.DrawText(aRect, aEntry,
|
|
|
|
DrawTextFlags::VCenter | DrawTextFlags::MultiLine
|
|
|
|
| DrawTextFlags::WordBreak);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
aEntry = aEntry.copy(1); // remove '-'
|
|
|
|
tools::Long aTextWidth = rRenderContext.GetTextWidth(aEntry);
|
|
|
|
tools::Long aTextHeight = rRenderContext.GetTextHeight();
|
|
|
|
|
|
|
|
rRenderContext.Push();
|
|
|
|
rRenderContext.SetLineColor(COL_BLACK);
|
|
|
|
rRenderContext.DrawLine(
|
|
|
|
aRect.LeftCenter(),
|
|
|
|
Point(aRect.Center().AdjustX(-(aTextWidth / 2)) - 4, aRect.Center().getY()));
|
|
|
|
rRenderContext.DrawText(Point(aRect.Center().AdjustX(-(aTextWidth / 2)),
|
|
|
|
aRect.Center().AdjustY(-(aTextHeight / 2) - 1)),
|
|
|
|
aEntry);
|
|
|
|
rRenderContext.DrawLine(
|
|
|
|
Point(aRect.Center().AdjustX(aTextWidth / 2) + 5, aRect.Center().getY()),
|
|
|
|
aRect.RightCenter());
|
|
|
|
rRenderContext.Pop();
|
|
|
|
}
|
2023-12-07 03:18:10 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
IMPL_LINK_NOARG(QuickFindPanel, SearchFindsListSelectionChangedHandler, weld::TreeView&, void)
|
|
|
|
{
|
2024-06-12 15:59:05 -05:00
|
|
|
std::unique_ptr<weld::TreeIter> xEntry(m_xSearchFindsList->make_iterator());
|
|
|
|
if (!m_xSearchFindsList->get_cursor(xEntry.get()))
|
|
|
|
return;
|
|
|
|
|
|
|
|
OUString sId = m_xSearchFindsList->get_id(*xEntry);
|
|
|
|
|
|
|
|
// check for page number entry
|
|
|
|
if (sId[0] == '-')
|
|
|
|
return;
|
|
|
|
|
2024-07-02 03:02:57 -05:00
|
|
|
std::unique_ptr<SwPaM>& rxPaM = m_vPaMs[sId.toUInt64()];
|
2023-12-07 03:18:10 -06:00
|
|
|
|
|
|
|
m_pWrtShell->StartAction();
|
|
|
|
bool bFound = false;
|
|
|
|
for (SwPaM& rPaM : m_pWrtShell->GetCursor()->GetRingContainer())
|
|
|
|
{
|
|
|
|
if (*rxPaM->GetPoint() == *rPaM.GetPoint() && *rxPaM->GetMark() == *rPaM.GetMark())
|
|
|
|
{
|
|
|
|
bFound = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
m_pWrtShell->GoNextCursor();
|
|
|
|
}
|
|
|
|
if (!bFound)
|
|
|
|
{
|
|
|
|
m_pWrtShell->AssureStdMode();
|
|
|
|
m_pWrtShell->SetSelection(*rxPaM);
|
|
|
|
}
|
|
|
|
m_pWrtShell->EndAction();
|
|
|
|
|
2024-09-23 21:25:17 -05:00
|
|
|
// tdf#163100 Need more FIND details
|
|
|
|
// Set the found times label to show "Match X of N matches found."
|
|
|
|
auto nSearchFindFoundTimes = m_vPaMs.size();
|
|
|
|
OUString sText = SwResId(STR_SEARCH_KEY_FOUND_XOFN, nSearchFindFoundTimes);
|
|
|
|
sText = sText.replaceFirst("%1", OUString::number(sId.toUInt32() + 1));
|
|
|
|
sText = sText.replaceFirst("%2", OUString::number(nSearchFindFoundTimes));
|
|
|
|
m_xSearchFindFoundTimesLabel->set_label(sText);
|
|
|
|
|
2023-12-07 03:18:10 -06:00
|
|
|
SwShellCursor* pShellCursor = m_pWrtShell->GetCursor_();
|
|
|
|
std::vector<basegfx::B2DRange> vRanges;
|
|
|
|
for (const SwRect& rRect : *pShellCursor)
|
|
|
|
{
|
|
|
|
tools::Rectangle aRect = rRect.SVRect();
|
|
|
|
vRanges.emplace_back(aRect.Left(), aRect.Top(), aRect.Right(), aRect.Bottom());
|
|
|
|
}
|
|
|
|
m_pWrtShell->GetView().BringToAttention(std::move(vRanges));
|
|
|
|
}
|
|
|
|
|
|
|
|
IMPL_LINK_NOARG(QuickFindPanel, SearchFindsListRowActivatedHandler, weld::TreeView&, bool)
|
|
|
|
{
|
2024-06-12 15:59:05 -05:00
|
|
|
std::unique_ptr<weld::TreeIter> xEntry(m_xSearchFindsList->make_iterator());
|
|
|
|
if (!m_xSearchFindsList->get_cursor(xEntry.get()))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// check for page number entry
|
|
|
|
if (m_xSearchFindsList->get_id(*xEntry)[0] == '-')
|
|
|
|
return false;
|
|
|
|
|
2023-12-07 03:18:10 -06:00
|
|
|
m_pWrtShell->GetView().GetEditWin().GrabFocus();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void QuickFindPanel::FillSearchFindsList()
|
|
|
|
{
|
|
|
|
m_vPaMs.clear();
|
|
|
|
m_xSearchFindsList->clear();
|
2024-06-12 21:16:06 -05:00
|
|
|
m_xSearchFindFoundTimesLabel->set_label(OUString());
|
2023-12-07 03:18:10 -06:00
|
|
|
|
2024-06-12 21:16:06 -05:00
|
|
|
const OUString& rsFindEntry = m_xSearchFindEntry->get_text();
|
|
|
|
if (rsFindEntry.isEmpty())
|
2024-06-07 21:00:35 -05:00
|
|
|
return;
|
|
|
|
|
2024-06-12 21:16:06 -05:00
|
|
|
SwWait aWait(*m_pWrtShell->GetDoc()->GetDocShell(), true);
|
2024-06-07 21:00:35 -05:00
|
|
|
|
2024-06-12 21:16:06 -05:00
|
|
|
m_pWrtShell->AssureStdMode();
|
2024-06-07 21:00:35 -05:00
|
|
|
|
2024-06-12 21:16:06 -05:00
|
|
|
i18nutil::SearchOptions2 aSearchOptions;
|
|
|
|
aSearchOptions.Locale = GetAppLanguageTag().getLocale();
|
|
|
|
aSearchOptions.searchString = rsFindEntry;
|
|
|
|
aSearchOptions.replaceString.clear();
|
|
|
|
if (m_bWholeWordsOnly)
|
|
|
|
aSearchOptions.searchFlag |= css::util::SearchFlags::NORM_WORD_ONLY;
|
|
|
|
if (m_bSimilarity)
|
2024-06-07 21:00:35 -05:00
|
|
|
{
|
2024-06-12 21:16:06 -05:00
|
|
|
aSearchOptions.AlgorithmType2 = css::util::SearchAlgorithms2::APPROXIMATE;
|
|
|
|
if (m_bIsLEVRelaxed)
|
|
|
|
aSearchOptions.searchFlag |= css::util::SearchFlags::LEV_RELAXED;
|
|
|
|
aSearchOptions.changedChars = m_nLEVOther;
|
|
|
|
aSearchOptions.insertedChars = m_nLEVShorter;
|
|
|
|
aSearchOptions.deletedChars = m_nLEVLonger;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
aSearchOptions.AlgorithmType2 = css::util::SearchAlgorithms2::ABSOLUTE;
|
|
|
|
TransliterationFlags nTransliterationFlags = TransliterationFlags::IGNORE_WIDTH;
|
|
|
|
if (!m_bMatchCase)
|
|
|
|
nTransliterationFlags |= TransliterationFlags::IGNORE_CASE;
|
|
|
|
aSearchOptions.transliterateFlags = nTransliterationFlags;
|
|
|
|
|
|
|
|
m_pWrtShell->SttSelect();
|
|
|
|
/*sal_Int32 nFound =*/m_pWrtShell->SearchPattern(
|
|
|
|
aSearchOptions, false, SwDocPositions::Start, SwDocPositions::End,
|
|
|
|
FindRanges::InBody | FindRanges::InSelAll, false);
|
|
|
|
m_pWrtShell->EndSelect();
|
|
|
|
|
|
|
|
if (m_pWrtShell->HasMark())
|
|
|
|
{
|
|
|
|
for (SwPaM& rPaM : m_pWrtShell->GetCursor()->GetRingContainer())
|
2024-06-07 21:00:35 -05:00
|
|
|
{
|
2024-06-12 21:16:06 -05:00
|
|
|
SwPosition* pMarkPosition = rPaM.GetMark();
|
|
|
|
SwPosition* pPointPosition = rPaM.GetPoint();
|
|
|
|
std::unique_ptr<SwPaM> xPaM(std::make_unique<SwPaM>(*pMarkPosition, *pPointPosition));
|
|
|
|
m_vPaMs.push_back(std::move(xPaM));
|
2024-06-07 21:00:35 -05:00
|
|
|
}
|
2024-06-12 21:16:06 -05:00
|
|
|
|
|
|
|
// tdf#160538 sort finds in frames and footnotes in the order they occur in the document
|
|
|
|
const SwNodeOffset nEndOfInsertsIndex
|
|
|
|
= m_pWrtShell->GetNodes().GetEndOfInserts().GetIndex();
|
|
|
|
const SwNodeOffset nEndOfExtrasIndex = m_pWrtShell->GetNodes().GetEndOfExtras().GetIndex();
|
|
|
|
std::stable_sort(m_vPaMs.begin(), m_vPaMs.end(),
|
|
|
|
[&nEndOfInsertsIndex, &nEndOfExtrasIndex,
|
|
|
|
this](const std::unique_ptr<SwPaM>& a, const std::unique_ptr<SwPaM>& b) {
|
|
|
|
SwPosition aPos(*a->Start());
|
|
|
|
SwPosition bPos(*b->Start());
|
|
|
|
// use page number for footnotes and endnotes
|
|
|
|
if (aPos.GetNodeIndex() >= nEndOfInsertsIndex
|
|
|
|
&& bPos.GetNodeIndex() < nEndOfInsertsIndex)
|
|
|
|
return b->GetPageNum() >= a->GetPageNum();
|
|
|
|
// use anchor position for finds that are located in flys
|
|
|
|
if (nEndOfExtrasIndex >= aPos.GetNodeIndex())
|
|
|
|
getAnchorPos(aPos);
|
|
|
|
if (nEndOfExtrasIndex >= bPos.GetNodeIndex())
|
|
|
|
getAnchorPos(bPos);
|
|
|
|
if (aPos == bPos)
|
|
|
|
{
|
|
|
|
// probably in same or nested fly frame
|
|
|
|
// sort using layout position
|
|
|
|
SwRect aCharRect, bCharRect;
|
|
|
|
if (SwContentFrame* pFrame
|
|
|
|
= a->GetMarkContentNode()->GetTextNode()->getLayoutFrame(
|
|
|
|
m_pWrtShell->GetLayout()))
|
|
|
|
{
|
|
|
|
pFrame->GetCharRect(aCharRect, *a->GetMark());
|
|
|
|
}
|
|
|
|
if (SwContentFrame* pFrame
|
|
|
|
= b->GetMarkContentNode()->GetTextNode()->getLayoutFrame(
|
|
|
|
m_pWrtShell->GetLayout()))
|
|
|
|
{
|
|
|
|
pFrame->GetCharRect(bCharRect, *b->GetMark());
|
|
|
|
}
|
|
|
|
return aCharRect.Top() < bCharRect.Top();
|
|
|
|
}
|
|
|
|
return aPos < bPos;
|
|
|
|
});
|
|
|
|
|
|
|
|
// fill list
|
|
|
|
for (sal_uInt16 nPage = 0, i = 0; std::unique_ptr<SwPaM> & xPaM : m_vPaMs)
|
2024-06-07 21:00:35 -05:00
|
|
|
{
|
2024-06-12 21:16:06 -05:00
|
|
|
SwPosition* pMarkPosition = xPaM->GetMark();
|
|
|
|
SwPosition* pPointPosition = xPaM->GetPoint();
|
|
|
|
|
|
|
|
const SwContentNode* pContentNode = pMarkPosition->GetContentNode();
|
|
|
|
const SwTextNode* pTextNode = pContentNode->GetTextNode();
|
|
|
|
const OUString& sNodeText = pTextNode->GetText();
|
|
|
|
|
|
|
|
auto nMarkIndex = pMarkPosition->GetContentIndex();
|
|
|
|
auto nPointIndex = pPointPosition->GetContentIndex();
|
|
|
|
|
|
|
|
// determine the text node text subview start index for the list entry text
|
|
|
|
auto nStartIndex = nMarkIndex - CharactersBeforeAndAfter;
|
|
|
|
if (nStartIndex < 0)
|
2024-06-02 21:23:10 -05:00
|
|
|
{
|
2024-06-12 21:16:06 -05:00
|
|
|
nStartIndex = 0;
|
|
|
|
}
|
|
|
|
else
|
2023-12-07 03:18:10 -06:00
|
|
|
{
|
2024-06-12 21:16:06 -05:00
|
|
|
// tdf#160539 format search finds results also to word boundaries
|
|
|
|
sal_Unicode ch;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
ch = sNodeText[nStartIndex];
|
|
|
|
} while (++nStartIndex < nMarkIndex && ch != ' ' && ch != '\t');
|
|
|
|
if (nStartIndex < nMarkIndex)
|
|
|
|
{
|
|
|
|
// move past neighboring space and tab characters
|
|
|
|
ch = sNodeText[nStartIndex];
|
|
|
|
while (nStartIndex < nMarkIndex && (ch == ' ' || ch == '\t'))
|
|
|
|
ch = sNodeText[++nStartIndex];
|
|
|
|
}
|
|
|
|
if (nStartIndex == nMarkIndex) // no white space found
|
|
|
|
nStartIndex = nMarkIndex - CharactersBeforeAndAfter;
|
2023-12-07 03:18:10 -06:00
|
|
|
}
|
2024-06-02 21:23:10 -05:00
|
|
|
|
2024-06-12 21:16:06 -05:00
|
|
|
// determine the text node text subview end index for the list entry text
|
|
|
|
auto nEndIndex = nPointIndex + CharactersBeforeAndAfter;
|
|
|
|
if (nEndIndex >= sNodeText.getLength())
|
2024-06-07 21:00:35 -05:00
|
|
|
{
|
2024-06-12 21:16:06 -05:00
|
|
|
nEndIndex = sNodeText.getLength() - 1;
|
|
|
|
}
|
|
|
|
else
|
2024-06-07 21:00:35 -05:00
|
|
|
{
|
2024-06-12 21:16:06 -05:00
|
|
|
// tdf#160539 format search finds results also to word boundaries
|
|
|
|
sal_Unicode ch;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
ch = sNodeText[nEndIndex];
|
|
|
|
} while (--nEndIndex > nPointIndex && ch != ' ' && ch != '\t');
|
|
|
|
if (nEndIndex > nPointIndex)
|
|
|
|
{
|
|
|
|
// move past neighboring space and tab characters
|
|
|
|
ch = sNodeText[nEndIndex];
|
|
|
|
while (nEndIndex > nPointIndex && (ch == ' ' || ch == '\t'))
|
|
|
|
ch = sNodeText[--nEndIndex];
|
|
|
|
}
|
|
|
|
if (nEndIndex == nPointIndex) // no white space found
|
|
|
|
{
|
|
|
|
nEndIndex = nPointIndex + CharactersBeforeAndAfter;
|
|
|
|
if (nEndIndex >= sNodeText.getLength())
|
|
|
|
nEndIndex = sNodeText.getLength() - 1;
|
|
|
|
}
|
2024-06-07 21:00:35 -05:00
|
|
|
}
|
2024-06-12 21:16:06 -05:00
|
|
|
|
|
|
|
// tdf#161291 indicate page of search finds
|
|
|
|
if (xPaM->GetPageNum() != nPage)
|
2024-06-07 21:00:35 -05:00
|
|
|
{
|
2024-06-12 21:16:06 -05:00
|
|
|
nPage = xPaM->GetPageNum();
|
|
|
|
OUString sPageEntry(u"-"_ustr + SwResId(ST_PGE) + u" "_ustr
|
|
|
|
+ OUString::number(nPage));
|
|
|
|
m_xSearchFindsList->append(sPageEntry, sPageEntry);
|
2024-06-07 21:00:35 -05:00
|
|
|
}
|
|
|
|
|
2024-06-12 21:16:06 -05:00
|
|
|
auto nCount = nMarkIndex - nStartIndex;
|
|
|
|
OUString sTextBeforeFind = OUString::Concat(sNodeText.subView(nStartIndex, nCount));
|
|
|
|
auto nCount1 = nPointIndex - nMarkIndex;
|
|
|
|
OUString sFind = OUString::Concat(sNodeText.subView(nMarkIndex, nCount1));
|
|
|
|
auto nCount2 = nEndIndex - nPointIndex + 1;
|
|
|
|
OUString sTextAfterFind = OUString::Concat(sNodeText.subView(nPointIndex, nCount2));
|
|
|
|
OUString sStr = sTextBeforeFind + "[" + sFind + "]" + sTextAfterFind;
|
|
|
|
|
|
|
|
OUString sId = OUString::number(i++);
|
|
|
|
m_xSearchFindsList->append(sId, sStr);
|
2024-06-12 15:59:05 -05:00
|
|
|
}
|
2024-06-12 21:16:06 -05:00
|
|
|
}
|
2024-06-12 15:59:05 -05:00
|
|
|
|
2024-06-12 21:16:06 -05:00
|
|
|
// Any finds?
|
|
|
|
auto nSearchFindFoundTimes = m_vPaMs.size();
|
2024-06-07 21:00:35 -05:00
|
|
|
|
2024-06-12 21:16:06 -05:00
|
|
|
// set the search term entry background
|
|
|
|
m_xSearchFindEntry->set_message_type(nSearchFindFoundTimes ? weld::EntryMessageType::Normal
|
|
|
|
: weld::EntryMessageType::Error);
|
|
|
|
// make the search finds list focusable or not
|
|
|
|
m_xSearchFindsList->set_sensitive(bool(nSearchFindFoundTimes));
|
|
|
|
|
|
|
|
// set the search term found label number of times found
|
|
|
|
OUString sText(SwResId(STR_SEARCH_KEY_FOUND_TIMES, nSearchFindFoundTimes));
|
|
|
|
sText = sText.replaceFirst("%1", OUString::number(nSearchFindFoundTimes));
|
|
|
|
m_xSearchFindFoundTimesLabel->set_label(sText);
|
2023-12-07 03:18:10 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// end of namespace ::sw::sidebar
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|