tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / sfx2 / source / appl / newhelp.cxx
blob82261d007e67fb333dae4127a5a9b6ba8ca8c355
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include "newhelp.hxx"
22 #include <sfx2/sfxresid.hxx>
23 #include "helpinterceptor.hxx"
24 #include <helper.hxx>
25 #include <srchdlg.hxx>
26 #include <sfx2/sfxhelp.hxx>
27 #include <sal/log.hxx>
28 #include <tools/debug.hxx>
29 #include <comphelper/diagnose_ex.hxx>
30 #include <o3tl/string_view.hxx>
32 #include <sfx2/strings.hrc>
33 #include <helpids.h>
34 #include <bitmaps.hlst>
36 #include <rtl/ustrbuf.hxx>
37 #include <comphelper/configurationhelper.hxx>
38 #include <comphelper/processfactory.hxx>
39 #include <comphelper/string.hxx>
40 #include <toolkit/helper/vclunohelper.hxx>
41 #include <com/sun/star/beans/PropertyValue.hpp>
42 #include <com/sun/star/beans/XPropertySetInfo.hpp>
43 #include <com/sun/star/container/XIndexAccess.hpp>
44 #include <com/sun/star/frame/XComponentLoader.hpp>
45 #include <com/sun/star/frame/XTitle.hpp>
46 #include <com/sun/star/frame/XLayoutManager.hpp>
47 #include <com/sun/star/frame/XController.hpp>
48 #include <com/sun/star/frame/XDispatch.hpp>
49 #include <com/sun/star/frame/XDispatchProvider.hpp>
50 #include <com/sun/star/frame/Frame.hpp>
51 #include <com/sun/star/i18n/XBreakIterator.hpp>
52 #include <com/sun/star/i18n/WordType.hpp>
53 #include <com/sun/star/lang/XComponent.hpp>
54 #include <com/sun/star/style/XStyle.hpp>
55 #include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
56 #include <com/sun/star/text/XText.hpp>
57 #include <com/sun/star/text/XTextCursor.hpp>
58 #include <com/sun/star/text/XTextDocument.hpp>
59 #include <com/sun/star/text/XTextViewCursor.hpp>
60 #include <com/sun/star/text/XTextViewCursorSupplier.hpp>
61 #include <com/sun/star/ucb/CommandAbortedException.hpp>
62 #include <com/sun/star/util/URL.hpp>
63 #include <com/sun/star/util/XSearchable.hpp>
64 #include <com/sun/star/util/XSearchDescriptor.hpp>
65 #include <com/sun/star/util/URLTransformer.hpp>
66 #include <com/sun/star/util/XURLTransformer.hpp>
67 #include <com/sun/star/util/XModifiable.hpp>
68 #include <com/sun/star/util/XCloseable.hpp>
69 #include <com/sun/star/util/CloseVetoException.hpp>
70 #include <com/sun/star/view/XSelectionSupplier.hpp>
71 #include <com/sun/star/view/XViewSettingsSupplier.hpp>
72 #include <unotools/historyoptions.hxx>
73 #include <unotools/viewoptions.hxx>
74 #include <tools/urlobj.hxx>
75 #include <svtools/imagemgr.hxx>
76 #include <svtools/miscopt.hxx>
77 #include <utility>
78 #include <vcl/commandevent.hxx>
79 #include <vcl/event.hxx>
80 #include <vcl/i18nhelp.hxx>
81 #include <vcl/settings.hxx>
82 #include <vcl/svapp.hxx>
83 #include <vcl/unohelp.hxx>
84 #include <vcl/weld.hxx>
86 #include <ucbhelper/content.hxx>
87 #include <unotools/ucbhelper.hxx>
89 #include <string_view>
90 #include <unordered_map>
91 #include <vector>
93 using namespace ::ucbhelper;
94 using namespace ::com::sun::star::ucb;
96 using namespace ::com::sun::star;
97 using namespace ::com::sun::star::beans;
98 using namespace ::com::sun::star::container;
99 using namespace ::com::sun::star::frame;
100 using namespace ::com::sun::star::i18n;
101 using namespace ::com::sun::star::lang;
102 using namespace ::com::sun::star::style;
103 using namespace ::com::sun::star::text;
104 using namespace ::com::sun::star::uno;
105 using namespace ::com::sun::star::util;
106 using namespace ::com::sun::star::view;
108 using namespace ::comphelper;
110 // defines ---------------------------------------------------------------
112 constexpr OUString CONFIGNAME_HELPWIN = u"OfficeHelp"_ustr;
113 constexpr OUString CONFIGNAME_INDEXWIN = u"OfficeHelpIndex"_ustr;
114 constexpr OUString CONFIGNAME_SEARCHPAGE = u"OfficeHelpSearch"_ustr;
115 constexpr OUString IMAGE_URL = u"private:factory/"_ustr;
117 constexpr OUString PROPERTY_KEYWORDLIST = u"KeywordList"_ustr;
118 constexpr OUString PROPERTY_KEYWORDREF = u"KeywordRef"_ustr;
119 constexpr OUString PROPERTY_ANCHORREF = u"KeywordAnchorForRef"_ustr;
120 constexpr OUString PROPERTY_TITLEREF = u"KeywordTitleForRef"_ustr;
121 constexpr OUString PROPERTY_TITLE = u"Title"_ustr;
122 constexpr OUString HELP_URL = u"vnd.sun.star.help://"_ustr;
123 constexpr OUStringLiteral HELP_SEARCH_TAG = u"/?Query=";
124 constexpr OUString USERITEM_NAME = u"UserItem"_ustr;
126 constexpr OUStringLiteral PACKAGE_SETUP = u"/org.openoffice.Setup";
127 constexpr OUString PATH_OFFICE_FACTORIES = u"Office/Factories/"_ustr;
128 constexpr OUString KEY_HELP_ON_OPEN = u"ooSetupFactoryHelpOnOpen"_ustr;
129 constexpr OUStringLiteral KEY_UI_NAME = u"ooSetupFactoryUIName";
131 namespace sfx2
135 /** Prepare a search string for searching or selecting.
136 For searching every search word needs the postfix '*' and the delimiter ' ' if necessary.
137 For selecting the delimiter '|' is required to search with regular expressions.
138 Samples:
139 search string | output for searching | output for selecting
140 -----------------------------------------------------------
141 "text" | "text*" | "text"
142 "text*" | "text*" | "text"
143 "text menu" | "text* menu*" | "text|menu"
145 static OUString PrepareSearchString( const OUString& rSearchString,
146 const Reference< XBreakIterator >& xBreak, bool bForSearch )
148 OUStringBuffer sSearchStr;
149 sal_Int32 nStartPos = 0;
150 const lang::Locale aLocale = Application::GetSettings().GetUILanguageTag().getLocale();
151 Boundary aBoundary = xBreak->getWordBoundary(
152 rSearchString, nStartPos, aLocale, WordType::ANYWORD_IGNOREWHITESPACES, true );
154 while ( aBoundary.startPos < aBoundary.endPos )
156 nStartPos = aBoundary.endPos;
157 OUString sSearchToken( rSearchString.copy(
158 static_cast<sal_uInt16>(aBoundary.startPos), static_cast<sal_uInt16>(aBoundary.endPos) - static_cast<sal_uInt16>(aBoundary.startPos) ) );
159 if ( !sSearchToken.isEmpty() && ( sSearchToken.getLength() > 1 || sSearchToken[0] != '.' ) )
161 if ( bForSearch && sSearchToken[ sSearchToken.getLength() - 1 ] != '*' )
162 sSearchToken += "*";
164 if ( sSearchToken.getLength() > 1 ||
165 ( sSearchToken.getLength() > 0 && sSearchToken[ 0 ] != '*' ) )
167 if ( !sSearchStr.isEmpty() )
169 if ( bForSearch )
170 sSearchStr.append(" ");
171 else
172 sSearchStr.append("|");
174 sSearchStr.append(sSearchToken);
177 aBoundary = xBreak->nextWord( rSearchString, nStartPos,
178 aLocale, WordType::ANYWORD_IGNOREWHITESPACES );
181 return sSearchStr.makeStringAndClear();
184 // namespace sfx2
188 // struct IndexEntry_Impl ------------------------------------------------
190 namespace {
192 struct IndexEntry_Impl
194 bool m_bSubEntry;
195 OUString m_aURL;
197 IndexEntry_Impl( OUString aURL, bool bSubEntry ) :
198 m_bSubEntry( bSubEntry ), m_aURL(std::move( aURL )) {}
201 // struct ContentEntry_Impl ----------------------------------------------
203 struct ContentEntry_Impl
205 OUString aURL;
206 bool bIsFolder;
208 ContentEntry_Impl( OUString _aURL, bool bFolder ) :
209 aURL(std::move( _aURL )), bIsFolder( bFolder ) {}
214 void ContentTabPage_Impl::InitRoot()
216 std::vector< OUString > aList =
217 SfxContentHelper::GetHelpTreeViewContents( u"vnd.sun.star.hier://com.sun.star.help.TreeView/"_ustr );
219 for (const OUString & aRow : aList)
221 sal_Int32 nIdx = 0;
222 OUString aTitle = aRow.getToken( 0, '\t', nIdx );
223 OUString aURL = aRow.getToken( 0, '\t', nIdx );
224 sal_Unicode cFolder = o3tl::getToken(aRow, 0, '\t', nIdx )[0];
225 bool bIsFolder = ( '1' == cFolder );
226 OUString sId;
227 if (bIsFolder)
228 sId = weld::toId(new ContentEntry_Impl(aURL, true));
229 m_xContentBox->insert(nullptr, -1, &aTitle, &sId, nullptr, nullptr, true, m_xScratchIter.get());
230 m_xContentBox->set_image(*m_xScratchIter, aClosedBookImage);
234 void ContentTabPage_Impl::ClearChildren(const weld::TreeIter* pParent)
236 std::unique_ptr<weld::TreeIter> xEntry = m_xContentBox->make_iterator(pParent);
237 bool bEntry = m_xContentBox->iter_children(*xEntry);
238 while (bEntry)
240 ClearChildren(xEntry.get());
241 delete weld::fromId<ContentEntry_Impl*>(m_xContentBox->get_id(*xEntry));
242 bEntry = m_xContentBox->iter_next_sibling(*xEntry);
247 IMPL_LINK(ContentTabPage_Impl, ExpandingHdl, const weld::TreeIter&, rIter, bool)
249 ContentEntry_Impl* pContentEntry = weld::fromId<ContentEntry_Impl*>(m_xContentBox->get_id(rIter));
250 if (!m_xContentBox->iter_has_child(rIter))
254 if (pContentEntry)
256 std::vector<OUString > aList = SfxContentHelper::GetHelpTreeViewContents(pContentEntry->aURL);
258 for (const OUString & aRow : aList)
260 sal_Int32 nIdx = 0;
261 OUString aTitle = aRow.getToken( 0, '\t', nIdx );
262 OUString aURL = aRow.getToken( 0, '\t', nIdx );
263 sal_Unicode cFolder = o3tl::getToken(aRow, 0, '\t', nIdx )[0];
264 bool bIsFolder = ( '1' == cFolder );
265 if ( bIsFolder )
267 OUString sId = weld::toId(new ContentEntry_Impl(aURL, true));
268 m_xContentBox->insert(&rIter, -1, &aTitle, &sId, nullptr, nullptr, true, m_xScratchIter.get());
269 m_xContentBox->set_image(*m_xScratchIter, aClosedBookImage);
271 else
273 Any aAny( ::utl::UCBContentHelper::GetProperty( aURL, u"TargetURL"_ustr ) );
274 OUString sId;
275 OUString aTargetURL;
276 if ( aAny >>= aTargetURL )
277 sId = weld::toId(new ContentEntry_Impl(aTargetURL, false));
278 m_xContentBox->insert(&rIter, -1, &aTitle, &sId, nullptr, nullptr, false, m_xScratchIter.get());
279 m_xContentBox->set_image(*m_xScratchIter, aDocumentImage);
284 catch (const Exception&)
286 TOOLS_WARN_EXCEPTION( "sfx.appl", "ContentListBox_Impl::RequestingChildren(): unexpected exception" );
290 if (!pContentEntry || pContentEntry->bIsFolder)
291 m_xContentBox->set_image(rIter, aOpenBookImage);
293 return true;
296 IMPL_LINK(ContentTabPage_Impl, CollapsingHdl, const weld::TreeIter&, rIter, bool)
298 ContentEntry_Impl* pContentEntry = weld::fromId<ContentEntry_Impl*>(m_xContentBox->get_id(rIter));
299 if (!pContentEntry || pContentEntry->bIsFolder)
300 m_xContentBox->set_image(rIter, aClosedBookImage);
302 return true;
305 OUString ContentTabPage_Impl::GetSelectedEntry() const
307 OUString aRet;
308 ContentEntry_Impl* pEntry = weld::fromId<ContentEntry_Impl*>(m_xContentBox->get_selected_id());
309 if (pEntry && !pEntry->bIsFolder)
310 aRet = pEntry->aURL;
311 return aRet;
314 // class HelpTabPage_Impl ------------------------------------------------
315 HelpTabPage_Impl::HelpTabPage_Impl(weld::Widget* pParent, SfxHelpIndexWindow_Impl* pIdxWin,
316 const OUString& rID, const OUString& rUIXMLDescription)
317 : BuilderPage(pParent, nullptr, rUIXMLDescription, rID)
318 , m_pIdxWin(pIdxWin)
322 HelpTabPage_Impl::~HelpTabPage_Impl()
326 // class ContentTabPage_Impl ---------------------------------------------
327 ContentTabPage_Impl::ContentTabPage_Impl(weld::Widget* pParent, SfxHelpIndexWindow_Impl* pIdxWin)
328 : HelpTabPage_Impl(pParent, pIdxWin, u"HelpContentPage"_ustr,
329 u"sfx/ui/helpcontentpage.ui"_ustr)
330 , m_xContentBox(m_xBuilder->weld_tree_view(u"content"_ustr))
331 , m_xScratchIter(m_xContentBox->make_iterator())
332 , aOpenBookImage(BMP_HELP_CONTENT_BOOK_OPEN)
333 , aClosedBookImage(BMP_HELP_CONTENT_BOOK_CLOSED)
334 , aDocumentImage(BMP_HELP_CONTENT_DOC)
336 m_xContentBox->set_size_request(m_xContentBox->get_approximate_digit_width() * 30,
337 m_xContentBox->get_height_rows(20));
338 m_xContentBox->connect_row_activated(LINK(this, ContentTabPage_Impl, DoubleClickHdl));
339 m_xContentBox->connect_expanding(LINK(this, ContentTabPage_Impl, ExpandingHdl));
340 m_xContentBox->connect_collapsing(LINK(this, ContentTabPage_Impl, CollapsingHdl));
342 InitRoot();
345 IMPL_LINK_NOARG(ContentTabPage_Impl, DoubleClickHdl, weld::TreeView&, bool)
347 aDoubleClickHdl.Call(nullptr);
348 return false;
351 void ContentTabPage_Impl::SetDoubleClickHdl(const Link<LinkParamNone*, void>& rLink)
353 aDoubleClickHdl = rLink;
356 ContentTabPage_Impl::~ContentTabPage_Impl()
358 std::unique_ptr<weld::TreeIter> xEntry = m_xContentBox->make_iterator();
359 bool bEntry = m_xContentBox->get_iter_first(*xEntry);
360 while (bEntry)
362 ClearChildren(xEntry.get());
363 delete weld::fromId<ContentEntry_Impl*>(m_xContentBox->get_id(*xEntry));
364 bEntry = m_xContentBox->iter_next_sibling(*xEntry);
368 void IndexTabPage_Impl::SelectExecutableEntry()
370 sal_Int32 nPos = m_xIndexList->find_text(m_xIndexEntry->get_text());
371 if (nPos == -1)
372 return;
374 sal_Int32 nOldPos = nPos;
375 OUString aEntryText;
376 IndexEntry_Impl* pEntry = weld::fromId<IndexEntry_Impl*>(m_xIndexList->get_id(nPos));
377 sal_Int32 nCount = m_xIndexList->n_children();
378 while ( nPos < nCount && ( !pEntry || pEntry->m_aURL.isEmpty() ) )
380 pEntry = weld::fromId<IndexEntry_Impl*>(m_xIndexList->get_id(++nPos));
381 aEntryText = m_xIndexList->get_text(nPos);
384 if ( nOldPos != nPos )
385 m_xIndexEntry->set_text(aEntryText);
388 // class IndexTabPage_Impl -----------------------------------------------
389 IndexTabPage_Impl::IndexTabPage_Impl(weld::Widget* pParent, SfxHelpIndexWindow_Impl* pIdxWin)
390 : HelpTabPage_Impl(pParent, pIdxWin, u"HelpIndexPage"_ustr, u"sfx/ui/helpindexpage.ui"_ustr)
391 , m_xIndexEntry(m_xBuilder->weld_entry(u"termentry"_ustr))
392 , m_xIndexList(m_xBuilder->weld_tree_view(u"termlist"_ustr))
393 , m_xOpenBtn(m_xBuilder->weld_button(u"display"_ustr))
394 , aFactoryIdle("sfx2 appl IndexTabPage_Impl Factory")
395 , aAutoCompleteIdle("sfx2 appl IndexTabPage_Impl AutoComplete")
396 , aKeywordTimer("sfx2::IndexTabPage_Impl aKeywordTimer")
397 , bIsActivated(false)
398 , nRowHeight(m_xIndexList->get_height_rows(1))
399 , nAllHeight(0)
400 , nLastCharCode(0)
402 m_xIndexList->set_size_request(m_xIndexList->get_approximate_digit_width() * 30, -1);
404 m_xOpenBtn->connect_clicked(LINK(this, IndexTabPage_Impl, OpenHdl));
405 aFactoryIdle.SetInvokeHandler( LINK(this, IndexTabPage_Impl, IdleHdl ));
406 aAutoCompleteIdle.SetInvokeHandler( LINK(this, IndexTabPage_Impl, AutoCompleteHdl ));
407 aKeywordTimer.SetInvokeHandler( LINK( this, IndexTabPage_Impl, TimeoutHdl ) );
408 m_xIndexList->connect_row_activated(LINK(this, IndexTabPage_Impl, DoubleClickHdl));
409 m_xIndexList->connect_selection_changed(LINK(this, IndexTabPage_Impl, TreeChangeHdl));
410 m_xIndexList->connect_custom_get_size(LINK(this, IndexTabPage_Impl, CustomGetSizeHdl));
411 m_xIndexList->connect_custom_render(LINK(this, IndexTabPage_Impl, CustomRenderHdl));
412 m_xIndexList->set_column_custom_renderer(0, true);
413 m_xIndexList->connect_size_allocate(LINK(this, IndexTabPage_Impl, ResizeHdl));
414 m_xIndexEntry->connect_key_press(LINK(this, IndexTabPage_Impl, KeyInputHdl));
415 m_xIndexEntry->connect_changed(LINK(this, IndexTabPage_Impl, EntryChangeHdl));
416 m_xIndexEntry->connect_activate(LINK(this, IndexTabPage_Impl, ActivateHdl));
419 IMPL_LINK(IndexTabPage_Impl, ResizeHdl, const Size&, rSize, void)
421 nAllHeight = rSize.Height();
424 IMPL_LINK_NOARG(IndexTabPage_Impl, CustomGetSizeHdl, weld::TreeView::get_size_args, Size)
426 return Size(m_xIndexList->get_size_request().Width(), nRowHeight);
429 IMPL_LINK(IndexTabPage_Impl, CustomRenderHdl, weld::TreeView::render_args, aPayload, void)
431 vcl::RenderContext& rRenderContext = std::get<0>(aPayload);
432 const ::tools::Rectangle& rRect = std::get<1>(aPayload);
433 bool bSelected = std::get<2>(aPayload);
434 const OUString& rId = std::get<3>(aPayload);
436 rRenderContext.Push(vcl::PushFlags::TEXTCOLOR);
437 const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
438 if (bSelected)
439 rRenderContext.SetTextColor(rStyleSettings.GetHighlightTextColor());
440 else
441 rRenderContext.SetTextColor(rStyleSettings.GetDialogTextColor());
443 Point aPos(rRect.TopLeft());
444 aPos.AdjustY((rRect.GetHeight() - rRenderContext.GetTextHeight()) / 2);
446 int nIndex = m_xIndexList->find_id(rId);
447 OUString aEntry(m_xIndexList->get_text(nIndex));
449 IndexEntry_Impl* pEntry = weld::fromId<IndexEntry_Impl*>(rId);
450 if (pEntry && pEntry->m_bSubEntry)
452 // indent sub entries
453 aPos.AdjustX(8);
454 sal_Int32 nPos = aEntry.indexOf(';');
455 rRenderContext.DrawText(aPos, (nPos !=-1) ? aEntry.copy(nPos + 1) : aEntry);
457 else
458 rRenderContext.DrawText(aPos, aEntry);
460 rRenderContext.Pop();
463 IMPL_LINK_NOARG(IndexTabPage_Impl, TreeChangeHdl, weld::TreeView&, void)
465 m_xIndexEntry->set_text(m_xIndexList->get_selected_text());
468 IMPL_LINK_NOARG(IndexTabPage_Impl, EntryChangeHdl, weld::Entry&, void)
470 switch (nLastCharCode)
472 case css::awt::Key::DELETE_WORD_BACKWARD:
473 case css::awt::Key::DELETE_WORD_FORWARD:
474 case css::awt::Key::DELETE_TO_BEGIN_OF_LINE:
475 case css::awt::Key::DELETE_TO_END_OF_LINE:
476 case KEY_BACKSPACE:
477 case KEY_DELETE:
478 aAutoCompleteIdle.Stop();
479 break;
480 default:
481 aAutoCompleteIdle.Start();
482 break;
486 IMPL_LINK(IndexTabPage_Impl, KeyInputHdl, const KeyEvent&, rKEvt, bool)
488 const vcl::KeyCode& rKCode = rKEvt.GetKeyCode();
489 if (rKCode.GetModifier()) // only with no modifiers held
490 return false;
492 sal_uInt16 nCode = rKCode.GetCode();
494 if (nCode == KEY_UP || nCode == KEY_PAGEUP ||
495 nCode == KEY_DOWN || nCode == KEY_PAGEDOWN)
497 // disable_notify_events();
498 sal_Int32 nIndex = m_xIndexList->get_selected_index();
499 sal_Int32 nOrigIndex = nIndex;
500 sal_Int32 nCount = m_xIndexList->n_children();
501 if (nIndex == -1)
503 m_xIndexList->set_cursor(0);
504 m_xIndexList->select(0);
505 m_xIndexEntry->set_text(m_xIndexList->get_selected_text());
507 else
509 if (nCode == KEY_UP)
510 --nIndex;
511 else if (nCode == KEY_DOWN)
512 ++nIndex;
513 else if (nCode == KEY_PAGEUP)
515 int nVisRows = nAllHeight / nRowHeight;
516 nIndex -= nVisRows;
518 else if (nCode == KEY_PAGEDOWN)
520 int nVisRows = nAllHeight / nRowHeight;
521 nIndex += nVisRows;
524 if (nIndex < 0)
525 nIndex = 0;
526 if (nIndex >= nCount)
527 nIndex = nCount - 1;
529 if (nIndex != nOrigIndex)
531 m_xIndexList->set_cursor(nIndex);
532 m_xIndexList->select(nIndex);
533 m_xIndexEntry->set_text(m_xIndexList->get_selected_text());
536 // m_xIndexList->grab_focus();
537 // g_signal_emit_by_name(pWidget, "key-press-event", pEvent, &ret);
538 // m_xIndexEntry->set_text(m_xIndexList->get_selected_text());
539 // m_xIndexEntry->grab_focus();
541 m_xIndexEntry->select_region(0, -1);
542 // enable_notify_events();
543 // m_bTreeChange = true;
544 // m_pEntry->fire_signal_changed();
545 // m_bTreeChange = false;
546 return true;
549 nLastCharCode = nCode;
550 return false;
553 IndexTabPage_Impl::~IndexTabPage_Impl()
555 ClearIndex();
558 namespace sfx2 {
560 typedef std::unordered_map< OUString, int > KeywordInfo;
563 void IndexTabPage_Impl::InitializeIndex()
565 weld::WaitObject aWaitCursor(m_pIdxWin->GetFrameWeld());
567 // By now more than 256 equal entries are not allowed
568 sal_Unicode append[256];
569 for(sal_Unicode & k : append)
570 k = ' ';
572 sfx2::KeywordInfo aInfo;
573 m_xIndexList->freeze();
577 OUStringBuffer aURL(HELP_URL + sFactory);
578 AppendConfigToken(aURL, true);
580 Content aCnt( aURL.makeStringAndClear(), Reference< css::ucb::XCommandEnvironment >(), comphelper::getProcessComponentContext() );
581 css::uno::Reference< css::beans::XPropertySetInfo > xInfo = aCnt.getProperties();
582 if ( xInfo->hasPropertyByName( PROPERTY_ANCHORREF ) )
584 css::uno::Sequence< OUString > aPropSeq{ PROPERTY_KEYWORDLIST, PROPERTY_KEYWORDREF,
585 PROPERTY_ANCHORREF, PROPERTY_TITLEREF };
587 // abi: use one possibly remote call only
588 css::uno::Sequence< css::uno::Any > aAnySeq =
589 aCnt.getPropertyValues( aPropSeq );
591 css::uno::Sequence< OUString > aKeywordList;
592 css::uno::Sequence< css::uno::Sequence< OUString > > aKeywordRefList;
593 css::uno::Sequence< css::uno::Sequence< OUString > > aAnchorRefList;
594 css::uno::Sequence< css::uno::Sequence< OUString > > aTitleRefList;
596 if ( ( aAnySeq[0] >>= aKeywordList ) && ( aAnySeq[1] >>= aKeywordRefList ) &&
597 ( aAnySeq[2] >>= aAnchorRefList ) && ( aAnySeq[3] >>= aTitleRefList ) )
599 int ndx,tmp;
600 OUString aIndex, aTempString;
601 sfx2::KeywordInfo::iterator it;
603 for ( int i = 0; i < aKeywordList.getLength(); ++i )
605 // abi: Do not copy, but use references
606 const OUString& aKeywordPair = aKeywordList[i];
607 DBG_ASSERT( !aKeywordPair.isEmpty(), "invalid help index" );
608 const css::uno::Sequence< OUString >& aRefList = aKeywordRefList[i];
609 const css::uno::Sequence< OUString >& aAnchorList = aAnchorRefList[i];
610 const css::uno::Sequence< OUString >& aTitleList = aTitleRefList[i];
612 DBG_ASSERT( aRefList.getLength() == aAnchorList.getLength(),"reference list and title list of different length" );
614 ndx = aKeywordPair.indexOf( ';' );
615 const bool insert = ndx != -1;
617 OUString sId;
619 if ( insert )
621 aTempString = aKeywordPair.copy( 0, ndx );
622 if ( aIndex != aTempString )
624 aIndex = aTempString;
625 it = aInfo.emplace(aTempString, 0).first;
626 sId = weld::toId(new IndexEntry_Impl(OUString(), false));
627 if ( (tmp = it->second++) != 0)
628 m_xIndexList->append(
629 sId, aTempString + std::u16string_view(append, tmp));
630 else
631 m_xIndexList->append(sId, aTempString);
634 else
635 aIndex.clear();
637 sal_uInt32 nRefListLen = aRefList.getLength();
639 DBG_ASSERT( aAnchorList.hasElements(), "*IndexTabPage_Impl::InitializeIndex(): AnchorList is empty!" );
640 DBG_ASSERT( nRefListLen, "*IndexTabPage_Impl::InitializeIndex(): RefList is empty!" );
642 if ( aAnchorList.hasElements() && nRefListLen )
644 if ( aAnchorList[0].getLength() > 0 )
646 sId = weld::toId(new IndexEntry_Impl(aRefList[0] + "#" + aAnchorList[0], insert));
648 else
649 sId = weld::toId(new IndexEntry_Impl(aRefList[0], insert));
652 // Assume the token is trimmed
653 it = aInfo.emplace(aKeywordPair, 0).first;
654 if ((tmp = it->second++) != 0)
655 m_xIndexList->append(sId, aKeywordPair + std::u16string_view(append, tmp));
656 else
657 m_xIndexList->append(sId, aKeywordPair);
659 for ( sal_uInt32 j = 1; j < nRefListLen ; ++j )
661 aTempString = aKeywordPair + " - " + aTitleList[j];
663 if ( aAnchorList[j].getLength() > 0 )
664 sId = weld::toId(new IndexEntry_Impl(aRefList[j] + "#" + aAnchorList[j], insert));
665 else
666 sId = weld::toId(new IndexEntry_Impl(aRefList[j], insert));
668 it = aInfo.emplace(aTempString, 0).first;
669 if ( (tmp = it->second++) != 0 )
670 m_xIndexList->append(
671 sId, aTempString + std::u16string_view(append, tmp));
672 else
673 m_xIndexList->append(sId, aTempString);
679 catch( Exception& )
681 TOOLS_WARN_EXCEPTION( "sfx.appl", "IndexTabPage_Impl::InitializeIndex(): unexpected exception" );
684 m_xIndexList->thaw();
686 if ( !sKeyword.isEmpty() )
687 aKeywordLink.Call( *this );
690 void IndexTabPage_Impl::ClearIndex()
692 const sal_Int32 nCount = m_xIndexList->n_children();
693 for ( sal_Int32 i = 0; i < nCount; ++i )
694 delete weld::fromId<IndexEntry_Impl*>(m_xIndexList->get_id(i));
695 m_xIndexList->clear();
698 IMPL_LINK_NOARG(IndexTabPage_Impl, OpenHdl, weld::Button&, void)
700 aDoubleClickHdl.Call(nullptr);
703 IMPL_LINK_NOARG(IndexTabPage_Impl, ActivateHdl, weld::Entry&, bool)
705 aDoubleClickHdl.Call(nullptr);
706 return true;
709 IMPL_LINK_NOARG(IndexTabPage_Impl, DoubleClickHdl, weld::TreeView&, bool)
711 aDoubleClickHdl.Call(nullptr);
712 return true;
715 IMPL_LINK_NOARG(IndexTabPage_Impl, IdleHdl, Timer*, void)
717 InitializeIndex();
720 int IndexTabPage_Impl::starts_with(const OUString& rStr, int nStartRow, bool bCaseSensitive)
722 const vcl::I18nHelper& rI18nHelper = Application::GetSettings().GetUILocaleI18nHelper();
724 int nRet = nStartRow;
725 int nCount = m_xIndexList->n_children();
726 while (nRet < nCount)
728 OUString aStr(m_xIndexList->get_text(nRet));
729 const bool bMatch = !bCaseSensitive ? rI18nHelper.MatchString(rStr, aStr) : aStr.startsWith(rStr);
730 if (bMatch)
731 return nRet;
732 ++nRet;
735 return -1;
738 IMPL_LINK_NOARG(IndexTabPage_Impl, AutoCompleteHdl, Timer*, void)
740 OUString aStartText = m_xIndexEntry->get_text();
741 int nStartPos, nEndPos;
742 m_xIndexEntry->get_selection_bounds(nStartPos, nEndPos);
743 int nMaxSelection = std::max(nStartPos, nEndPos);
744 if (nMaxSelection != aStartText.getLength())
745 return;
747 int nActive = m_xIndexList->get_selected_index();
748 int nStart = nActive;
750 if (nStart == -1)
751 nStart = 0;
753 // Try match case insensitive from current position
754 int nPos = starts_with(aStartText, nStart, false);
755 if (nPos == -1 && nStart != 0)
757 // Try match case insensitive, but from start
758 nPos = starts_with(aStartText, 0, false);
761 if (nPos == -1)
763 // Try match case sensitive from current position
764 nPos = starts_with(aStartText, nStart, true);
765 if (nPos == -1 && nStart != 0)
767 // Try match case sensitive, but from start
768 nPos = starts_with(aStartText, 0, true);
772 if (nPos != -1)
774 m_xIndexList->set_cursor(nPos);
775 m_xIndexList->select(nPos);
776 OUString aText = m_xIndexList->get_text(nPos);
777 if (aText != aStartText)
778 m_xIndexEntry->set_text(aText);
779 m_xIndexEntry->select_region(aText.getLength(), aStartText.getLength());
783 IMPL_LINK( IndexTabPage_Impl, TimeoutHdl, Timer*, pTimer, void)
785 if(&aKeywordTimer == pTimer && !sKeyword.isEmpty())
786 aKeywordLink.Call(*this);
789 void IndexTabPage_Impl::Activate()
791 if ( !bIsActivated )
793 bIsActivated = true;
794 aFactoryIdle.Start();
798 void IndexTabPage_Impl::SetDoubleClickHdl(const Link<LinkParamNone*, void>& rLink)
800 aDoubleClickHdl = rLink;
803 void IndexTabPage_Impl::SetFactory( const OUString& rFactory )
805 OUString sNewFactory( rFactory );
806 DBG_ASSERT( !sNewFactory.isEmpty(), "empty factory" );
807 bool bValid = m_pIdxWin->IsValidFactory( rFactory );
809 if ( sFactory.isEmpty() && !bValid )
811 sNewFactory = SfxHelp::GetDefaultHelpModule();
812 bValid = true;
815 if ( sNewFactory != sFactory && bValid )
817 sFactory = sNewFactory;
818 ClearIndex();
819 if ( bIsActivated )
820 aFactoryIdle.Start();
824 OUString IndexTabPage_Impl::GetSelectedEntry() const
826 OUString aRet;
827 IndexEntry_Impl* pEntry = weld::fromId<IndexEntry_Impl*>(m_xIndexList->get_id(m_xIndexList->find_text(m_xIndexEntry->get_text())));
828 if (pEntry)
829 aRet = pEntry->m_aURL;
830 return aRet;
833 void IndexTabPage_Impl::SetKeyword( const OUString& rKeyword )
835 sKeyword = rKeyword;
837 if (m_xIndexList->n_children() > 0)
838 aKeywordTimer.Start();
839 else if ( !bIsActivated )
840 aFactoryIdle.Start();
844 bool IndexTabPage_Impl::HasKeyword() const
846 bool bRet = false;
847 if ( !sKeyword.isEmpty() )
849 sal_Int32 nPos = m_xIndexList->find_text( sKeyword );
850 bRet = nPos != -1;
853 return bRet;
857 bool IndexTabPage_Impl::HasKeywordIgnoreCase()
859 bool bRet = false;
860 if ( !sKeyword.isEmpty() )
862 sal_Int32 nEntries = m_xIndexList->n_children();
863 const vcl::I18nHelper& rI18nHelper = Application::GetSettings().GetLocaleI18nHelper();
864 for ( sal_Int32 n = 0; n < nEntries; n++)
866 const OUString sIndexItem {m_xIndexList->get_text(n)};
867 if (rI18nHelper.MatchString( sIndexItem, sKeyword ))
869 sKeyword = sIndexItem;
870 bRet = true;
875 return bRet;
878 void IndexTabPage_Impl::OpenKeyword()
880 if ( !sKeyword.isEmpty() )
882 m_xIndexEntry->set_text(sKeyword);
883 aDoubleClickHdl.Call(nullptr);
884 sKeyword.clear();
888 IMPL_LINK_NOARG(SearchTabPage_Impl, ActivateHdl, weld::ComboBox&, bool)
890 Search();
891 return true;
894 // class SearchTabPage_Impl ----------------------------------------------
896 SearchTabPage_Impl::SearchTabPage_Impl(weld::Widget* pParent, SfxHelpIndexWindow_Impl* pIdxWin)
897 : HelpTabPage_Impl(pParent, pIdxWin, u"HelpSearchPage"_ustr,
898 u"sfx/ui/helpsearchpage.ui"_ustr)
899 , m_xSearchED(m_xBuilder->weld_combo_box(u"search"_ustr))
900 , m_xSearchBtn(m_xBuilder->weld_button(u"find"_ustr))
901 , m_xFullWordsCB(m_xBuilder->weld_check_button(u"completewords"_ustr))
902 , m_xScopeCB(m_xBuilder->weld_check_button(u"headings"_ustr))
903 , m_xResultsLB(m_xBuilder->weld_tree_view(u"results"_ustr))
904 , m_xOpenBtn(m_xBuilder->weld_button(u"display"_ustr))
905 , xBreakIterator(vcl::unohelper::CreateBreakIterator())
907 m_xResultsLB->set_size_request(m_xResultsLB->get_approximate_digit_width() * 30,
908 m_xResultsLB->get_height_rows(15));
910 m_xSearchBtn->connect_clicked(LINK(this, SearchTabPage_Impl, ClickHdl));
911 m_xSearchED->connect_changed(LINK(this, SearchTabPage_Impl, ModifyHdl));
912 m_xSearchED->connect_entry_activate(LINK(this, SearchTabPage_Impl, ActivateHdl));
913 m_xOpenBtn->connect_clicked(LINK(this, SearchTabPage_Impl, OpenHdl));
914 m_xResultsLB->connect_row_activated(LINK(this, SearchTabPage_Impl, DoubleClickHdl));
916 SvtViewOptions aViewOpt( EViewType::TabPage, CONFIGNAME_SEARCHPAGE );
917 if ( aViewOpt.Exists() )
919 OUString aUserData;
920 Any aUserItem = aViewOpt.GetUserItem( USERITEM_NAME );
921 if ( aUserItem >>= aUserData )
923 sal_Int32 nIdx {0};
924 bool bChecked = o3tl::toInt32(o3tl::getToken(aUserData, 0, ';', nIdx)) == 1;
925 m_xFullWordsCB->set_active(bChecked);
926 bChecked = o3tl::toInt32(o3tl::getToken(aUserData, 0, ';', nIdx)) == 1;
927 m_xScopeCB->set_active(bChecked);
929 while ( nIdx > 0 )
931 m_xSearchED->append_text( INetURLObject::decode(
932 o3tl::getToken(aUserData, 0, ';', nIdx),
933 INetURLObject::DecodeMechanism::WithCharset ) );
938 ModifyHdl(*m_xSearchED);
941 SearchTabPage_Impl::~SearchTabPage_Impl()
943 SvtViewOptions aViewOpt( EViewType::TabPage, CONFIGNAME_SEARCHPAGE );
944 OUStringBuffer aUserData =
945 OUString::number(m_xFullWordsCB->get_active() ? 1 : 0) +
946 ";" +
947 OUString::number(m_xScopeCB->get_active() ? 1 : 0);
948 sal_Int32 nCount = std::min(m_xSearchED->get_count(), 10); // save only 10 entries
950 for ( sal_Int32 i = 0; i < nCount; ++i )
952 aUserData.append(";" +
953 INetURLObject::encode(
954 m_xSearchED->get_text(i),
955 INetURLObject::PART_UNO_PARAM_VALUE,
956 INetURLObject::EncodeMechanism::All ));
959 Any aUserItem( aUserData.makeStringAndClear() );
960 aViewOpt.SetUserItem( USERITEM_NAME, aUserItem );
962 m_xSearchED.reset();
963 m_xSearchBtn.reset();
964 m_xFullWordsCB.reset();
965 m_xScopeCB.reset();
966 m_xResultsLB.reset();
967 m_xOpenBtn.reset();
970 void SearchTabPage_Impl::ClearSearchResults()
972 m_xResultsLB->clear();
975 void SearchTabPage_Impl::RememberSearchText( const OUString& rSearchText )
977 for (sal_Int32 i = 0, nEntryCount = m_xSearchED->get_count(); i < nEntryCount; ++i)
979 if (rSearchText == m_xSearchED->get_text(i))
981 m_xSearchED->remove(i);
982 break;
986 m_xSearchED->insert_text(0, rSearchText);
989 IMPL_LINK_NOARG(SearchTabPage_Impl, ClickHdl, weld::Button&, void)
991 Search();
994 void SearchTabPage_Impl::Search()
996 OUString aSearchText = comphelper::string::strip(m_xSearchED->get_active_text(), ' ');
997 if ( aSearchText.isEmpty() )
998 return;
1000 std::unique_ptr<weld::WaitObject> xWaitCursor(new weld::WaitObject(m_pIdxWin->GetFrameWeld()));
1001 ClearSearchResults();
1002 RememberSearchText( aSearchText );
1003 OUStringBuffer aSearchURL(HELP_URL + aFactory + HELP_SEARCH_TAG);
1004 if (!m_xFullWordsCB->get_active())
1005 aSearchText = sfx2::PrepareSearchString( aSearchText, xBreakIterator, true );
1006 aSearchURL.append(aSearchText);
1007 AppendConfigToken(aSearchURL, false);
1008 if (m_xScopeCB->get_active())
1009 aSearchURL.append("&Scope=Heading");
1010 std::vector< OUString > aFactories = SfxContentHelper::GetResultSet(aSearchURL.makeStringAndClear());
1011 for (const OUString & rRow : aFactories)
1013 sal_Int32 nIdx = 0;
1014 OUString aTitle = rRow.getToken(0, '\t', nIdx);
1015 OUString sURL(rRow.getToken(1, '\t', nIdx));
1016 m_xResultsLB->append(sURL, aTitle);
1018 xWaitCursor.reset();
1020 if ( aFactories.empty() )
1022 std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_xContainer.get(),
1023 VclMessageType::Info, VclButtonsType::Ok,
1024 SfxResId(STR_INFO_NOSEARCHRESULTS)));
1025 xBox->run();
1029 IMPL_LINK_NOARG(SearchTabPage_Impl, OpenHdl, weld::Button&, void)
1031 aDoubleClickHdl.Call(nullptr);
1034 IMPL_LINK(SearchTabPage_Impl, ModifyHdl, weld::ComboBox&, rComboBox, void)
1036 OUString aSearchText = comphelper::string::strip(m_xSearchED->get_active_text(), ' ');
1037 m_xSearchBtn->set_sensitive(!aSearchText.isEmpty());
1039 if (rComboBox.changed_by_direct_pick())
1040 Search();
1043 IMPL_LINK_NOARG(SearchTabPage_Impl, DoubleClickHdl, weld::TreeView&, bool)
1045 aDoubleClickHdl.Call(nullptr);
1046 return true;
1049 void SearchTabPage_Impl::SetDoubleClickHdl(const Link<LinkParamNone*, void>& rLink)
1051 aDoubleClickHdl = rLink;
1054 OUString SearchTabPage_Impl::GetSelectedEntry() const
1056 return m_xResultsLB->get_selected_id();
1059 void SearchTabPage_Impl::ClearPage()
1061 ClearSearchResults();
1062 m_xSearchED->set_entry_text(OUString());
1065 bool SearchTabPage_Impl::OpenKeyword( const OUString& rKeyword )
1067 bool bRet = false;
1068 m_xSearchED->set_entry_text(rKeyword);
1069 Search();
1070 if (m_xResultsLB->n_children() > 0)
1072 // found keyword -> open it
1073 m_xResultsLB->select(0);
1074 OpenHdl(*m_xOpenBtn);
1075 bRet = true;
1077 return bRet;
1080 // class BookmarksTabPage_Impl -------------------------------------------
1082 void BookmarksTabPage_Impl::DoAction(std::u16string_view rAction)
1084 if (rAction == u"display")
1085 aDoubleClickHdl.Call(nullptr);
1086 else if (rAction == u"rename")
1088 sal_Int32 nPos = m_xBookmarksBox->get_selected_index();
1089 if (nPos != -1)
1091 SfxAddHelpBookmarkDialog_Impl aDlg(m_xBookmarksBox.get(), true);
1092 aDlg.SetTitle(m_xBookmarksBox->get_text(nPos));
1093 if (aDlg.run() == RET_OK)
1095 OUString sURL = m_xBookmarksBox->get_id(nPos);
1096 m_xBookmarksBox->remove(nPos);
1097 m_xBookmarksBox->append(sURL, aDlg.GetTitle(),
1098 SvFileInformationManager::GetImageId(INetURLObject(rtl::Concat2View(IMAGE_URL+INetURLObject(sURL).GetHost()))));
1099 m_xBookmarksBox->select(m_xBookmarksBox->n_children() - 1);
1103 else if (rAction == u"delete")
1105 sal_Int32 nPos = m_xBookmarksBox->get_selected_index();
1106 if (nPos != -1)
1108 m_xBookmarksBox->remove(nPos);
1109 const sal_Int32 nCount = m_xBookmarksBox->n_children();
1110 if (nCount)
1112 if (nPos >= nCount)
1113 nPos = nCount - 1;
1114 m_xBookmarksBox->select(nPos);
1120 IMPL_LINK(BookmarksTabPage_Impl, CommandHdl, const CommandEvent&, rCEvt, bool)
1122 if (rCEvt.GetCommand() != CommandEventId::ContextMenu)
1123 return false;
1125 std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(m_xBookmarksBox.get(), u"sfx/ui/bookmarkmenu.ui"_ustr));
1126 std::unique_ptr<weld::Menu> xMenu = xBuilder->weld_menu(u"menu"_ustr);
1128 OUString sIdent = xMenu->popup_at_rect(m_xBookmarksBox.get(), ::tools::Rectangle(rCEvt.GetMousePosPixel(), Size(1,1)));
1129 if (!sIdent.isEmpty())
1130 DoAction(sIdent);
1131 return true;
1134 IMPL_LINK(BookmarksTabPage_Impl, KeyInputHdl, const KeyEvent&, rKEvt, bool)
1136 bool bHandled = false;
1137 sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode();
1138 if (KEY_DELETE == nCode && m_xBookmarksBox->n_children() > 0)
1140 DoAction(u"delete");
1141 bHandled = true;
1143 return bHandled;
1146 // class BookmarksTabPage_Impl -------------------------------------------
1147 BookmarksTabPage_Impl::BookmarksTabPage_Impl(weld::Widget* pParent, SfxHelpIndexWindow_Impl* _pIdxWin)
1148 : HelpTabPage_Impl(pParent, _pIdxWin, u"HelpBookmarkPage"_ustr,
1149 u"sfx/ui/helpbookmarkpage.ui"_ustr)
1150 , m_xBookmarksBox(m_xBuilder->weld_tree_view(u"bookmarks"_ustr))
1151 , m_xBookmarksPB(m_xBuilder->weld_button(u"display"_ustr))
1153 m_xBookmarksBox->set_size_request(m_xBookmarksBox->get_approximate_digit_width() * 30,
1154 m_xBookmarksBox->get_height_rows(20));
1156 m_xBookmarksPB->connect_clicked( LINK(this, BookmarksTabPage_Impl, OpenHdl));
1157 m_xBookmarksBox->connect_row_activated(LINK(this, BookmarksTabPage_Impl, DoubleClickHdl));
1158 m_xBookmarksBox->connect_popup_menu(LINK(this, BookmarksTabPage_Impl, CommandHdl));
1159 m_xBookmarksBox->connect_key_press(LINK(this, BookmarksTabPage_Impl, KeyInputHdl));
1161 // load bookmarks from configuration
1162 const std::vector< SvtHistoryOptions::HistoryItem > aBookmarkSeq = SvtHistoryOptions::GetList( EHistoryType::HelpBookmarks );
1163 for ( const auto& rBookmark : aBookmarkSeq )
1165 AddBookmarks( rBookmark.sTitle, rBookmark.sURL );
1169 BookmarksTabPage_Impl::~BookmarksTabPage_Impl()
1171 // save bookmarks to configuration
1172 SvtHistoryOptions::Clear( EHistoryType::HelpBookmarks );
1173 const sal_Int32 nCount = m_xBookmarksBox->n_children();
1174 for (sal_Int32 i = 0; i < nCount; ++i)
1176 SvtHistoryOptions::AppendItem(EHistoryType::HelpBookmarks, m_xBookmarksBox->get_id(i), u""_ustr,
1177 m_xBookmarksBox->get_text(i), std::nullopt, std::nullopt);
1180 m_xBookmarksBox.reset();
1181 m_xBookmarksPB.reset();
1184 IMPL_LINK_NOARG(BookmarksTabPage_Impl, OpenHdl, weld::Button&, void)
1186 aDoubleClickHdl.Call(nullptr);
1189 IMPL_LINK_NOARG(BookmarksTabPage_Impl, DoubleClickHdl, weld::TreeView&, bool)
1191 aDoubleClickHdl.Call(nullptr);
1192 return true;
1195 void BookmarksTabPage_Impl::SetDoubleClickHdl(const Link<LinkParamNone*, void>& rLink)
1197 aDoubleClickHdl = rLink;
1200 OUString BookmarksTabPage_Impl::GetSelectedEntry() const
1202 return m_xBookmarksBox->get_selected_id();
1205 void BookmarksTabPage_Impl::AddBookmarks(const OUString& rTitle, const OUString& rURL)
1207 const OUString aImageURL {IMAGE_URL + INetURLObject(rURL).GetHost()};
1208 m_xBookmarksBox->append(rURL, rTitle, SvFileInformationManager::GetImageId(INetURLObject(aImageURL)));
1211 OUString SfxHelpWindow_Impl::buildHelpURL(std::u16string_view sFactory ,
1212 std::u16string_view sContent ,
1213 std::u16string_view sAnchor)
1215 OUStringBuffer sHelpURL(256);
1216 sHelpURL.append(HELP_URL + sFactory + sContent);
1217 AppendConfigToken(sHelpURL, true/*bUseQuestionMark*/);
1218 if (!sAnchor.empty())
1219 sHelpURL.append(sAnchor);
1220 return sHelpURL.makeStringAndClear();
1223 void SfxHelpWindow_Impl::loadHelpContent(const OUString& sHelpURL, bool bAddToHistory)
1225 Reference< XComponentLoader > xLoader(getTextFrame(), UNO_QUERY);
1226 if (!xLoader.is())
1227 return;
1229 // If a print job runs do not open a new page
1230 Reference< XFrame2 > xTextFrame = pTextWin->getFrame();
1231 Reference< XController > xTextController ;
1232 if (xTextFrame.is())
1233 xTextController = xTextFrame->getController ();
1234 if ( xTextController.is() && !xTextController->suspend( true ) )
1236 xTextController->suspend( false );
1237 return;
1240 // save url to history
1241 if (bAddToHistory)
1242 pHelpInterceptor->addURL(sHelpURL);
1244 if ( !IsWait() )
1245 EnterWait();
1246 bool bSuccess = false;
1247 // TODO implement locale fallback ... see below while(true)
1251 Reference< XComponent > xContent = xLoader->loadComponentFromURL(sHelpURL, u"_self"_ustr, 0, Sequence< PropertyValue >());
1252 if (xContent.is())
1254 bSuccess = true;
1257 catch(const RuntimeException&)
1258 { throw; }
1259 catch(const Exception&)
1260 { /*break;*/ }
1262 /* TODO try next locale ...
1263 no further locale available? => break loop and show error page
1266 openDone(sHelpURL, bSuccess);
1267 if ( IsWait() )
1268 LeaveWait();
1271 IMPL_LINK(SfxHelpIndexWindow_Impl, ActivatePageHdl, const OUString&, rPage, void)
1273 GetPage(rPage)->Activate();
1276 SfxHelpIndexWindow_Impl::SfxHelpIndexWindow_Impl(SfxHelpWindow_Impl* _pParent, weld::Container* pContainer)
1277 : m_xBuilder(Application::CreateBuilder(pContainer, u"sfx/ui/helpcontrol.ui"_ustr))
1278 , m_xContainer(m_xBuilder->weld_container(u"HelpControl"_ustr))
1279 , m_xActiveLB(m_xBuilder->weld_combo_box(u"active"_ustr))
1280 , m_xTabCtrl(m_xBuilder->weld_notebook(u"tabcontrol"_ustr))
1281 , aIdle("sfx2 appl SfxHelpIndexWindow_Impl")
1282 , aIndexKeywordLink(LINK(this, SfxHelpIndexWindow_Impl, KeywordHdl))
1283 , pParentWin(_pParent)
1284 , bIsInitDone(false)
1286 // create the pages
1287 GetContentPage();
1288 GetIndexPage();
1289 GetSearchPage();
1290 GetBookmarksPage();
1292 OUString sPageId(u"index"_ustr);
1293 SvtViewOptions aViewOpt( EViewType::TabDialog, CONFIGNAME_INDEXWIN );
1294 if ( aViewOpt.Exists() )
1296 OUString sSavedPageId = aViewOpt.GetPageID();
1297 if (m_xTabCtrl->get_page_index(sSavedPageId) != -1)
1298 sPageId = sSavedPageId;
1300 m_xTabCtrl->set_current_page(sPageId);
1301 ActivatePageHdl(sPageId);
1302 m_xActiveLB->connect_changed(LINK(this, SfxHelpIndexWindow_Impl, SelectHdl));
1304 m_xTabCtrl->connect_enter_page(LINK(this, SfxHelpIndexWindow_Impl, ActivatePageHdl));
1306 aIdle.SetInvokeHandler( LINK( this, SfxHelpIndexWindow_Impl, InitHdl ) );
1307 aIdle.Start();
1309 m_xContainer->show();
1312 SfxHelpIndexWindow_Impl::~SfxHelpIndexWindow_Impl()
1314 SvtViewOptions aViewOpt(EViewType::TabDialog, CONFIGNAME_INDEXWIN);
1315 aViewOpt.SetPageID(m_xTabCtrl->get_current_page_ident());
1317 xCPage.reset();
1318 xIPage.reset();
1319 xSPage.reset();
1320 xBPage.reset();
1323 void SfxHelpIndexWindow_Impl::Initialize()
1325 OUStringBuffer aHelpURL(HELP_URL);
1326 AppendConfigToken(aHelpURL, true);
1327 std::vector<OUString> aFactories = SfxContentHelper::GetResultSet(aHelpURL.makeStringAndClear());
1328 for (const OUString & rRow : aFactories)
1330 sal_Int32 nIdx = 0;
1331 OUString aTitle = rRow.getToken( 0, '\t', nIdx ); // token 0
1332 std::u16string_view aURL = o3tl::getToken(rRow, 1, '\t', nIdx ); // token 2
1333 OUString aFactory(INetURLObject(aURL).GetHost());
1334 m_xActiveLB->append(aFactory, aTitle);
1337 if (m_xActiveLB->get_active() == -1)
1338 SetActiveFactory();
1341 void SfxHelpIndexWindow_Impl::SetActiveFactory()
1343 DBG_ASSERT( xIPage, "index page not initialized" );
1344 if (!bIsInitDone && !m_xActiveLB->get_count())
1346 aIdle.Stop();
1347 InitHdl( nullptr );
1350 for (sal_Int32 i = 0, nEntryCount = m_xActiveLB->get_count(); i < nEntryCount; ++i)
1352 OUString aFactory = m_xActiveLB->get_id(i);
1353 aFactory = aFactory.toAsciiLowerCase();
1354 if (aFactory == xIPage->GetFactory())
1356 if (m_xActiveLB->get_active() != i)
1358 m_xActiveLB->set_active(i);
1359 aSelectFactoryLink.Call(nullptr);
1361 break;
1366 HelpTabPage_Impl* SfxHelpIndexWindow_Impl::GetPage(std::u16string_view rName)
1368 HelpTabPage_Impl* pPage = nullptr;
1370 if (rName == u"contents")
1371 pPage = GetContentPage();
1372 else if (rName == u"index")
1373 pPage = GetIndexPage();
1374 else if (rName == u"find")
1375 pPage = GetSearchPage();
1376 else if (rName == u"bookmarks")
1377 pPage = GetBookmarksPage();
1379 assert(pPage && "SfxHelpIndexWindow_Impl::GetCurrentPage(): no current page");
1381 return pPage;
1384 IMPL_LINK_NOARG(SfxHelpIndexWindow_Impl, SelectHdl, weld::ComboBox&, void)
1386 aIdle.Start();
1389 IMPL_LINK_NOARG(SfxHelpIndexWindow_Impl, InitHdl, Timer *, void)
1391 bIsInitDone = true;
1392 Initialize();
1394 // now use the timer for selection
1395 aIdle.SetInvokeHandler( LINK( this, SfxHelpIndexWindow_Impl, SelectFactoryHdl ) );
1396 aIdle.SetPriority( TaskPriority::LOWEST );
1399 IMPL_LINK_NOARG(SfxHelpIndexWindow_Impl, SelectFactoryHdl, Timer *, void)
1401 OUString aFactory = m_xActiveLB->get_active_id();
1402 if (!aFactory.isEmpty())
1404 SetFactory(aFactory.toAsciiLowerCase(), false);
1405 aSelectFactoryLink.Call(this);
1409 IMPL_LINK_NOARG(SfxHelpIndexWindow_Impl, KeywordHdl, IndexTabPage_Impl&, void)
1411 // keyword found on index?
1412 bool bIndex = xIPage->HasKeyword();
1414 if( !bIndex)
1415 bIndex = xIPage->HasKeywordIgnoreCase();
1416 // then set index or search page as current.
1417 OUString sPageId = bIndex ? u"index"_ustr : u"find"_ustr;
1418 if (sPageId != m_xTabCtrl->get_current_page_ident())
1419 m_xTabCtrl->set_current_page(sPageId);
1421 // at last we open the keyword
1422 if ( bIndex )
1423 xIPage->OpenKeyword();
1424 else if ( !xSPage->OpenKeyword( sKeyword ) )
1425 pParentWin->ShowStartPage();
1428 IMPL_LINK_NOARG(SfxHelpIndexWindow_Impl, IndexTabPageDoubleClickHdl, LinkParamNone*, void)
1430 aPageDoubleClickLink.Call(nullptr);
1433 void SfxHelpIndexWindow_Impl::SetDoubleClickHdl(const Link<LinkParamNone*, void>& rLink)
1435 aPageDoubleClickLink = rLink;
1438 IMPL_LINK_NOARG(SfxHelpIndexWindow_Impl, ContentTabPageDoubleClickHdl, LinkParamNone*, void)
1440 aPageDoubleClickLink.Call(nullptr);
1443 IMPL_LINK_NOARG(SfxHelpIndexWindow_Impl, TabPageDoubleClickHdl, LinkParamNone*, void)
1445 aPageDoubleClickLink.Call(nullptr);
1448 void SfxHelpIndexWindow_Impl::SetFactory( const OUString& rFactory, bool bActive )
1450 if ( !rFactory.isEmpty() )
1452 GetIndexPage()->SetFactory( rFactory );
1453 // the index page made a check if rFactory is valid,
1454 // so the index page always returns a valid factory
1455 GetSearchPage()->SetFactory( GetIndexPage()->GetFactory() );
1456 if ( bActive )
1457 SetActiveFactory();
1461 OUString SfxHelpIndexWindow_Impl::GetSelectedEntry() const
1463 OUString sRet;
1465 OUString sName(m_xTabCtrl->get_current_page_ident());
1467 if (sName == "contents")
1469 sRet = xCPage->GetSelectedEntry();
1471 else if (sName == "index")
1473 sRet = xIPage->GetSelectedEntry();
1475 else if (sName == "find")
1477 sRet = xSPage->GetSelectedEntry();
1479 else if (sName == "bookmarks")
1481 sRet = xBPage->GetSelectedEntry();
1484 return sRet;
1487 void SfxHelpIndexWindow_Impl::AddBookmarks( const OUString& rTitle, const OUString& rURL )
1489 GetBookmarksPage()->AddBookmarks( rTitle, rURL );
1492 bool SfxHelpIndexWindow_Impl::IsValidFactory( std::u16string_view _rFactory )
1494 bool bValid = false;
1495 for (sal_Int32 i = 0, nEntryCount = m_xActiveLB->get_count(); i < nEntryCount; ++i)
1497 OUString aFactory = m_xActiveLB->get_id(i);
1498 if (aFactory == _rFactory)
1500 bValid = true;
1501 break;
1504 return bValid;
1507 void SfxHelpIndexWindow_Impl::ClearSearchPage()
1509 if ( xSPage )
1510 xSPage->ClearPage();
1513 void SfxHelpIndexWindow_Impl::GrabFocusBack()
1515 OUString sName(m_xTabCtrl->get_current_page_ident());
1517 if (sName == "contents" && xCPage)
1518 xCPage->SetFocusOnBox();
1519 else if (sName == "index" && xIPage)
1520 xIPage->SetFocusOnBox();
1521 else if (sName == "find" && xSPage)
1522 xSPage->SetFocusOnBox();
1523 else if (sName == "bookmarks" && xBPage)
1524 xBPage->SetFocusOnBox();
1527 bool SfxHelpIndexWindow_Impl::HasFocusOnEdit() const
1529 bool bRet = false;
1530 OUString sName(m_xTabCtrl->get_current_page_ident());
1531 if (sName == "index" && xIPage)
1532 bRet = xIPage->HasFocusOnEdit();
1533 else if (sName == "find" && xSPage)
1534 bRet = xSPage->HasFocusOnEdit();
1535 return bRet;
1538 OUString SfxHelpIndexWindow_Impl::GetSearchText() const
1540 OUString sRet;
1541 OUString sName(m_xTabCtrl->get_current_page_ident());
1542 if (sName == "find" && xSPage)
1543 sRet = xSPage->GetSearchText();
1544 return sRet;
1547 bool SfxHelpIndexWindow_Impl::IsFullWordSearch() const
1549 bool bRet = false;
1550 OUString sName(m_xTabCtrl->get_current_page_ident());
1551 if (sName == "find" && xSPage)
1552 bRet = xSPage->IsFullWordSearch();
1553 return bRet;
1556 void SfxHelpIndexWindow_Impl::OpenKeyword( const OUString& rKeyword )
1558 sKeyword = rKeyword;
1559 DBG_ASSERT( xIPage, "invalid index page" );
1560 xIPage->SetKeyword( sKeyword );
1563 void SfxHelpIndexWindow_Impl::SelectExecutableEntry()
1565 OUString sName(m_xTabCtrl->get_current_page_ident());
1566 if (sName == "index" && xIPage )
1567 xIPage->SelectExecutableEntry();
1570 weld::Window* SfxHelpIndexWindow_Impl::GetFrameWeld() const
1572 return pParentWin->GetFrameWeld();
1575 // class TextWin_Impl ----------------------------------------------------
1576 TextWin_Impl::TextWin_Impl( vcl::Window* p ) : DockingWindow( p, 0 )
1580 bool TextWin_Impl::EventNotify( NotifyEvent& rNEvt )
1582 if( ( rNEvt.GetType() == NotifyEventType::KEYINPUT ) && rNEvt.GetKeyEvent()->GetKeyCode().GetCode() == KEY_TAB )
1583 return GetParent()->EventNotify( rNEvt );
1584 else
1585 return DockingWindow::EventNotify( rNEvt );
1589 // remove docking area acceptor from layoutmanager, so it will not layout anything further .-)
1590 static void lcl_disableLayoutOfFrame(const Reference< XFrame2 >& xFrame)
1592 xFrame->setLayoutManager( Reference< XLayoutManager >() );
1595 // class SfxHelpTextWindow_Impl ------------------------------------------
1597 SfxHelpTextWindow_Impl::SfxHelpTextWindow_Impl(SfxHelpWindow_Impl* pHelpWin, weld::Builder& rBuilder, vcl::Window* pParent) :
1599 Window( pParent, WB_CLIPCHILDREN | WB_TABSTOP | WB_DIALOGCONTROL ),
1601 xToolBox ( rBuilder.weld_toolbar(u"toolbar"_ustr) ),
1602 xOnStartupCB ( rBuilder.weld_check_button(u"checkbutton"_ustr) ),
1603 xMenu ( rBuilder.weld_menu(u"menu"_ustr) ),
1604 aSelectIdle ( "sfx2 appl SfxHelpTextWindow_Impl Select" ),
1605 aIndexOnImage ( BMP_HELP_TOOLBOX_INDEX_ON ),
1606 aIndexOffImage ( BMP_HELP_TOOLBOX_INDEX_OFF ),
1607 aIndexOnText ( SfxResId( STR_HELP_BUTTON_INDEX_ON ) ),
1608 aIndexOffText ( SfxResId( STR_HELP_BUTTON_INDEX_OFF ) ),
1609 aOnStartupText ( SfxResId( RID_HELP_ONSTARTUP_TEXT ) ),
1610 xHelpWin ( pHelpWin ),
1611 pTextWin ( VclPtr<TextWin_Impl>::Create( this ) ),
1612 bIsDebug ( false ),
1613 bIsIndexOn ( false ),
1614 bIsInClose ( false ),
1615 bIsFullWordSearch ( false )
1617 xFrame = Frame::create( ::comphelper::getProcessComponentContext() );
1618 xFrame->initialize( VCLUnoHelper::GetInterface ( pTextWin ) );
1619 xFrame->setName( u"OFFICE_HELP"_ustr );
1620 lcl_disableLayoutOfFrame(xFrame);
1622 xToolBox->set_help_id(HID_HELP_TOOLBOX);
1624 xToolBox->set_item_tooltip_text(u"index"_ustr, aIndexOffText );
1625 xToolBox->set_item_help_id(u"index"_ustr, HID_HELP_TOOLBOXITEM_INDEX);
1626 xToolBox->set_item_help_id(u"backward"_ustr, HID_HELP_TOOLBOXITEM_BACKWARD);
1627 xToolBox->set_item_help_id(u"forward"_ustr, HID_HELP_TOOLBOXITEM_FORWARD);
1628 xToolBox->set_item_help_id(u"start"_ustr, HID_HELP_TOOLBOXITEM_START);
1629 xToolBox->set_item_help_id(u"print"_ustr, HID_HELP_TOOLBOXITEM_PRINT);
1630 xToolBox->set_item_help_id(u"bookmarks"_ustr, HID_HELP_TOOLBOXITEM_BOOKMARKS );
1631 xToolBox->set_item_help_id(u"searchdialog"_ustr, HID_HELP_TOOLBOXITEM_SEARCHDIALOG);
1633 InitToolBoxImages();
1634 InitOnStartupBox();
1635 xOnStartupCB->connect_toggled(LINK(this, SfxHelpTextWindow_Impl, CheckHdl));
1637 aSelectIdle.SetInvokeHandler( LINK( this, SfxHelpTextWindow_Impl, SelectHdl ) );
1638 aSelectIdle.SetPriority( TaskPriority::LOWEST );
1640 char* pEnv = getenv( "help_debug" );
1641 if ( pEnv )
1642 bIsDebug = true;
1644 SvtMiscOptions().AddListenerLink( LINK( this, SfxHelpTextWindow_Impl, NotifyHdl ) );
1647 SfxHelpTextWindow_Impl::~SfxHelpTextWindow_Impl()
1649 disposeOnce();
1652 void SfxHelpTextWindow_Impl::dispose()
1654 bIsInClose = true;
1655 SvtMiscOptions().RemoveListenerLink( LINK( this, SfxHelpTextWindow_Impl, NotifyHdl ) );
1656 m_xSrchDlg.reset();
1657 xToolBox.reset();
1658 xOnStartupCB.reset();
1659 xHelpWin.clear();
1660 pTextWin.disposeAndClear();
1661 vcl::Window::dispose();
1664 bool SfxHelpTextWindow_Impl::HasSelection() const
1666 // is there any selection in the text and not only a cursor?
1667 bool bRet = false;
1668 Reference < XTextRange > xRange = getCursor();
1669 if ( xRange.is() )
1671 Reference < XText > xText = xRange->getText();
1672 Reference < XTextCursor > xCursor = xText->createTextCursorByRange( xRange );
1673 bRet = !xCursor->isCollapsed();
1676 return bRet;
1679 void SfxHelpTextWindow_Impl::InitToolBoxImages()
1681 xToolBox->set_item_icon_name(u"index"_ustr, bIsIndexOn ? aIndexOffImage : aIndexOnImage);
1684 void SfxHelpTextWindow_Impl::InitOnStartupBox()
1686 sCurrentFactory = SfxHelp::GetCurrentModuleIdentifier();
1688 const Reference< XComponentContext >& xContext = ::comphelper::getProcessComponentContext();
1689 const OUString sPath { PATH_OFFICE_FACTORIES + sCurrentFactory };
1691 // Attention: This check boy knows two states:
1692 // 1) Reading of the config key fails with an exception or by getting an empty Any (!) => check box must be hidden
1693 // 2) We read sal_True/sal_False => check box must be shown and enabled/disabled
1695 bool bHideBox = true;
1696 bool bHelpAtStartup = false;
1699 xConfiguration = ConfigurationHelper::openConfig(
1700 xContext, PACKAGE_SETUP, EConfigurationModes::Standard );
1701 if ( xConfiguration.is() )
1703 Any aAny = ConfigurationHelper::readRelativeKey( xConfiguration, sPath, KEY_HELP_ON_OPEN );
1704 if (aAny >>= bHelpAtStartup)
1705 bHideBox = false;
1708 catch( Exception& )
1710 bHideBox = true;
1713 if ( bHideBox )
1714 xOnStartupCB->hide();
1715 else
1717 // detect module name
1718 OUString sModuleName;
1720 if ( xConfiguration.is() )
1722 OUString sTemp;
1725 Any aAny = ConfigurationHelper::readRelativeKey( xConfiguration, sPath, KEY_UI_NAME );
1726 aAny >>= sTemp;
1728 catch( Exception const & )
1730 TOOLS_WARN_EXCEPTION( "sfx.appl", "SfxHelpTextWindow_Impl::InitOnStartupBox()" );
1732 sModuleName = sTemp;
1735 if ( !sModuleName.isEmpty() )
1737 // set module name in checkbox text
1738 xOnStartupCB->set_label(aOnStartupText.replaceFirst("%MODULENAME", sModuleName));
1739 // and show it
1740 xOnStartupCB->show();
1741 // set check state
1742 xOnStartupCB->set_active(bHelpAtStartup);
1743 xOnStartupCB->save_state();
1748 Reference< XBreakIterator > const & SfxHelpTextWindow_Impl::GetBreakIterator()
1750 if ( !xBreakIterator.is() )
1751 xBreakIterator = vcl::unohelper::CreateBreakIterator();
1752 DBG_ASSERT( xBreakIterator.is(), "Could not create BreakIterator" );
1753 return xBreakIterator;
1756 Reference< XTextRange > SfxHelpTextWindow_Impl::getCursor() const
1758 // return the current cursor
1759 Reference< XTextRange > xCursor;
1763 Reference < XSelectionSupplier > xSelSup( xFrame->getController(), UNO_QUERY );
1764 if ( xSelSup.is() )
1766 Any aAny = xSelSup->getSelection();
1767 Reference < XIndexAccess > xSelection;
1768 if ( aAny >>= xSelection )
1770 if ( xSelection->getCount() == 1 )
1772 aAny = xSelection->getByIndex(0);
1773 aAny >>= xCursor;
1778 catch( Exception& )
1780 TOOLS_WARN_EXCEPTION( "sfx.appl", "SfxHelpTextWindow_Impl::getCursor(): unexpected exception" );
1783 return xCursor;
1787 bool SfxHelpTextWindow_Impl::isHandledKey( const vcl::KeyCode& _rKeyCode )
1789 bool bRet = false;
1790 sal_uInt16 nCode = _rKeyCode.GetCode();
1792 // the keys <CTRL><A> (select all), <CTRL><C> (copy),
1793 // <CTRL><F> (find), <CTRL><P> (print) and <CTRL><W> (close window)
1794 // were handled in help
1795 if ( _rKeyCode.IsMod1() &&
1796 ( KEY_A == nCode || KEY_C == nCode || KEY_F == nCode || KEY_P == nCode || KEY_W == nCode ) )
1798 if ( KEY_F == nCode )
1799 DoSearch();
1800 else
1801 bRet = true;
1804 return bRet;
1808 IMPL_LINK_NOARG(SfxHelpTextWindow_Impl, SelectHdl, Timer *, void)
1812 // select the words, which are equal to the search text of the search page
1813 Reference < XController > xController = xFrame->getController();
1814 if ( xController.is() )
1816 // get document
1817 Reference < XSearchable > xSearchable( xController->getModel(), UNO_QUERY );
1818 if ( xSearchable.is() )
1820 // create descriptor, set string and find all words
1821 Reference < XSearchDescriptor > xSrchDesc = xSearchable->createSearchDescriptor();
1822 xSrchDesc->setPropertyValue( u"SearchRegularExpression"_ustr, Any( true ) );
1823 if ( bIsFullWordSearch )
1824 xSrchDesc->setPropertyValue( u"SearchWords"_ustr, Any( true ) );
1826 xSrchDesc->setSearchString( sfx2::PrepareSearchString( aSearchText, GetBreakIterator(), false ) );
1827 Reference< XIndexAccess > xSelection = xSearchable->findAll( xSrchDesc );
1829 // then select all found words
1830 Reference < XSelectionSupplier > xSelectionSup( xController, UNO_QUERY );
1831 if ( xSelectionSup.is() )
1833 xSelectionSup->select( Any(xSelection) );
1838 catch( Exception& )
1840 TOOLS_WARN_EXCEPTION( "sfx.appl", "SfxHelpTextWindow_Impl::SelectHdl(): unexpected exception" );
1845 IMPL_LINK_NOARG( SfxHelpTextWindow_Impl, NotifyHdl, LinkParamNone*, void )
1847 InitToolBoxImages();
1848 Resize();
1851 IMPL_LINK( SfxHelpTextWindow_Impl, FindHdl, sfx2::SearchDialog&, rDlg, void )
1853 FindHdl(&rDlg);
1855 void SfxHelpTextWindow_Impl::FindHdl(sfx2::SearchDialog* pDlg)
1859 // select the words, which are equal to the search text of the search page
1860 Reference < XController > xController = xFrame->getController();
1861 if ( xController.is() )
1863 // get document
1864 Reference < XSearchable > xSearchable( xController->getModel(), UNO_QUERY );
1865 if ( xSearchable.is() )
1867 bool bWrapAround = ( nullptr == pDlg );
1868 if ( bWrapAround )
1869 pDlg = m_xSrchDlg.get();
1870 assert(pDlg && "invalid search dialog");
1872 // create descriptor, set string and find all words
1873 Reference < XSearchDescriptor > xSrchDesc = xSearchable->createSearchDescriptor();
1874 xSrchDesc->setPropertyValue( u"SearchWords"_ustr, Any(pDlg->IsOnlyWholeWords()) );
1875 xSrchDesc->setPropertyValue( u"SearchCaseSensitive"_ustr, Any(pDlg->IsMarchCase()) );
1876 xSrchDesc->setPropertyValue( u"SearchBackwards"_ustr, Any(pDlg->IsSearchBackwards()) );
1877 xSrchDesc->setSearchString( pDlg->GetSearchText() );
1878 Reference< XInterface > xSelection;
1879 Reference< XTextRange > xCursor = getCursor();
1881 if ( xCursor.is() )
1883 if ( pDlg->IsSearchBackwards() )
1884 xCursor = xCursor->getStart();
1885 xSelection = xSearchable->findNext( xCursor, xSrchDesc );
1887 else
1888 xSelection = xSearchable->findFirst( xSrchDesc );
1890 // then select the found word
1891 if ( xSelection.is() )
1893 Reference < XSelectionSupplier > xSelectionSup( xController, UNO_QUERY );
1894 if ( xSelectionSup.is() )
1896 xSelectionSup->select( Any(xSelection) );
1899 else if ( pDlg->IsWrapAround() && !bWrapAround )
1901 Reference < text::XTextViewCursorSupplier > xCrsrSupp( xController, uno::UNO_QUERY );
1902 Reference < text::XTextViewCursor > xTVCrsr = xCrsrSupp->getViewCursor();
1903 if ( xTVCrsr.is() )
1905 Reference < text::XTextDocument > xDoc( xController->getModel(), uno::UNO_QUERY );
1906 Reference < text::XText > xText = xDoc->getText();
1907 if ( xText.is() )
1909 if ( pDlg->IsSearchBackwards() )
1910 xTVCrsr->gotoRange( xText->getEnd(), false );
1911 else
1912 xTVCrsr->gotoRange( xText->getStart(), false );
1913 FindHdl( nullptr );
1917 else
1919 assert(m_xSrchDlg && "no search dialog");
1920 std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_xSrchDlg->getDialog(),
1921 VclMessageType::Info, VclButtonsType::Ok, SfxResId(STR_INFO_NOSEARCHTEXTFOUND)));
1922 xBox->run();
1923 m_xSrchDlg->SetFocusOnEdit();
1928 catch( Exception& )
1930 TOOLS_WARN_EXCEPTION( "sfx.appl", "SfxHelpTextWindow_Impl::SelectHdl(): unexpected exception" );
1934 IMPL_LINK_NOARG(SfxHelpTextWindow_Impl, CloseHdl, LinkParamNone*, void)
1936 m_xSrchDlg.reset();
1939 IMPL_LINK_NOARG(SfxHelpTextWindow_Impl, CheckHdl, weld::Toggleable&, void)
1941 if ( !xConfiguration.is() )
1942 return;
1944 bool bChecked = xOnStartupCB->get_active();
1947 ConfigurationHelper::writeRelativeKey(
1948 xConfiguration, PATH_OFFICE_FACTORIES + sCurrentFactory, KEY_HELP_ON_OPEN, Any( bChecked ) );
1949 ConfigurationHelper::flush( xConfiguration );
1951 catch( Exception const & )
1953 TOOLS_WARN_EXCEPTION( "sfx.appl", "SfxHelpTextWindow_Impl::CheckHdl()" );
1957 void SfxHelpTextWindow_Impl::Resize()
1959 Size aSize = GetOutputSizePixel();
1960 pTextWin->SetPosSizePixel( Point(0, 0), aSize );
1963 bool SfxHelpTextWindow_Impl::PreNotify( NotifyEvent& rNEvt )
1965 bool bDone = false;
1966 NotifyEventType nType = rNEvt.GetType();
1967 if ( NotifyEventType::COMMAND == nType && rNEvt.GetCommandEvent() )
1969 const CommandEvent* pCmdEvt = rNEvt.GetCommandEvent();
1970 vcl::Window* pCmdWin = rNEvt.GetWindow();
1972 if ( pCmdEvt->GetCommand() == CommandEventId::ContextMenu && pCmdWin != this )
1974 Point aPos;
1975 if ( pCmdEvt->IsMouseEvent() )
1976 aPos = pCmdEvt->GetMousePosPixel();
1977 else
1978 aPos = Point( pTextWin->GetPosPixel().X() + 20, 20 );
1980 xMenu->clear();
1982 if (bIsIndexOn)
1983 xMenu->append(u"index"_ustr, aIndexOffText, BMP_HELP_TOOLBOX_INDEX_OFF);
1984 else
1985 xMenu->append(u"index"_ustr, aIndexOnText, BMP_HELP_TOOLBOX_INDEX_ON);
1987 xMenu->append_separator(u"separator1"_ustr);
1988 xMenu->append(u"backward"_ustr, SfxResId(STR_HELP_BUTTON_PREV), BMP_HELP_TOOLBOX_PREV);
1989 xMenu->set_sensitive(u"backward"_ustr, xHelpWin->HasHistoryPredecessor());
1990 xMenu->append(u"forward"_ustr, SfxResId(STR_HELP_BUTTON_NEXT), BMP_HELP_TOOLBOX_NEXT);
1991 xMenu->set_sensitive(u"forward"_ustr, xHelpWin->HasHistorySuccessor());
1992 xMenu->append(u"start"_ustr, SfxResId(STR_HELP_BUTTON_START), BMP_HELP_TOOLBOX_START);
1993 xMenu->append_separator(u"separator2"_ustr);
1994 xMenu->append(u"print"_ustr, SfxResId(STR_HELP_BUTTON_PRINT), BMP_HELP_TOOLBOX_PRINT);
1995 xMenu->append(u"bookmarks"_ustr, SfxResId(STR_HELP_BUTTON_ADDBOOKMARK), BMP_HELP_TOOLBOX_BOOKMARKS);
1996 xMenu->append(u"searchdialog"_ustr, SfxResId(STR_HELP_BUTTON_SEARCHDIALOG), BMP_HELP_TOOLBOX_SEARCHDIALOG);
1997 xMenu->append_separator(u"separator3"_ustr);
1998 xMenu->append_check(u"selectionmode"_ustr, SfxResId(STR_HELP_MENU_TEXT_SELECTION_MODE));
1999 URL aURL;
2000 aURL.Complete = ".uno:SelectTextMode";
2001 Reference< util::XURLTransformer > xTrans( util::URLTransformer::create( ::comphelper::getProcessComponentContext() ) );
2002 xTrans->parseStrict(aURL);
2003 Reference < XDispatch > xDisp = xFrame->queryDispatch( aURL, OUString(), 0 );
2004 if(xDisp.is())
2006 rtl::Reference<HelpStatusListener_Impl> pStateListener =
2007 new HelpStatusListener_Impl(xDisp, aURL );
2008 FeatureStateEvent rEvent = pStateListener->GetStateEvent();
2009 bool bCheck = false;
2010 rEvent.State >>= bCheck;
2011 xMenu->set_active(u"selectionmode"_ustr, bCheck);
2013 xMenu->append_separator(u"separator4"_ustr);
2014 xMenu->append(u"copy"_ustr, SfxResId(STR_HELP_MENU_TEXT_COPY), BMP_HELP_TOOLBOX_COPY);
2015 xMenu->set_sensitive(u"copy"_ustr, HasSelection());
2017 if ( bIsDebug )
2019 xMenu->append_separator(u"separator5"_ustr);
2020 xMenu->append(u"sourceview"_ustr, SfxResId(STR_HELP_BUTTON_SOURCEVIEW));
2023 int x, y, width, height;
2024 weld::Window* pTopLevel = GetFrameWeld();
2025 xHelpWin->GetContainer()->get_extents_relative_to(*pTopLevel, x, y, width, height);
2026 aPos.AdjustX(x);
2027 aPos.AdjustY(y);
2029 xHelpWin->DoAction(xMenu->popup_at_rect(pTopLevel, tools::Rectangle(aPos, Size(1,1))));
2030 bDone = true;
2033 else if ( NotifyEventType::KEYINPUT == nType && rNEvt.GetKeyEvent() )
2035 const KeyEvent* pKEvt = rNEvt.GetKeyEvent();
2036 const vcl::KeyCode& rKeyCode = pKEvt->GetKeyCode();
2037 sal_uInt16 nKeyGroup = rKeyCode.GetGroup();
2038 sal_uInt16 nKey = rKeyCode.GetCode();
2039 if ( KEYGROUP_ALPHA == nKeyGroup && !isHandledKey( rKeyCode ) )
2041 // do nothing disables the writer accelerators
2042 bDone = true;
2044 else if ( rKeyCode.IsMod1() && ( KEY_F4 == nKey || KEY_W == nKey ) )
2046 // <CTRL><F4> or <CTRL><W> -> close top frame
2047 xHelpWin->CloseWindow();
2048 bDone = true;
2050 else if ( KEY_TAB == nKey && xOnStartupCB->has_focus() )
2052 xToolBox->grab_focus();
2053 bDone = true;
2057 return bDone || Window::PreNotify( rNEvt );
2061 void SfxHelpTextWindow_Impl::GetFocus()
2063 if ( bIsInClose )
2064 return;
2068 if( xFrame.is() )
2070 Reference< css::awt::XWindow > xWindow = xFrame->getComponentWindow();
2071 if( xWindow.is() )
2072 xWindow->setFocus();
2075 catch( Exception const & )
2077 TOOLS_WARN_EXCEPTION( "sfx.appl", "SfxHelpTextWindow_Impl::GetFocus()" );
2082 void SfxHelpTextWindow_Impl::DataChanged( const DataChangedEvent& rDCEvt )
2084 Window::DataChanged( rDCEvt );
2086 if ( ( ( rDCEvt.GetType() == DataChangedEventType::SETTINGS ) ||
2087 ( rDCEvt.GetType() == DataChangedEventType::DISPLAY ) ) &&
2088 ( rDCEvt.GetFlags() & AllSettingsFlags::STYLE ) )
2090 SetBackground( Wallpaper( GetSettings().GetStyleSettings().GetFaceColor() ) );
2091 InitToolBoxImages();
2095 void SfxHelpTextWindow_Impl::ToggleIndex( bool bOn )
2097 bIsIndexOn = bOn;
2098 if ( bIsIndexOn )
2100 xToolBox->set_item_icon_name(u"index"_ustr, aIndexOffImage);
2101 xToolBox->set_item_tooltip_text(u"index"_ustr, aIndexOffText);
2103 else
2105 xToolBox->set_item_icon_name(u"index"_ustr, aIndexOnImage);
2106 xToolBox->set_item_tooltip_text(u"index"_ustr, aIndexOnText);
2110 void SfxHelpTextWindow_Impl::SelectSearchText( const OUString& rSearchText, bool _bIsFullWordSearch )
2112 aSearchText = rSearchText;
2113 bIsFullWordSearch = _bIsFullWordSearch;
2114 aSelectIdle.Start();
2118 void SfxHelpTextWindow_Impl::SetPageStyleHeaderOff() const
2120 bool bSetOff = false;
2121 // set off the pagestyle header to prevent print output of the help URL
2124 Reference < XController > xController = xFrame->getController();
2125 Reference < XSelectionSupplier > xSelSup( xController, UNO_QUERY );
2126 if ( xSelSup.is() )
2128 Reference < XIndexAccess > xSelection;
2129 if ( xSelSup->getSelection() >>= xSelection )
2131 Reference < XTextRange > xRange;
2132 if ( xSelection->getByIndex(0) >>= xRange )
2134 Reference < XText > xText = xRange->getText();
2135 Reference < XPropertySet > xProps( xText->createTextCursorByRange( xRange ), UNO_QUERY );
2136 OUString sStyleName;
2137 if ( xProps->getPropertyValue( u"PageStyleName"_ustr ) >>= sStyleName )
2139 Reference < XStyleFamiliesSupplier > xStyles( xController->getModel(), UNO_QUERY );
2140 Reference < XNameContainer > xContainer;
2141 if ( xStyles->getStyleFamilies()->getByName( u"PageStyles"_ustr )
2142 >>= xContainer )
2144 Reference < XStyle > xStyle;
2145 if ( xContainer->getByName( sStyleName ) >>= xStyle )
2147 Reference < XPropertySet > xPropSet( xStyle, UNO_QUERY );
2148 xPropSet->setPropertyValue( u"HeaderIsOn"_ustr, Any( false ) );
2150 Reference< XModifiable > xReset(xStyles, UNO_QUERY);
2151 xReset->setModified(false);
2152 bSetOff = true;
2160 catch( Exception const & )
2162 TOOLS_WARN_EXCEPTION( "sfx.appl", "SfxHelpTextWindow_Impl::SetPageStyleHeaderOff()" );
2165 SAL_WARN_IF( !bSetOff, "sfx.appl", "SfxHelpTextWindow_Impl::SetPageStyleHeaderOff(): set off failed" );
2169 void SfxHelpTextWindow_Impl::CloseFrame()
2171 bIsInClose = true;
2174 css::uno::Reference< css::util::XCloseable > xCloseable ( xFrame, css::uno::UNO_QUERY );
2175 if (xCloseable.is())
2176 xCloseable->close(true);
2178 catch( css::util::CloseVetoException& )
2184 void SfxHelpTextWindow_Impl::DoSearch()
2186 if (m_xSrchDlg)
2187 return;
2189 // create the search dialog
2190 m_xSrchDlg = std::make_shared<sfx2::SearchDialog>(pTextWin->GetFrameWeld(), "HelpSearchDialog");
2191 // set handler
2192 m_xSrchDlg->SetFindHdl( LINK( this, SfxHelpTextWindow_Impl, FindHdl ) );
2193 m_xSrchDlg->SetCloseHdl( LINK( this, SfxHelpTextWindow_Impl, CloseHdl ) );
2194 // get selected text of the help page to set it as the search text
2195 Reference< XTextRange > xCursor = getCursor();
2196 if ( xCursor.is() )
2198 OUString sText = xCursor->getString();
2199 if ( !sText.isEmpty() )
2200 m_xSrchDlg->SetSearchText( sText );
2202 sfx2::SearchDialog::runAsync(m_xSrchDlg);
2205 void SfxHelpWindow_Impl::GetFocus()
2207 if (pTextWin)
2208 pTextWin->GrabFocus();
2209 else
2210 ResizableDockingWindow::GetFocus();
2213 void SfxHelpWindow_Impl::MakeLayout()
2215 Split();
2217 m_xHelpPaneWindow->set_visible(bIndex);
2220 IMPL_LINK(SfxHelpWindow_Impl, ResizeHdl, const Size&, rSize, void)
2222 int nNewWidth = rSize.Width();
2223 if (!nNewWidth)
2224 return;
2225 if (bSplit)
2226 nIndexSize = round(m_xContainer->get_position() * 100.0 / nNewWidth);
2227 nWidth = nNewWidth;
2228 Split();
2229 nIndexSize = round(m_xContainer->get_position() * 100.0 / nWidth);
2232 void SfxHelpWindow_Impl::Split()
2234 if (!nWidth)
2235 return;
2236 m_xContainer->set_position(nWidth * nIndexSize / 100);
2237 bSplit = true;
2240 void SfxHelpWindow_Impl::LoadConfig()
2242 SvtViewOptions aViewOpt( EViewType::Window, CONFIGNAME_HELPWIN );
2243 if ( !aViewOpt.Exists() )
2244 return;
2245 bIndex = aViewOpt.IsVisible();
2247 Any aUserItem = aViewOpt.GetUserItem( USERITEM_NAME );
2248 OUString aUserData;
2249 if ( aUserItem >>= aUserData )
2251 DBG_ASSERT( comphelper::string::getTokenCount(aUserData, ';') == 6, "invalid user data" );
2252 sal_Int32 nIdx = 0;
2253 nIndexSize = o3tl::toInt32(o3tl::getToken(aUserData, 0, ';', nIdx ));
2254 o3tl::getToken(aUserData, 0, ';', nIdx); // ignore nTextSize
2255 sal_Int32 nOldWidth = o3tl::toInt32(o3tl::getToken(aUserData, 0, ';', nIdx ));
2256 sal_Int32 nOldHeight = o3tl::toInt32(o3tl::getToken(aUserData, 0, ';', nIdx ));
2257 aWinSize = Size(nOldWidth, nOldHeight);
2258 aWinPos.setX( o3tl::toInt32(o3tl::getToken(aUserData, 0, ';', nIdx )) );
2259 aWinPos.setY( o3tl::toInt32(o3tl::getToken(aUserData, 0, ';', nIdx )) );
2262 pTextWin->ToggleIndex( bIndex );
2265 void SfxHelpWindow_Impl::SaveConfig()
2267 SvtViewOptions aViewOpt( EViewType::Window, CONFIGNAME_HELPWIN );
2268 sal_Int32 nW = 0, nH = 0;
2270 if ( xWindow.is() )
2272 css::awt::Rectangle aRect = xWindow->getPosSize();
2273 nW = aRect.Width;
2274 nH = aRect.Height;
2277 aViewOpt.SetVisible( bIndex );
2278 VclPtr<vcl::Window> pScreenWin = VCLUnoHelper::GetWindow( xWindow );
2279 aWinPos = pScreenWin->GetWindowExtentsAbsolute().TopLeft();
2280 if (bSplit)
2281 nIndexSize = round(m_xContainer->get_position() * 100.0 / nWidth);
2282 const OUString aUserData = OUString::number( nIndexSize )
2283 + ";" + OUString::number( 100 - nIndexSize )
2284 + ";" + OUString::number( nW )
2285 + ";" + OUString::number( nH )
2286 + ";" + OUString::number( aWinPos.X() )
2287 + ";" + OUString::number( aWinPos.Y() );
2289 aViewOpt.SetUserItem( USERITEM_NAME, Any( aUserData ) );
2292 void SfxHelpWindow_Impl::ShowStartPage()
2294 loadHelpContent(SfxHelpWindow_Impl::buildHelpURL(xIndexWin->GetFactory(), u"/start", u""));
2297 IMPL_LINK(SfxHelpWindow_Impl, SelectHdl, const OUString&, rCurItem, void)
2299 bGrabFocusToToolBox = pTextWin->GetToolBox().has_focus();
2300 DoAction(rCurItem);
2303 IMPL_LINK_NOARG(SfxHelpWindow_Impl, OpenHdl, LinkParamNone*, void)
2305 xIndexWin->SelectExecutableEntry();
2306 OUString aEntry = xIndexWin->GetSelectedEntry();
2308 if ( aEntry.isEmpty() )
2309 return;
2311 OUString sHelpURL;
2313 bool bComplete = aEntry.toAsciiLowerCase().match("vnd.sun.star.help");
2315 if (bComplete)
2316 sHelpURL = aEntry;
2317 else
2319 std::u16string_view aId;
2320 OUString aAnchor('#');
2321 if ( comphelper::string::getTokenCount(aEntry, '#') == 2 )
2323 sal_Int32 nIdx{ 0 };
2324 aId = o3tl::getToken(aEntry, 0, '#', nIdx );
2325 aAnchor += o3tl::getToken(aEntry, 0, '#', nIdx );
2327 else
2328 aId = aEntry;
2330 sHelpURL = SfxHelpWindow_Impl::buildHelpURL(xIndexWin->GetFactory(), Concat2View(OUString::Concat("/") + aId), aAnchor);
2333 loadHelpContent(sHelpURL);
2336 IMPL_LINK( SfxHelpWindow_Impl, SelectFactoryHdl, SfxHelpIndexWindow_Impl* , pWin, void )
2338 if ( sTitle.isEmpty() )
2339 sTitle = GetParent()->GetText();
2341 Reference< XTitle > xTitle(xFrame, UNO_QUERY);
2342 if (xTitle.is ())
2343 xTitle->setTitle(sTitle + " - " + xIndexWin->GetActiveFactoryTitle());
2345 if ( pWin )
2346 ShowStartPage();
2347 xIndexWin->ClearSearchPage();
2351 IMPL_LINK( SfxHelpWindow_Impl, ChangeHdl, HelpListener_Impl&, rListener, void )
2353 SetFactory( rListener.GetFactory() );
2357 void SfxHelpWindow_Impl::openDone(std::u16string_view sURL ,
2358 bool bSuccess)
2360 INetURLObject aObj( sURL );
2361 if ( aObj.GetProtocol() == INetProtocol::VndSunStarHelp )
2362 SetFactory( aObj.GetHost() );
2363 if ( IsWait() )
2364 LeaveWait();
2365 if ( bGrabFocusToToolBox )
2367 pTextWin->GetToolBox().grab_focus();
2368 bGrabFocusToToolBox = false;
2370 else
2371 xIndexWin->GrabFocusBack();
2372 if ( !bSuccess )
2373 return;
2375 // set some view settings: "prevent help tips" and "helpid == 68245"
2378 Reference < XController > xController = pTextWin->getFrame()->getController();
2379 if ( xController.is() )
2381 Reference < XViewSettingsSupplier > xSettings( xController, UNO_QUERY );
2382 Reference < XPropertySet > xViewProps = xSettings->getViewSettings();
2383 Reference< XPropertySetInfo > xInfo = xViewProps->getPropertySetInfo();
2384 xViewProps->setPropertyValue( u"ShowContentTips"_ustr, Any( false ) );
2385 xViewProps->setPropertyValue( u"ShowGraphics"_ustr, Any( true ) );
2386 xViewProps->setPropertyValue( u"ShowTables"_ustr, Any( true ) );
2387 xViewProps->setPropertyValue( u"HelpURL"_ustr, Any( u"HID:SFX2_HID_HELP_ONHELP"_ustr ) );
2388 OUString sProperty( u"IsExecuteHyperlinks"_ustr );
2389 if ( xInfo->hasPropertyByName( sProperty ) )
2390 xViewProps->setPropertyValue( sProperty, Any( true ) );
2391 xController->restoreViewData(Any());
2394 catch( Exception& )
2396 TOOLS_WARN_EXCEPTION( "sfx.appl", "SfxHelpWindow_Impl::OpenDoneHdl(): unexpected exception" );
2399 // When the SearchPage opens the help doc, then select all words, which are equal to its text
2400 OUString sSearchText = comphelper::string::strip(xIndexWin->GetSearchText(), ' ');
2401 if ( !sSearchText.isEmpty() )
2402 pTextWin->SelectSearchText( sSearchText, xIndexWin->IsFullWordSearch() );
2404 // no page style header -> this prevents a print output of the URL
2405 pTextWin->SetPageStyleHeaderOff();
2409 SfxHelpWindow_Impl::SfxHelpWindow_Impl(
2410 const css::uno::Reference < css::frame::XFrame2 >& rFrame,
2411 vcl::Window* pParent ) :
2413 ResizableDockingWindow(pParent),
2415 xFrame ( rFrame ),
2416 pTextWin ( nullptr ),
2417 pHelpInterceptor ( new HelpInterceptor_Impl() ),
2418 pHelpListener ( new HelpListener_Impl( pHelpInterceptor ) ),
2419 bIndex ( true ),
2420 bGrabFocusToToolBox ( false ),
2421 bSplit ( false ),
2422 nWidth ( 0 ),
2423 nIndexSize ( 40 ), // % of width
2424 aWinPos ( 0, 0 ),
2425 aWinSize ( 0, 0 ),
2426 sTitle ( pParent->GetText() )
2428 SetStyle(GetStyle() & ~WB_DOCKABLE);
2430 SetHelpId( HID_HELP_WINDOW );
2432 m_xBuilder = Application::CreateInterimBuilder(m_xBox.get(), u"sfx/ui/helpwindow.ui"_ustr, false);
2433 m_xContainer = m_xBuilder->weld_paned(u"HelpWindow"_ustr);
2434 m_xContainer->connect_size_allocate(LINK(this, SfxHelpWindow_Impl, ResizeHdl));
2435 m_xHelpPaneWindow = m_xBuilder->weld_container(u"helppanewindow"_ustr);
2436 m_xHelpTextWindow = m_xBuilder->weld_container(u"helptextwindow"_ustr);
2437 m_xHelpTextXWindow = m_xHelpTextWindow->CreateChildFrame();
2439 pHelpInterceptor->InitWaiter( this );
2440 xIndexWin.reset(new SfxHelpIndexWindow_Impl(this, m_xHelpPaneWindow.get()));
2441 xIndexWin->SetDoubleClickHdl( LINK( this, SfxHelpWindow_Impl, OpenHdl ) );
2442 xIndexWin->SetSelectFactoryHdl( LINK( this, SfxHelpWindow_Impl, SelectFactoryHdl ) );
2444 pTextWin = VclPtr<SfxHelpTextWindow_Impl>::Create(this, *m_xBuilder, VCLUnoHelper::GetWindow(m_xHelpTextXWindow));
2445 Reference < XFrames > xFrames = rFrame->getFrames();
2446 xFrames->append( Reference<XFrame>(pTextWin->getFrame(), UNO_QUERY_THROW) );
2447 pTextWin->SetSelectHdl( LINK( this, SfxHelpWindow_Impl, SelectHdl ) );
2448 pTextWin->Show();
2449 pHelpInterceptor->setInterception( Reference<XFrame>(pTextWin->getFrame(), UNO_QUERY_THROW) );
2450 pHelpListener->SetChangeHdl( LINK( this, SfxHelpWindow_Impl, ChangeHdl ) );
2451 LoadConfig();
2454 SfxHelpWindow_Impl::~SfxHelpWindow_Impl()
2456 disposeOnce();
2459 void SfxHelpWindow_Impl::dispose()
2461 SaveConfig();
2462 xIndexWin.reset();
2463 pTextWin->CloseFrame();
2464 pTextWin.disposeAndClear();
2466 m_xHelpTextXWindow->dispose();
2467 m_xHelpTextXWindow.clear();
2468 m_xHelpTextWindow.reset();
2469 m_xHelpPaneWindow.reset();
2470 m_xContainer.reset();
2471 m_xBuilder.reset();
2473 ResizableDockingWindow::dispose();
2476 bool SfxHelpWindow_Impl::PreNotify( NotifyEvent& rNEvt )
2478 bool bHandled = false;
2479 if ( rNEvt.GetType() == NotifyEventType::KEYINPUT )
2481 // Backward == <ALT><LEFT> or <BACKSPACE> Forward == <ALT><RIGHT>
2482 const vcl::KeyCode& rKeyCode = rNEvt.GetKeyEvent()->GetKeyCode();
2483 sal_uInt16 nKey = rKeyCode.GetCode();
2484 if ( ( rKeyCode.IsMod2() && ( KEY_LEFT == nKey || KEY_RIGHT == nKey ) ) ||
2485 ( !rKeyCode.GetModifier() && KEY_BACKSPACE == nKey && !xIndexWin->HasFocusOnEdit() ) )
2487 DoAction( rKeyCode.GetCode() == KEY_RIGHT ? u"forward" : u"backward" );
2488 bHandled = true;
2490 else if ( rKeyCode.IsMod1() && ( KEY_F4 == nKey || KEY_W == nKey ) )
2492 // <CTRL><F4> or <CTRL><W> -> close top frame
2493 CloseWindow();
2494 bHandled = true;
2497 return bHandled || Window::PreNotify( rNEvt );
2500 void SfxHelpWindow_Impl::setContainerWindow( const Reference < css::awt::XWindow >& xWin )
2502 xWindow = xWin;
2503 MakeLayout();
2504 if (xWindow.is())
2506 VclPtr<vcl::Window> pScreenWin = VCLUnoHelper::GetWindow(xWindow);
2507 if (aWinSize.Width() && aWinSize.Height())
2508 pScreenWin->SetPosSizePixel(Point(aWinPos), aWinSize);
2509 else
2510 pScreenWin->SetPosPixel(Point(aWinPos));
2514 void SfxHelpWindow_Impl::SetFactory( const OUString& rFactory )
2516 xIndexWin->SetFactory( rFactory, true );
2519 void SfxHelpWindow_Impl::SetHelpURL( std::u16string_view rURL )
2521 INetURLObject aObj( rURL );
2522 if ( aObj.GetProtocol() == INetProtocol::VndSunStarHelp )
2523 SetFactory( aObj.GetHost() );
2526 void SfxHelpWindow_Impl::DoAction(std::u16string_view rActionId)
2528 if (rActionId == u"index")
2530 bIndex = !bIndex;
2531 MakeLayout();
2532 pTextWin->ToggleIndex( bIndex );
2534 else if (rActionId == u"start")
2536 ShowStartPage();
2538 else if (rActionId == u"backward" || rActionId == u"forward")
2540 URL aURL;
2541 aURL.Complete = ".uno:Backward";
2542 if (rActionId == u"forward")
2543 aURL.Complete = ".uno:Forward";
2544 Reference< util::XURLTransformer > xTrans( util::URLTransformer::create( ::comphelper::getProcessComponentContext() ) );
2545 xTrans->parseStrict(aURL);
2546 pHelpInterceptor->dispatch( aURL, Sequence < PropertyValue >() );
2548 else if (rActionId == u"searchdialog")
2550 pTextWin->DoSearch();
2552 else if (rActionId == u"print" || rActionId == u"sourceview" || rActionId == u"copy" || rActionId == u"selectionmode")
2554 Reference < XDispatchProvider > xProv = pTextWin->getFrame();
2555 if ( xProv.is() )
2557 URL aURL;
2558 if (rActionId == u"print")
2559 aURL.Complete = ".uno:Print";
2560 else if (rActionId == u"sourceview")
2561 aURL.Complete = ".uno:SourceView";
2562 else if (rActionId == u"copy")
2563 aURL.Complete = ".uno:Copy";
2564 else // rActionId == "selectionmode"
2565 aURL.Complete = ".uno:SelectTextMode";
2566 Reference< util::XURLTransformer > xTrans( util::URLTransformer::create( ::comphelper::getProcessComponentContext() ) );
2567 xTrans->parseStrict(aURL);
2568 Reference < XDispatch > xDisp = xProv->queryDispatch( aURL, OUString(), 0 );
2569 if ( xDisp.is() )
2570 xDisp->dispatch( aURL, Sequence < PropertyValue >() );
2573 else if (rActionId == u"bookmarks")
2575 OUString aURL = pHelpInterceptor->GetCurrentURL();
2576 if ( !aURL.isEmpty() )
2580 Content aCnt( aURL, Reference< css::ucb::XCommandEnvironment >(), comphelper::getProcessComponentContext() );
2581 css::uno::Reference< css::beans::XPropertySetInfo > xInfo = aCnt.getProperties();
2582 if ( xInfo->hasPropertyByName( PROPERTY_TITLE ) )
2584 css::uno::Any aAny = aCnt.getPropertyValue( PROPERTY_TITLE );
2585 OUString aValue;
2586 if ( aAny >>= aValue )
2588 SfxAddHelpBookmarkDialog_Impl aDlg(GetFrameWeld(), false);
2589 aDlg.SetTitle(aValue);
2590 if (aDlg.run() == RET_OK )
2592 xIndexWin->AddBookmarks( aDlg.GetTitle(), aURL );
2597 catch( Exception& )
2599 TOOLS_WARN_EXCEPTION( "sfx.appl", "SfxHelpWindow_Impl::DoAction(): unexpected exception" );
2605 void SfxHelpWindow_Impl::CloseWindow()
2609 // search for top frame
2610 Reference< XFramesSupplier > xCreator = getTextFrame()->getCreator();
2611 while ( xCreator.is() && !xCreator->isTop() )
2613 xCreator = xCreator->getCreator();
2616 // when found, close it
2617 if ( xCreator.is() && xCreator->isTop() )
2619 Reference < XCloseable > xCloser( xCreator, UNO_QUERY );
2620 if ( xCloser.is() )
2621 xCloser->close( false );
2624 catch( Exception const & )
2626 TOOLS_WARN_EXCEPTION( "sfx.appl", "SfxHelpWindow_Impl::CloseWindow()" );
2631 void SfxHelpWindow_Impl::UpdateToolbox()
2633 pTextWin->GetToolBox().set_item_sensitive(u"backward"_ustr, pHelpInterceptor->HasHistoryPred());
2634 pTextWin->GetToolBox().set_item_sensitive(u"forward"_ustr, pHelpInterceptor->HasHistorySucc());
2638 bool SfxHelpWindow_Impl::HasHistoryPredecessor() const
2640 return pHelpInterceptor->HasHistoryPred();
2644 bool SfxHelpWindow_Impl::HasHistorySuccessor() const
2646 return pHelpInterceptor->HasHistorySucc();
2649 // class SfxAddHelpBookmarkDialog_Impl -----------------------------------
2651 SfxAddHelpBookmarkDialog_Impl::SfxAddHelpBookmarkDialog_Impl(weld::Widget* pParent, bool bRename)
2652 : GenericDialogController(pParent, u"sfx/ui/bookmarkdialog.ui"_ustr, u"BookmarkDialog"_ustr)
2653 , m_xTitleED(m_xBuilder->weld_entry(u"entry"_ustr))
2654 , m_xAltTitle(m_xBuilder->weld_label(u"alttitle"_ustr))
2656 if (bRename)
2657 m_xDialog->set_title(m_xAltTitle->get_label());
2660 void SfxAddHelpBookmarkDialog_Impl::SetTitle(const OUString& rTitle)
2662 m_xTitleED->set_text(rTitle);
2663 m_xTitleED->select_region(0, -1);
2666 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */