LanguageTool: don't crash if REST protocol isn't set
[LibreOffice.git] / sfx2 / source / appl / newhelp.cxx
blob850a2b207962c83bc3013122cf7ddfef21ed480b
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 <osl/diagnose.h>
29 #include <tools/debug.hxx>
30 #include <tools/diagnose_ex.h>
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 <vcl/commandevent.hxx>
78 #include <vcl/event.hxx>
79 #include <vcl/i18nhelp.hxx>
80 #include <vcl/settings.hxx>
81 #include <vcl/svapp.hxx>
82 #include <vcl/unohelp.hxx>
83 #include <vcl/weld.hxx>
85 #include <ucbhelper/content.hxx>
86 #include <unotools/ucbhelper.hxx>
88 #include <string_view>
89 #include <unordered_map>
90 #include <vector>
92 using namespace ::ucbhelper;
93 using namespace ::com::sun::star::ucb;
95 using namespace ::com::sun::star;
96 using namespace ::com::sun::star::beans;
97 using namespace ::com::sun::star::container;
98 using namespace ::com::sun::star::frame;
99 using namespace ::com::sun::star::i18n;
100 using namespace ::com::sun::star::lang;
101 using namespace ::com::sun::star::style;
102 using namespace ::com::sun::star::text;
103 using namespace ::com::sun::star::uno;
104 using namespace ::com::sun::star::util;
105 using namespace ::com::sun::star::view;
106 using namespace ::com::sun::star::ui;
108 using namespace ::comphelper;
110 // defines ---------------------------------------------------------------
112 constexpr OUStringLiteral CONFIGNAME_HELPWIN = u"OfficeHelp";
113 constexpr OUStringLiteral CONFIGNAME_INDEXWIN = u"OfficeHelpIndex";
114 constexpr OUStringLiteral CONFIGNAME_SEARCHPAGE = u"OfficeHelpSearch";
115 constexpr OUStringLiteral IMAGE_URL = u"private:factory/";
117 constexpr OUStringLiteral PROPERTY_KEYWORDLIST = u"KeywordList";
118 constexpr OUStringLiteral PROPERTY_KEYWORDREF = u"KeywordRef";
119 constexpr OUStringLiteral PROPERTY_ANCHORREF = u"KeywordAnchorForRef";
120 constexpr OUStringLiteral PROPERTY_TITLEREF = u"KeywordTitleForRef";
121 constexpr OUStringLiteral PROPERTY_TITLE = u"Title";
122 constexpr OUStringLiteral HELP_URL = u"vnd.sun.star.help://";
123 constexpr OUStringLiteral HELP_SEARCH_TAG = u"/?Query=";
124 constexpr OUStringLiteral USERITEM_NAME = u"UserItem";
126 constexpr OUStringLiteral PACKAGE_SETUP = u"/org.openoffice.Setup";
127 constexpr OUStringLiteral PATH_OFFICE_FACTORIES = u"Office/Factories/";
128 constexpr OUStringLiteral KEY_HELP_ON_OPEN = u"ooSetupFactoryHelpOnOpen";
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( const OUString& rURL, bool bSubEntry ) :
198 m_bSubEntry( bSubEntry ), m_aURL( rURL ) {}
201 // struct ContentEntry_Impl ----------------------------------------------
203 struct ContentEntry_Impl
205 OUString aURL;
206 bool bIsFolder;
208 ContentEntry_Impl( const OUString& rURL, bool bFolder ) :
209 aURL( rURL ), bIsFolder( bFolder ) {}
214 void ContentTabPage_Impl::InitRoot()
216 std::vector< OUString > aList =
217 SfxContentHelper::GetHelpTreeViewContents( "vnd.sun.star.hier://com.sun.star.help.TreeView/" );
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 = aRow.getToken( 0, '\t', nIdx )[0];
225 bool bIsFolder = ( '1' == cFolder );
226 OUString sId;
227 if (bIsFolder)
228 sId = OUString::number(reinterpret_cast<sal_Int64>(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 reinterpret_cast<ContentEntry_Impl*>(m_xContentBox->get_id(*xEntry).toInt64());
242 bEntry = m_xContentBox->iter_next_sibling(*xEntry);
247 IMPL_LINK(ContentTabPage_Impl, ExpandingHdl, const weld::TreeIter&, rIter, bool)
249 ContentEntry_Impl* pContentEntry = reinterpret_cast<ContentEntry_Impl*>(m_xContentBox->get_id(rIter).toInt64());
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 = aRow.getToken( 0, '\t', nIdx )[0];
264 bool bIsFolder = ( '1' == cFolder );
265 if ( bIsFolder )
267 OUString sId = OUString::number(reinterpret_cast<sal_Int64>(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, "TargetURL" ) );
274 OUString sId;
275 OUString aTargetURL;
276 if ( aAny >>= aTargetURL )
277 sId = OUString::number(reinterpret_cast<sal_Int64>(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 = reinterpret_cast<ContentEntry_Impl*>(m_xContentBox->get_id(rIter).toInt64());
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 = reinterpret_cast<ContentEntry_Impl*>(m_xContentBox->get_selected_id().toInt64());
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 OString& 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, "HelpContentPage",
329 "sfx/ui/helpcontentpage.ui")
330 , m_xContentBox(m_xBuilder->weld_tree_view("content"))
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 reinterpret_cast<ContentEntry_Impl*>(m_xContentBox->get_id(*xEntry).toInt64());
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 = reinterpret_cast<IndexEntry_Impl*>(m_xIndexList->get_id(nPos).toInt64());
377 sal_Int32 nCount = m_xIndexList->n_children();
378 while ( nPos < nCount && ( !pEntry || pEntry->m_aURL.isEmpty() ) )
380 pEntry = reinterpret_cast<IndexEntry_Impl*>(m_xIndexList->get_id(++nPos).toInt64());
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, "HelpIndexPage", "sfx/ui/helpindexpage.ui")
391 , m_xIndexEntry(m_xBuilder->weld_entry("termentry"))
392 , m_xIndexList(m_xBuilder->weld_tree_view("termlist"))
393 , m_xOpenBtn(m_xBuilder->weld_button("display"))
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_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 = reinterpret_cast<IndexEntry_Impl*>(rId.toInt64());
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);
578 aURL.append(sFactory);
579 AppendConfigToken(aURL, true);
581 Content aCnt( aURL.makeStringAndClear(), Reference< css::ucb::XCommandEnvironment >(), comphelper::getProcessComponentContext() );
582 css::uno::Reference< css::beans::XPropertySetInfo > xInfo = aCnt.getProperties();
583 if ( xInfo->hasPropertyByName( PROPERTY_ANCHORREF ) )
585 css::uno::Sequence< OUString > aPropSeq{ PROPERTY_KEYWORDLIST, PROPERTY_KEYWORDREF,
586 PROPERTY_ANCHORREF, PROPERTY_TITLEREF };
588 // abi: use one possibly remote call only
589 css::uno::Sequence< css::uno::Any > aAnySeq =
590 aCnt.getPropertyValues( aPropSeq );
592 css::uno::Sequence< OUString > aKeywordList;
593 css::uno::Sequence< css::uno::Sequence< OUString > > aKeywordRefList;
594 css::uno::Sequence< css::uno::Sequence< OUString > > aAnchorRefList;
595 css::uno::Sequence< css::uno::Sequence< OUString > > aTitleRefList;
597 if ( ( aAnySeq[0] >>= aKeywordList ) && ( aAnySeq[1] >>= aKeywordRefList ) &&
598 ( aAnySeq[2] >>= aAnchorRefList ) && ( aAnySeq[3] >>= aTitleRefList ) )
600 int ndx,tmp;
601 OUString aIndex, aTempString;
602 OUStringBuffer aData( 128 ); // Capacity of up to 128 characters
603 sfx2::KeywordInfo::iterator it;
605 for ( int i = 0; i < aKeywordList.getLength(); ++i )
607 // abi: Do not copy, but use references
608 const OUString& aKeywordPair = aKeywordList[i];
609 DBG_ASSERT( !aKeywordPair.isEmpty(), "invalid help index" );
610 const css::uno::Sequence< OUString >& aRefList = aKeywordRefList[i];
611 const css::uno::Sequence< OUString >& aAnchorList = aAnchorRefList[i];
612 const css::uno::Sequence< OUString >& aTitleList = aTitleRefList[i];
614 DBG_ASSERT( aRefList.getLength() == aAnchorList.getLength(),"reference list and title list of different length" );
616 ndx = aKeywordPair.indexOf( ';' );
617 const bool insert = ndx != -1;
619 OUString sId;
621 if ( insert )
623 aTempString = aKeywordPair.copy( 0, ndx );
624 if ( aIndex != aTempString )
626 aIndex = aTempString;
627 it = aInfo.emplace(aTempString, 0).first;
628 sId = OUString::number(reinterpret_cast<sal_Int64>(new IndexEntry_Impl(OUString(), false)));
629 if ( (tmp = it->second++) != 0)
630 m_xIndexList->append(
631 sId, aTempString + std::u16string_view(append, tmp));
632 else
633 m_xIndexList->append(sId, aTempString);
636 else
637 aIndex.clear();
639 sal_uInt32 nRefListLen = aRefList.getLength();
641 DBG_ASSERT( aAnchorList.hasElements(), "*IndexTabPage_Impl::InitializeIndex(): AnchorList is empty!" );
642 DBG_ASSERT( nRefListLen, "*IndexTabPage_Impl::InitializeIndex(): RefList is empty!" );
644 if ( aAnchorList.hasElements() && nRefListLen )
646 if ( aAnchorList[0].getLength() > 0 )
648 aData.append( aRefList[0] ).append( '#' ).append( aAnchorList[0] );
649 sId = OUString::number(reinterpret_cast<sal_Int64>(new IndexEntry_Impl(aData.makeStringAndClear(), insert)));
651 else
652 sId = OUString::number(reinterpret_cast<sal_Int64>(new IndexEntry_Impl(aRefList[0], insert)));
655 // Assume the token is trimmed
656 it = aInfo.emplace(aKeywordPair, 0).first;
657 if ((tmp = it->second++) != 0)
658 m_xIndexList->append(sId, aKeywordPair + std::u16string_view(append, tmp));
659 else
660 m_xIndexList->append(sId, aKeywordPair);
662 for ( sal_uInt32 j = 1; j < nRefListLen ; ++j )
664 aData
665 .append( aKeywordPair )
666 .append( ' ' )
667 .append( '-' )
668 .append( ' ' )
669 .append( aTitleList[j] );
671 aTempString = aData.makeStringAndClear();
673 if ( aAnchorList[j].getLength() > 0 )
675 aData.append( aRefList[j] ).append( '#' ).append( aAnchorList[j] );
676 sId = OUString::number(reinterpret_cast<sal_Int64>(new IndexEntry_Impl(aData.makeStringAndClear(), insert)));
678 else
679 sId = OUString::number(reinterpret_cast<sal_Int64>(new IndexEntry_Impl(aRefList[j], insert)));
681 it = aInfo.emplace(aTempString, 0).first;
682 if ( (tmp = it->second++) != 0 )
683 m_xIndexList->append(
684 sId, aTempString + std::u16string_view(append, tmp));
685 else
686 m_xIndexList->append(sId, aTempString);
692 catch( Exception& )
694 TOOLS_WARN_EXCEPTION( "sfx.appl", "IndexTabPage_Impl::InitializeIndex(): unexpected exception" );
697 m_xIndexList->thaw();
699 if ( !sKeyword.isEmpty() )
700 aKeywordLink.Call( *this );
703 void IndexTabPage_Impl::ClearIndex()
705 const sal_Int32 nCount = m_xIndexList->n_children();
706 for ( sal_Int32 i = 0; i < nCount; ++i )
707 delete reinterpret_cast<IndexEntry_Impl*>(m_xIndexList->get_id(i).toInt64());
708 m_xIndexList->clear();
711 IMPL_LINK_NOARG(IndexTabPage_Impl, OpenHdl, weld::Button&, void)
713 aDoubleClickHdl.Call(nullptr);
716 IMPL_LINK_NOARG(IndexTabPage_Impl, ActivateHdl, weld::Entry&, bool)
718 aDoubleClickHdl.Call(nullptr);
719 return true;
722 IMPL_LINK_NOARG(IndexTabPage_Impl, DoubleClickHdl, weld::TreeView&, bool)
724 aDoubleClickHdl.Call(nullptr);
725 return true;
728 IMPL_LINK_NOARG(IndexTabPage_Impl, IdleHdl, Timer*, void)
730 InitializeIndex();
733 int IndexTabPage_Impl::starts_with(const OUString& rStr, int nStartRow, bool bCaseSensitive)
735 const vcl::I18nHelper& rI18nHelper = Application::GetSettings().GetUILocaleI18nHelper();
737 int nRet = nStartRow;
738 int nCount = m_xIndexList->n_children();
739 while (nRet < nCount)
741 OUString aStr(m_xIndexList->get_text(nRet));
742 const bool bMatch = !bCaseSensitive ? rI18nHelper.MatchString(rStr, aStr) : aStr.startsWith(rStr);
743 if (bMatch)
744 return nRet;
745 ++nRet;
748 return -1;
751 IMPL_LINK_NOARG(IndexTabPage_Impl, AutoCompleteHdl, Timer*, void)
753 OUString aStartText = m_xIndexEntry->get_text();
754 int nStartPos, nEndPos;
755 m_xIndexEntry->get_selection_bounds(nStartPos, nEndPos);
756 int nMaxSelection = std::max(nStartPos, nEndPos);
757 if (nMaxSelection != aStartText.getLength())
758 return;
760 int nActive = m_xIndexList->get_selected_index();
761 int nStart = nActive;
763 if (nStart == -1)
764 nStart = 0;
766 // Try match case insensitive from current position
767 int nPos = starts_with(aStartText, nStart, false);
768 if (nPos == -1 && nStart != 0)
770 // Try match case insensitive, but from start
771 nPos = starts_with(aStartText, 0, false);
774 if (nPos == -1)
776 // Try match case sensitive from current position
777 nPos = starts_with(aStartText, nStart, true);
778 if (nPos == -1 && nStart != 0)
780 // Try match case sensitive, but from start
781 nPos = starts_with(aStartText, 0, true);
785 if (nPos != -1)
787 m_xIndexList->set_cursor(nPos);
788 m_xIndexList->select(nPos);
789 OUString aText = m_xIndexList->get_text(nPos);
790 if (aText != aStartText)
791 m_xIndexEntry->set_text(aText);
792 m_xIndexEntry->select_region(aText.getLength(), aStartText.getLength());
796 IMPL_LINK( IndexTabPage_Impl, TimeoutHdl, Timer*, pTimer, void)
798 if(&aKeywordTimer == pTimer && !sKeyword.isEmpty())
799 aKeywordLink.Call(*this);
802 void IndexTabPage_Impl::Activate()
804 if ( !bIsActivated )
806 bIsActivated = true;
807 aFactoryIdle.Start();
811 void IndexTabPage_Impl::SetDoubleClickHdl(const Link<LinkParamNone*, void>& rLink)
813 aDoubleClickHdl = rLink;
816 void IndexTabPage_Impl::SetFactory( const OUString& rFactory )
818 OUString sNewFactory( rFactory );
819 DBG_ASSERT( !sNewFactory.isEmpty(), "empty factory" );
820 bool bValid = m_pIdxWin->IsValidFactory( rFactory );
822 if ( sFactory.isEmpty() && !bValid )
824 sNewFactory = SfxHelp::GetDefaultHelpModule();
825 bValid = true;
828 if ( sNewFactory != sFactory && bValid )
830 sFactory = sNewFactory;
831 ClearIndex();
832 if ( bIsActivated )
833 aFactoryIdle.Start();
837 OUString IndexTabPage_Impl::GetSelectedEntry() const
839 OUString aRet;
840 IndexEntry_Impl* pEntry = reinterpret_cast<IndexEntry_Impl*>(m_xIndexList->get_id(m_xIndexList->find_text(m_xIndexEntry->get_text())).toInt64());
841 if (pEntry)
842 aRet = pEntry->m_aURL;
843 return aRet;
846 void IndexTabPage_Impl::SetKeyword( const OUString& rKeyword )
848 sKeyword = rKeyword;
850 if (m_xIndexList->n_children() > 0)
851 aKeywordTimer.Start();
852 else if ( !bIsActivated )
853 aFactoryIdle.Start();
857 bool IndexTabPage_Impl::HasKeyword() const
859 bool bRet = false;
860 if ( !sKeyword.isEmpty() )
862 sal_Int32 nPos = m_xIndexList->find_text( sKeyword );
863 bRet = nPos != -1;
866 return bRet;
870 bool IndexTabPage_Impl::HasKeywordIgnoreCase()
872 bool bRet = false;
873 if ( !sKeyword.isEmpty() )
875 sal_Int32 nEntries = m_xIndexList->n_children();
876 const vcl::I18nHelper& rI18nHelper = Application::GetSettings().GetLocaleI18nHelper();
877 for ( sal_Int32 n = 0; n < nEntries; n++)
879 const OUString sIndexItem {m_xIndexList->get_text(n)};
880 if (rI18nHelper.MatchString( sIndexItem, sKeyword ))
882 sKeyword = sIndexItem;
883 bRet = true;
888 return bRet;
891 void IndexTabPage_Impl::OpenKeyword()
893 if ( !sKeyword.isEmpty() )
895 m_xIndexEntry->set_text(sKeyword);
896 aDoubleClickHdl.Call(nullptr);
897 sKeyword.clear();
901 IMPL_LINK_NOARG(SearchTabPage_Impl, ActivateHdl, weld::ComboBox&, bool)
903 Search();
904 return true;
907 // class SearchTabPage_Impl ----------------------------------------------
909 SearchTabPage_Impl::SearchTabPage_Impl(weld::Widget* pParent, SfxHelpIndexWindow_Impl* pIdxWin)
910 : HelpTabPage_Impl(pParent, pIdxWin, "HelpSearchPage",
911 "sfx/ui/helpsearchpage.ui")
912 , m_xSearchED(m_xBuilder->weld_combo_box("search"))
913 , m_xSearchBtn(m_xBuilder->weld_button("find"))
914 , m_xFullWordsCB(m_xBuilder->weld_check_button("completewords"))
915 , m_xScopeCB(m_xBuilder->weld_check_button("headings"))
916 , m_xResultsLB(m_xBuilder->weld_tree_view("results"))
917 , m_xOpenBtn(m_xBuilder->weld_button("display"))
918 , xBreakIterator(vcl::unohelper::CreateBreakIterator())
920 m_xResultsLB->set_size_request(m_xResultsLB->get_approximate_digit_width() * 30,
921 m_xResultsLB->get_height_rows(15));
923 m_xSearchBtn->connect_clicked(LINK(this, SearchTabPage_Impl, ClickHdl));
924 m_xSearchED->connect_changed(LINK(this, SearchTabPage_Impl, ModifyHdl));
925 m_xSearchED->connect_entry_activate(LINK(this, SearchTabPage_Impl, ActivateHdl));
926 m_xOpenBtn->connect_clicked(LINK(this, SearchTabPage_Impl, OpenHdl));
927 m_xResultsLB->connect_row_activated(LINK(this, SearchTabPage_Impl, DoubleClickHdl));
929 SvtViewOptions aViewOpt( EViewType::TabPage, CONFIGNAME_SEARCHPAGE );
930 if ( aViewOpt.Exists() )
932 OUString aUserData;
933 Any aUserItem = aViewOpt.GetUserItem( USERITEM_NAME );
934 if ( aUserItem >>= aUserData )
936 sal_Int32 nIdx {0};
937 bool bChecked = aUserData.getToken(0, ';', nIdx).toInt32() == 1;
938 m_xFullWordsCB->set_active(bChecked);
939 bChecked = aUserData.getToken(0, ';', nIdx).toInt32() == 1;
940 m_xScopeCB->set_active(bChecked);
942 while ( nIdx > 0 )
944 m_xSearchED->append_text( INetURLObject::decode(
945 aUserData.getToken(0, ';', nIdx),
946 INetURLObject::DecodeMechanism::WithCharset ) );
951 ModifyHdl(*m_xSearchED);
954 SearchTabPage_Impl::~SearchTabPage_Impl()
956 SvtViewOptions aViewOpt( EViewType::TabPage, CONFIGNAME_SEARCHPAGE );
957 OUStringBuffer aUserData =
958 OUString::number(m_xFullWordsCB->get_active() ? 1 : 0) +
959 ";" +
960 OUString::number(m_xScopeCB->get_active() ? 1 : 0);
961 sal_Int32 nCount = std::min(m_xSearchED->get_count(), 10); // save only 10 entries
963 for ( sal_Int32 i = 0; i < nCount; ++i )
965 aUserData.append(";" +
966 INetURLObject::encode(
967 m_xSearchED->get_text(i),
968 INetURLObject::PART_UNO_PARAM_VALUE,
969 INetURLObject::EncodeMechanism::All ));
972 Any aUserItem = makeAny( aUserData.makeStringAndClear() );
973 aViewOpt.SetUserItem( USERITEM_NAME, aUserItem );
975 m_xSearchED.reset();
976 m_xSearchBtn.reset();
977 m_xFullWordsCB.reset();
978 m_xScopeCB.reset();
979 m_xResultsLB.reset();
980 m_xOpenBtn.reset();
983 void SearchTabPage_Impl::ClearSearchResults()
985 m_xResultsLB->clear();
988 void SearchTabPage_Impl::RememberSearchText( const OUString& rSearchText )
990 for (sal_Int32 i = 0, nEntryCount = m_xSearchED->get_count(); i < nEntryCount; ++i)
992 if (rSearchText == m_xSearchED->get_text(i))
994 m_xSearchED->remove(i);
995 break;
999 m_xSearchED->insert_text(0, rSearchText);
1002 IMPL_LINK_NOARG(SearchTabPage_Impl, ClickHdl, weld::Button&, void)
1004 Search();
1007 void SearchTabPage_Impl::Search()
1009 OUString aSearchText = comphelper::string::strip(m_xSearchED->get_active_text(), ' ');
1010 if ( aSearchText.isEmpty() )
1011 return;
1013 std::unique_ptr<weld::WaitObject> xWaitCursor(new weld::WaitObject(m_pIdxWin->GetFrameWeld()));
1014 ClearSearchResults();
1015 RememberSearchText( aSearchText );
1016 OUStringBuffer aSearchURL(HELP_URL);
1017 aSearchURL.append(aFactory);
1018 aSearchURL.append(HELP_SEARCH_TAG);
1019 if (!m_xFullWordsCB->get_active())
1020 aSearchText = sfx2::PrepareSearchString( aSearchText, xBreakIterator, true );
1021 aSearchURL.append(aSearchText);
1022 AppendConfigToken(aSearchURL, false);
1023 if (m_xScopeCB->get_active())
1024 aSearchURL.append("&Scope=Heading");
1025 std::vector< OUString > aFactories = SfxContentHelper::GetResultSet(aSearchURL.makeStringAndClear());
1026 for (const OUString & rRow : aFactories)
1028 sal_Int32 nIdx = 0;
1029 OUString aTitle = rRow.getToken(0, '\t', nIdx);
1030 OUString sURL(rRow.getToken(1, '\t', nIdx));
1031 m_xResultsLB->append(sURL, aTitle);
1033 xWaitCursor.reset();
1035 if ( aFactories.empty() )
1037 std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_xContainer.get(),
1038 VclMessageType::Info, VclButtonsType::Ok,
1039 SfxResId(STR_INFO_NOSEARCHRESULTS)));
1040 xBox->run();
1044 IMPL_LINK_NOARG(SearchTabPage_Impl, OpenHdl, weld::Button&, void)
1046 aDoubleClickHdl.Call(nullptr);
1049 IMPL_LINK(SearchTabPage_Impl, ModifyHdl, weld::ComboBox&, rComboBox, void)
1051 OUString aSearchText = comphelper::string::strip(m_xSearchED->get_active_text(), ' ');
1052 m_xSearchBtn->set_sensitive(!aSearchText.isEmpty());
1054 if (rComboBox.changed_by_direct_pick())
1055 Search();
1058 IMPL_LINK_NOARG(SearchTabPage_Impl, DoubleClickHdl, weld::TreeView&, bool)
1060 aDoubleClickHdl.Call(nullptr);
1061 return true;
1064 void SearchTabPage_Impl::SetDoubleClickHdl(const Link<LinkParamNone*, void>& rLink)
1066 aDoubleClickHdl = rLink;
1069 OUString SearchTabPage_Impl::GetSelectedEntry() const
1071 return m_xResultsLB->get_selected_id();
1074 void SearchTabPage_Impl::ClearPage()
1076 ClearSearchResults();
1077 m_xSearchED->set_entry_text(OUString());
1080 bool SearchTabPage_Impl::OpenKeyword( const OUString& rKeyword )
1082 bool bRet = false;
1083 m_xSearchED->set_entry_text(rKeyword);
1084 Search();
1085 if (m_xResultsLB->n_children() > 0)
1087 // found keyword -> open it
1088 m_xResultsLB->select(0);
1089 OpenHdl(*m_xOpenBtn);
1090 bRet = true;
1092 return bRet;
1095 // class BookmarksTabPage_Impl -------------------------------------------
1097 void BookmarksTabPage_Impl::DoAction(std::string_view rAction)
1099 if (rAction == "display")
1100 aDoubleClickHdl.Call(nullptr);
1101 else if (rAction == "rename")
1103 sal_Int32 nPos = m_xBookmarksBox->get_selected_index();
1104 if (nPos != -1)
1106 SfxAddHelpBookmarkDialog_Impl aDlg(m_xBookmarksBox.get(), true);
1107 aDlg.SetTitle(m_xBookmarksBox->get_text(nPos));
1108 if (aDlg.run() == RET_OK)
1110 OUString sURL = m_xBookmarksBox->get_id(nPos);
1111 m_xBookmarksBox->remove(nPos);
1112 m_xBookmarksBox->append(sURL, aDlg.GetTitle(), SvFileInformationManager::GetImageId(INetURLObject(IMAGE_URL+INetURLObject(sURL).GetHost())));
1113 m_xBookmarksBox->select(m_xBookmarksBox->n_children() - 1);
1117 else if (rAction == "delete")
1119 sal_Int32 nPos = m_xBookmarksBox->get_selected_index();
1120 if (nPos != -1)
1122 m_xBookmarksBox->remove(nPos);
1123 const sal_Int32 nCount = m_xBookmarksBox->n_children();
1124 if (nCount)
1126 if (nPos >= nCount)
1127 nPos = nCount - 1;
1128 m_xBookmarksBox->select(nPos);
1134 IMPL_LINK(BookmarksTabPage_Impl, CommandHdl, const CommandEvent&, rCEvt, bool)
1136 if (rCEvt.GetCommand() != CommandEventId::ContextMenu)
1137 return false;
1139 std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(m_xBookmarksBox.get(), "sfx/ui/bookmarkmenu.ui"));
1140 std::unique_ptr<weld::Menu> xMenu = xBuilder->weld_menu("menu");
1142 OString sIdent = xMenu->popup_at_rect(m_xBookmarksBox.get(), ::tools::Rectangle(rCEvt.GetMousePosPixel(), Size(1,1)));
1143 if (!sIdent.isEmpty())
1144 DoAction(sIdent);
1145 return true;
1148 IMPL_LINK(BookmarksTabPage_Impl, KeyInputHdl, const KeyEvent&, rKEvt, bool)
1150 bool bHandled = false;
1151 sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode();
1152 if (KEY_DELETE == nCode && m_xBookmarksBox->n_children() > 0)
1154 DoAction("delete");
1155 bHandled = true;
1157 return bHandled;
1160 // class BookmarksTabPage_Impl -------------------------------------------
1161 BookmarksTabPage_Impl::BookmarksTabPage_Impl(weld::Widget* pParent, SfxHelpIndexWindow_Impl* _pIdxWin)
1162 : HelpTabPage_Impl(pParent, _pIdxWin, "HelpBookmarkPage",
1163 "sfx/ui/helpbookmarkpage.ui")
1164 , m_xBookmarksBox(m_xBuilder->weld_tree_view("bookmarks"))
1165 , m_xBookmarksPB(m_xBuilder->weld_button("display"))
1167 m_xBookmarksBox->set_size_request(m_xBookmarksBox->get_approximate_digit_width() * 30,
1168 m_xBookmarksBox->get_height_rows(20));
1170 m_xBookmarksPB->connect_clicked( LINK(this, BookmarksTabPage_Impl, OpenHdl));
1171 m_xBookmarksBox->connect_row_activated(LINK(this, BookmarksTabPage_Impl, DoubleClickHdl));
1172 m_xBookmarksBox->connect_popup_menu(LINK(this, BookmarksTabPage_Impl, CommandHdl));
1173 m_xBookmarksBox->connect_key_press(LINK(this, BookmarksTabPage_Impl, KeyInputHdl));
1175 // load bookmarks from configuration
1176 const std::vector< SvtHistoryOptions::HistoryItem > aBookmarkSeq = SvtHistoryOptions::GetList( EHistoryType::HelpBookmarks );
1177 for ( const auto& rBookmark : aBookmarkSeq )
1179 AddBookmarks( rBookmark.sTitle, rBookmark.sURL );
1183 BookmarksTabPage_Impl::~BookmarksTabPage_Impl()
1185 // save bookmarks to configuration
1186 SvtHistoryOptions::Clear( EHistoryType::HelpBookmarks );
1187 const sal_Int32 nCount = m_xBookmarksBox->n_children();
1188 for (sal_Int32 i = 0; i < nCount; ++i)
1189 SvtHistoryOptions::AppendItem(EHistoryType::HelpBookmarks, m_xBookmarksBox->get_id(i), "", m_xBookmarksBox->get_text(i), std::nullopt);
1191 m_xBookmarksBox.reset();
1192 m_xBookmarksPB.reset();
1195 IMPL_LINK_NOARG(BookmarksTabPage_Impl, OpenHdl, weld::Button&, void)
1197 aDoubleClickHdl.Call(nullptr);
1200 IMPL_LINK_NOARG(BookmarksTabPage_Impl, DoubleClickHdl, weld::TreeView&, bool)
1202 aDoubleClickHdl.Call(nullptr);
1203 return true;
1206 void BookmarksTabPage_Impl::SetDoubleClickHdl(const Link<LinkParamNone*, void>& rLink)
1208 aDoubleClickHdl = rLink;
1211 OUString BookmarksTabPage_Impl::GetSelectedEntry() const
1213 return m_xBookmarksBox->get_selected_id();
1216 void BookmarksTabPage_Impl::AddBookmarks(const OUString& rTitle, const OUString& rURL)
1218 const OUString aImageURL {IMAGE_URL + INetURLObject(rURL).GetHost()};
1219 m_xBookmarksBox->append(rURL, rTitle, SvFileInformationManager::GetImageId(INetURLObject(aImageURL)));
1222 OUString SfxHelpWindow_Impl::buildHelpURL(std::u16string_view sFactory ,
1223 std::u16string_view sContent ,
1224 std::u16string_view sAnchor)
1226 OUStringBuffer sHelpURL(256);
1227 sHelpURL.append(HELP_URL);
1228 sHelpURL.append(sFactory);
1229 sHelpURL.append(sContent);
1230 AppendConfigToken(sHelpURL, true/*bUseQuestionMark*/);
1231 if (!sAnchor.empty())
1232 sHelpURL.append(sAnchor);
1233 return sHelpURL.makeStringAndClear();
1236 void SfxHelpWindow_Impl::loadHelpContent(const OUString& sHelpURL, bool bAddToHistory)
1238 Reference< XComponentLoader > xLoader(getTextFrame(), UNO_QUERY);
1239 if (!xLoader.is())
1240 return;
1242 // If a print job runs do not open a new page
1243 Reference< XFrame2 > xTextFrame = pTextWin->getFrame();
1244 Reference< XController > xTextController ;
1245 if (xTextFrame.is())
1246 xTextController = xTextFrame->getController ();
1247 if ( xTextController.is() && !xTextController->suspend( true ) )
1249 xTextController->suspend( false );
1250 return;
1253 // save url to history
1254 if (bAddToHistory)
1255 pHelpInterceptor->addURL(sHelpURL);
1257 if ( !IsWait() )
1258 EnterWait();
1259 bool bSuccess = false;
1260 // TODO implement locale fallback ... see below while(true)
1264 Reference< XComponent > xContent = xLoader->loadComponentFromURL(sHelpURL, "_self", 0, Sequence< PropertyValue >());
1265 if (xContent.is())
1267 bSuccess = true;
1270 catch(const RuntimeException&)
1271 { throw; }
1272 catch(const Exception&)
1273 { /*break;*/ }
1275 /* TODO try next locale ...
1276 no further locale available? => break loop and show error page
1279 openDone(sHelpURL, bSuccess);
1280 if ( IsWait() )
1281 LeaveWait();
1284 IMPL_LINK(SfxHelpIndexWindow_Impl, ActivatePageHdl, const OString&, rPage, void)
1286 GetPage(rPage)->Activate();
1289 SfxHelpIndexWindow_Impl::SfxHelpIndexWindow_Impl(SfxHelpWindow_Impl* _pParent, weld::Container* pContainer)
1290 : m_xBuilder(Application::CreateBuilder(pContainer, "sfx/ui/helpcontrol.ui"))
1291 , m_xContainer(m_xBuilder->weld_container("HelpControl"))
1292 , m_xActiveLB(m_xBuilder->weld_combo_box("active"))
1293 , m_xTabCtrl(m_xBuilder->weld_notebook("tabcontrol"))
1294 , aIdle("sfx2 appl SfxHelpIndexWindow_Impl")
1295 , aIndexKeywordLink(LINK(this, SfxHelpIndexWindow_Impl, KeywordHdl))
1296 , pParentWin(_pParent)
1297 , bIsInitDone(false)
1299 // create the pages
1300 GetContentPage();
1301 GetIndexPage();
1302 GetSearchPage();
1303 GetBookmarksPage();
1305 OString sPageId("index");
1306 SvtViewOptions aViewOpt( EViewType::TabDialog, CONFIGNAME_INDEXWIN );
1307 if ( aViewOpt.Exists() )
1309 OString sSavedPageId = aViewOpt.GetPageID();
1310 if (m_xTabCtrl->get_page_index(sSavedPageId) != -1)
1311 sPageId = sSavedPageId;
1313 m_xTabCtrl->set_current_page(sPageId);
1314 ActivatePageHdl(sPageId);
1315 m_xActiveLB->connect_changed(LINK(this, SfxHelpIndexWindow_Impl, SelectHdl));
1317 m_xTabCtrl->connect_enter_page(LINK(this, SfxHelpIndexWindow_Impl, ActivatePageHdl));
1319 aIdle.SetInvokeHandler( LINK( this, SfxHelpIndexWindow_Impl, InitHdl ) );
1320 aIdle.Start();
1322 m_xContainer->show();
1325 SfxHelpIndexWindow_Impl::~SfxHelpIndexWindow_Impl()
1327 SvtViewOptions aViewOpt(EViewType::TabDialog, CONFIGNAME_INDEXWIN);
1328 aViewOpt.SetPageID(m_xTabCtrl->get_current_page_ident());
1330 xCPage.reset();
1331 xIPage.reset();
1332 xSPage.reset();
1333 xBPage.reset();
1336 void SfxHelpIndexWindow_Impl::Initialize()
1338 OUStringBuffer aHelpURL(HELP_URL);
1339 AppendConfigToken(aHelpURL, true);
1340 std::vector<OUString> aFactories = SfxContentHelper::GetResultSet(aHelpURL.makeStringAndClear());
1341 for (const OUString & rRow : aFactories)
1343 sal_Int32 nIdx = 0;
1344 OUString aTitle = rRow.getToken( 0, '\t', nIdx ); // token 0
1345 OUString aURL = rRow.getToken( 1, '\t', nIdx ); // token 2
1346 OUString aFactory(INetURLObject(aURL).GetHost());
1347 m_xActiveLB->append(aFactory, aTitle);
1350 if (m_xActiveLB->get_active() == -1)
1351 SetActiveFactory();
1354 void SfxHelpIndexWindow_Impl::SetActiveFactory()
1356 DBG_ASSERT( xIPage, "index page not initialized" );
1357 if (!bIsInitDone && !m_xActiveLB->get_count())
1359 aIdle.Stop();
1360 InitHdl( nullptr );
1363 for (sal_Int32 i = 0, nEntryCount = m_xActiveLB->get_count(); i < nEntryCount; ++i)
1365 OUString aFactory = m_xActiveLB->get_id(i);
1366 aFactory = aFactory.toAsciiLowerCase();
1367 if (aFactory == xIPage->GetFactory())
1369 if (m_xActiveLB->get_active() != i)
1371 m_xActiveLB->set_active(i);
1372 aSelectFactoryLink.Call(nullptr);
1374 break;
1379 HelpTabPage_Impl* SfxHelpIndexWindow_Impl::GetPage(std::string_view rName)
1381 HelpTabPage_Impl* pPage = nullptr;
1383 if (rName == "contents")
1384 pPage = GetContentPage();
1385 else if (rName == "index")
1386 pPage = GetIndexPage();
1387 else if (rName == "find")
1388 pPage = GetSearchPage();
1389 else if (rName == "bookmarks")
1390 pPage = GetBookmarksPage();
1392 assert(pPage && "SfxHelpIndexWindow_Impl::GetCurrentPage(): no current page");
1394 return pPage;
1397 IMPL_LINK_NOARG(SfxHelpIndexWindow_Impl, SelectHdl, weld::ComboBox&, void)
1399 aIdle.Start();
1402 IMPL_LINK_NOARG(SfxHelpIndexWindow_Impl, InitHdl, Timer *, void)
1404 bIsInitDone = true;
1405 Initialize();
1407 // now use the timer for selection
1408 aIdle.SetInvokeHandler( LINK( this, SfxHelpIndexWindow_Impl, SelectFactoryHdl ) );
1409 aIdle.SetPriority( TaskPriority::LOWEST );
1412 IMPL_LINK_NOARG(SfxHelpIndexWindow_Impl, SelectFactoryHdl, Timer *, void)
1414 OUString aFactory = m_xActiveLB->get_active_id();
1415 if (!aFactory.isEmpty())
1417 SetFactory(aFactory.toAsciiLowerCase(), false);
1418 aSelectFactoryLink.Call(this);
1422 IMPL_LINK_NOARG(SfxHelpIndexWindow_Impl, KeywordHdl, IndexTabPage_Impl&, void)
1424 // keyword found on index?
1425 bool bIndex = xIPage->HasKeyword();
1427 if( !bIndex)
1428 bIndex = xIPage->HasKeywordIgnoreCase();
1429 // then set index or search page as current.
1430 OString sPageId = bIndex ? "index" : "find";
1431 if (sPageId != m_xTabCtrl->get_current_page_ident())
1432 m_xTabCtrl->set_current_page(sPageId);
1434 // at last we open the keyword
1435 if ( bIndex )
1436 xIPage->OpenKeyword();
1437 else if ( !xSPage->OpenKeyword( sKeyword ) )
1438 pParentWin->ShowStartPage();
1441 IMPL_LINK_NOARG(SfxHelpIndexWindow_Impl, IndexTabPageDoubleClickHdl, LinkParamNone*, void)
1443 aPageDoubleClickLink.Call(nullptr);
1446 void SfxHelpIndexWindow_Impl::SetDoubleClickHdl(const Link<LinkParamNone*, void>& rLink)
1448 aPageDoubleClickLink = rLink;
1451 IMPL_LINK_NOARG(SfxHelpIndexWindow_Impl, ContentTabPageDoubleClickHdl, LinkParamNone*, void)
1453 aPageDoubleClickLink.Call(nullptr);
1456 IMPL_LINK_NOARG(SfxHelpIndexWindow_Impl, TabPageDoubleClickHdl, LinkParamNone*, void)
1458 aPageDoubleClickLink.Call(nullptr);
1461 void SfxHelpIndexWindow_Impl::SetFactory( const OUString& rFactory, bool bActive )
1463 if ( !rFactory.isEmpty() )
1465 GetIndexPage()->SetFactory( rFactory );
1466 // the index page made a check if rFactory is valid,
1467 // so the index page always returns a valid factory
1468 GetSearchPage()->SetFactory( GetIndexPage()->GetFactory() );
1469 if ( bActive )
1470 SetActiveFactory();
1474 OUString SfxHelpIndexWindow_Impl::GetSelectedEntry() const
1476 OUString sRet;
1478 OString sName(m_xTabCtrl->get_current_page_ident());
1480 if (sName == "contents")
1482 sRet = xCPage->GetSelectedEntry();
1484 else if (sName == "index")
1486 sRet = xIPage->GetSelectedEntry();
1488 else if (sName == "find")
1490 sRet = xSPage->GetSelectedEntry();
1492 else if (sName == "bookmarks")
1494 sRet = xBPage->GetSelectedEntry();
1497 return sRet;
1500 void SfxHelpIndexWindow_Impl::AddBookmarks( const OUString& rTitle, const OUString& rURL )
1502 GetBookmarksPage()->AddBookmarks( rTitle, rURL );
1505 bool SfxHelpIndexWindow_Impl::IsValidFactory( std::u16string_view _rFactory )
1507 bool bValid = false;
1508 for (sal_Int32 i = 0, nEntryCount = m_xActiveLB->get_count(); i < nEntryCount; ++i)
1510 OUString aFactory = m_xActiveLB->get_id(i);
1511 if (aFactory == _rFactory)
1513 bValid = true;
1514 break;
1517 return bValid;
1520 void SfxHelpIndexWindow_Impl::ClearSearchPage()
1522 if ( xSPage )
1523 xSPage->ClearPage();
1526 void SfxHelpIndexWindow_Impl::GrabFocusBack()
1528 OString sName(m_xTabCtrl->get_current_page_ident());
1530 if (sName == "contents" && xCPage)
1531 xCPage->SetFocusOnBox();
1532 else if (sName == "index" && xIPage)
1533 xIPage->SetFocusOnBox();
1534 else if (sName == "find" && xSPage)
1535 xSPage->SetFocusOnBox();
1536 else if (sName == "bookmarks" && xBPage)
1537 xBPage->SetFocusOnBox();
1540 bool SfxHelpIndexWindow_Impl::HasFocusOnEdit() const
1542 bool bRet = false;
1543 OString sName(m_xTabCtrl->get_current_page_ident());
1544 if (sName == "index" && xIPage)
1545 bRet = xIPage->HasFocusOnEdit();
1546 else if (sName == "find" && xSPage)
1547 bRet = xSPage->HasFocusOnEdit();
1548 return bRet;
1551 OUString SfxHelpIndexWindow_Impl::GetSearchText() const
1553 OUString sRet;
1554 OString sName(m_xTabCtrl->get_current_page_ident());
1555 if (sName == "find" && xSPage)
1556 sRet = xSPage->GetSearchText();
1557 return sRet;
1560 bool SfxHelpIndexWindow_Impl::IsFullWordSearch() const
1562 bool bRet = false;
1563 OString sName(m_xTabCtrl->get_current_page_ident());
1564 if (sName == "find" && xSPage)
1565 bRet = xSPage->IsFullWordSearch();
1566 return bRet;
1569 void SfxHelpIndexWindow_Impl::OpenKeyword( const OUString& rKeyword )
1571 sKeyword = rKeyword;
1572 DBG_ASSERT( xIPage, "invalid index page" );
1573 xIPage->SetKeyword( sKeyword );
1576 void SfxHelpIndexWindow_Impl::SelectExecutableEntry()
1578 OString sName(m_xTabCtrl->get_current_page_ident());
1579 if (sName == "index" && xIPage )
1580 xIPage->SelectExecutableEntry();
1583 weld::Window* SfxHelpIndexWindow_Impl::GetFrameWeld() const
1585 return pParentWin->GetFrameWeld();
1588 // class TextWin_Impl ----------------------------------------------------
1589 TextWin_Impl::TextWin_Impl( vcl::Window* p ) : DockingWindow( p, 0 )
1593 bool TextWin_Impl::EventNotify( NotifyEvent& rNEvt )
1595 if( ( rNEvt.GetType() == MouseNotifyEvent::KEYINPUT ) && rNEvt.GetKeyEvent()->GetKeyCode().GetCode() == KEY_TAB )
1596 return GetParent()->EventNotify( rNEvt );
1597 else
1598 return DockingWindow::EventNotify( rNEvt );
1602 // remove docking area acceptor from layoutmanager, so it will not layout anything further .-)
1603 static void lcl_disableLayoutOfFrame(const Reference< XFrame2 >& xFrame)
1605 xFrame->setLayoutManager( Reference< XLayoutManager >() );
1608 // class SfxHelpTextWindow_Impl ------------------------------------------
1610 SfxHelpTextWindow_Impl::SfxHelpTextWindow_Impl(SfxHelpWindow_Impl* pHelpWin, weld::Builder& rBuilder, vcl::Window* pParent) :
1612 Window( pParent, WB_CLIPCHILDREN | WB_TABSTOP | WB_DIALOGCONTROL ),
1614 xToolBox ( rBuilder.weld_toolbar("toolbar") ),
1615 xOnStartupCB ( rBuilder.weld_check_button("checkbutton") ),
1616 xMenu ( rBuilder.weld_menu("menu") ),
1617 aSelectIdle ( "sfx2 appl SfxHelpTextWindow_Impl Select" ),
1618 aIndexOnImage ( BMP_HELP_TOOLBOX_INDEX_ON ),
1619 aIndexOffImage ( BMP_HELP_TOOLBOX_INDEX_OFF ),
1620 aIndexOnText ( SfxResId( STR_HELP_BUTTON_INDEX_ON ) ),
1621 aIndexOffText ( SfxResId( STR_HELP_BUTTON_INDEX_OFF ) ),
1622 aOnStartupText ( SfxResId( RID_HELP_ONSTARTUP_TEXT ) ),
1623 xHelpWin ( pHelpWin ),
1624 pTextWin ( VclPtr<TextWin_Impl>::Create( this ) ),
1625 bIsDebug ( false ),
1626 bIsIndexOn ( false ),
1627 bIsInClose ( false ),
1628 bIsFullWordSearch ( false )
1630 xFrame = Frame::create( ::comphelper::getProcessComponentContext() );
1631 xFrame->initialize( VCLUnoHelper::GetInterface ( pTextWin ) );
1632 xFrame->setName( "OFFICE_HELP" );
1633 lcl_disableLayoutOfFrame(xFrame);
1635 xToolBox->set_help_id(HID_HELP_TOOLBOX);
1637 xToolBox->set_item_tooltip_text("index", aIndexOffText );
1638 xToolBox->set_item_help_id("index", HID_HELP_TOOLBOXITEM_INDEX);
1639 xToolBox->set_item_help_id("backward", HID_HELP_TOOLBOXITEM_BACKWARD);
1640 xToolBox->set_item_help_id("forward", HID_HELP_TOOLBOXITEM_FORWARD);
1641 xToolBox->set_item_help_id("start", HID_HELP_TOOLBOXITEM_START);
1642 xToolBox->set_item_help_id("print", HID_HELP_TOOLBOXITEM_PRINT);
1643 xToolBox->set_item_help_id("bookmarks", HID_HELP_TOOLBOXITEM_BOOKMARKS );
1644 xToolBox->set_item_help_id("searchdialog", HID_HELP_TOOLBOXITEM_SEARCHDIALOG);
1646 InitToolBoxImages();
1647 InitOnStartupBox();
1648 xOnStartupCB->connect_toggled(LINK(this, SfxHelpTextWindow_Impl, CheckHdl));
1650 aSelectIdle.SetInvokeHandler( LINK( this, SfxHelpTextWindow_Impl, SelectHdl ) );
1651 aSelectIdle.SetPriority( TaskPriority::LOWEST );
1653 char* pEnv = getenv( "help_debug" );
1654 if ( pEnv )
1655 bIsDebug = true;
1657 SvtMiscOptions().AddListenerLink( LINK( this, SfxHelpTextWindow_Impl, NotifyHdl ) );
1660 SfxHelpTextWindow_Impl::~SfxHelpTextWindow_Impl()
1662 disposeOnce();
1665 void SfxHelpTextWindow_Impl::dispose()
1667 bIsInClose = true;
1668 SvtMiscOptions().RemoveListenerLink( LINK( this, SfxHelpTextWindow_Impl, NotifyHdl ) );
1669 m_xSrchDlg.reset();
1670 xToolBox.reset();
1671 xOnStartupCB.reset();
1672 xHelpWin.clear();
1673 pTextWin.disposeAndClear();
1674 vcl::Window::dispose();
1677 bool SfxHelpTextWindow_Impl::HasSelection() const
1679 // is there any selection in the text and not only a cursor?
1680 bool bRet = false;
1681 Reference < XTextRange > xRange = getCursor();
1682 if ( xRange.is() )
1684 Reference < XText > xText = xRange->getText();
1685 Reference < XTextCursor > xCursor = xText->createTextCursorByRange( xRange );
1686 bRet = !xCursor->isCollapsed();
1689 return bRet;
1692 void SfxHelpTextWindow_Impl::InitToolBoxImages()
1694 xToolBox->set_item_icon_name("index", bIsIndexOn ? aIndexOffImage : aIndexOnImage);
1697 void SfxHelpTextWindow_Impl::InitOnStartupBox()
1699 sCurrentFactory = SfxHelp::GetCurrentModuleIdentifier();
1701 Reference< XComponentContext > xContext = ::comphelper::getProcessComponentContext();
1702 const OUString sPath { PATH_OFFICE_FACTORIES + sCurrentFactory };
1704 // Attention: This check boy knows two states:
1705 // 1) Reading of the config key fails with an exception or by getting an empty Any (!) => check box must be hidden
1706 // 2) We read sal_True/sal_False => check box must be shown and enabled/disabled
1708 bool bHideBox = true;
1709 bool bHelpAtStartup = false;
1712 xConfiguration = ConfigurationHelper::openConfig(
1713 xContext, PACKAGE_SETUP, EConfigurationModes::Standard );
1714 if ( xConfiguration.is() )
1716 Any aAny = ConfigurationHelper::readRelativeKey( xConfiguration, sPath, KEY_HELP_ON_OPEN );
1717 if (aAny >>= bHelpAtStartup)
1718 bHideBox = false;
1721 catch( Exception& )
1723 bHideBox = true;
1726 if ( bHideBox )
1727 xOnStartupCB->hide();
1728 else
1730 // detect module name
1731 OUString sModuleName;
1733 if ( xConfiguration.is() )
1735 OUString sTemp;
1738 Any aAny = ConfigurationHelper::readRelativeKey( xConfiguration, sPath, KEY_UI_NAME );
1739 aAny >>= sTemp;
1741 catch( Exception const & )
1743 TOOLS_WARN_EXCEPTION( "sfx.appl", "SfxHelpTextWindow_Impl::InitOnStartupBox()" );
1745 sModuleName = sTemp;
1748 if ( !sModuleName.isEmpty() )
1750 // set module name in checkbox text
1751 xOnStartupCB->set_label(aOnStartupText.replaceFirst("%MODULENAME", sModuleName));
1752 // and show it
1753 xOnStartupCB->show();
1754 // set check state
1755 xOnStartupCB->set_active(bHelpAtStartup);
1756 xOnStartupCB->save_state();
1761 Reference< XBreakIterator > const & SfxHelpTextWindow_Impl::GetBreakIterator()
1763 if ( !xBreakIterator.is() )
1764 xBreakIterator = vcl::unohelper::CreateBreakIterator();
1765 DBG_ASSERT( xBreakIterator.is(), "Could not create BreakIterator" );
1766 return xBreakIterator;
1769 Reference< XTextRange > SfxHelpTextWindow_Impl::getCursor() const
1771 // return the current cursor
1772 Reference< XTextRange > xCursor;
1776 Reference < XSelectionSupplier > xSelSup( xFrame->getController(), UNO_QUERY );
1777 if ( xSelSup.is() )
1779 Any aAny = xSelSup->getSelection();
1780 Reference < XIndexAccess > xSelection;
1781 if ( aAny >>= xSelection )
1783 if ( xSelection->getCount() == 1 )
1785 aAny = xSelection->getByIndex(0);
1786 aAny >>= xCursor;
1791 catch( Exception& )
1793 TOOLS_WARN_EXCEPTION( "sfx.appl", "SfxHelpTextWindow_Impl::getCursor(): unexpected exception" );
1796 return xCursor;
1800 bool SfxHelpTextWindow_Impl::isHandledKey( const vcl::KeyCode& _rKeyCode )
1802 bool bRet = false;
1803 sal_uInt16 nCode = _rKeyCode.GetCode();
1805 // the keys <CTRL><A> (select all), <CTRL><C> (copy),
1806 // <CTRL><F> (find), <CTRL><P> (print) and <CTRL><W> (close window)
1807 // were handled in help
1808 if ( _rKeyCode.IsMod1() &&
1809 ( KEY_A == nCode || KEY_C == nCode || KEY_F == nCode || KEY_P == nCode || KEY_W == nCode ) )
1811 if ( KEY_F == nCode )
1812 DoSearch();
1813 else
1814 bRet = true;
1817 return bRet;
1821 IMPL_LINK_NOARG(SfxHelpTextWindow_Impl, SelectHdl, Timer *, void)
1825 // select the words, which are equal to the search text of the search page
1826 Reference < XController > xController = xFrame->getController();
1827 if ( xController.is() )
1829 // get document
1830 Reference < XSearchable > xSearchable( xController->getModel(), UNO_QUERY );
1831 if ( xSearchable.is() )
1833 // create descriptor, set string and find all words
1834 Reference < XSearchDescriptor > xSrchDesc = xSearchable->createSearchDescriptor();
1835 xSrchDesc->setPropertyValue( "SearchRegularExpression", makeAny( true ) );
1836 if ( bIsFullWordSearch )
1837 xSrchDesc->setPropertyValue( "SearchWords", makeAny( true ) );
1839 xSrchDesc->setSearchString( sfx2::PrepareSearchString( aSearchText, GetBreakIterator(), false ) );
1840 Reference< XIndexAccess > xSelection = xSearchable->findAll( xSrchDesc );
1842 // then select all found words
1843 Reference < XSelectionSupplier > xSelectionSup( xController, UNO_QUERY );
1844 if ( xSelectionSup.is() )
1846 xSelectionSup->select( Any(xSelection) );
1851 catch( Exception& )
1853 TOOLS_WARN_EXCEPTION( "sfx.appl", "SfxHelpTextWindow_Impl::SelectHdl(): unexpected exception" );
1858 IMPL_LINK_NOARG( SfxHelpTextWindow_Impl, NotifyHdl, LinkParamNone*, void )
1860 InitToolBoxImages();
1861 Resize();
1864 IMPL_LINK( SfxHelpTextWindow_Impl, FindHdl, sfx2::SearchDialog&, rDlg, void )
1866 FindHdl(&rDlg);
1868 void SfxHelpTextWindow_Impl::FindHdl(sfx2::SearchDialog* pDlg)
1870 bool bWrapAround = ( nullptr == pDlg );
1871 if ( bWrapAround )
1872 pDlg = m_xSrchDlg.get();
1873 DBG_ASSERT( pDlg, "invalid search dialog" );
1876 // select the words, which are equal to the search text of the search page
1877 Reference < XController > xController = xFrame->getController();
1878 if ( xController.is() )
1880 // get document
1881 Reference < XSearchable > xSearchable( xController->getModel(), UNO_QUERY );
1882 if ( xSearchable.is() )
1884 // create descriptor, set string and find all words
1885 Reference < XSearchDescriptor > xSrchDesc = xSearchable->createSearchDescriptor();
1886 xSrchDesc->setPropertyValue( "SearchWords", makeAny(pDlg->IsOnlyWholeWords()) );
1887 xSrchDesc->setPropertyValue( "SearchCaseSensitive", makeAny(pDlg->IsMarchCase()) );
1888 xSrchDesc->setPropertyValue( "SearchBackwards", makeAny(pDlg->IsSearchBackwards()) );
1889 xSrchDesc->setSearchString( pDlg->GetSearchText() );
1890 Reference< XInterface > xSelection;
1891 Reference< XTextRange > xCursor = getCursor();
1893 if ( xCursor.is() )
1895 if ( pDlg->IsSearchBackwards() )
1896 xCursor = xCursor->getStart();
1897 xSelection = xSearchable->findNext( xCursor, xSrchDesc );
1899 else
1900 xSelection = xSearchable->findFirst( xSrchDesc );
1902 // then select the found word
1903 if ( xSelection.is() )
1905 Reference < XSelectionSupplier > xSelectionSup( xController, UNO_QUERY );
1906 if ( xSelectionSup.is() )
1908 xSelectionSup->select( Any(xSelection) );
1911 else if ( pDlg->IsWrapAround() && !bWrapAround )
1913 Reference < text::XTextViewCursorSupplier > xCrsrSupp( xController, uno::UNO_QUERY );
1914 Reference < text::XTextViewCursor > xTVCrsr = xCrsrSupp->getViewCursor();
1915 if ( xTVCrsr.is() )
1917 Reference < text::XTextDocument > xDoc( xController->getModel(), uno::UNO_QUERY );
1918 Reference < text::XText > xText = xDoc->getText();
1919 if ( xText.is() )
1921 if ( pDlg->IsSearchBackwards() )
1922 xTVCrsr->gotoRange( xText->getEnd(), false );
1923 else
1924 xTVCrsr->gotoRange( xText->getStart(), false );
1925 FindHdl( nullptr );
1929 else
1931 assert(m_xSrchDlg && "no search dialog");
1932 std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_xSrchDlg->getDialog(),
1933 VclMessageType::Info, VclButtonsType::Ok, SfxResId(STR_INFO_NOSEARCHTEXTFOUND)));
1934 xBox->run();
1935 m_xSrchDlg->SetFocusOnEdit();
1940 catch( Exception& )
1942 TOOLS_WARN_EXCEPTION( "sfx.appl", "SfxHelpTextWindow_Impl::SelectHdl(): unexpected exception" );
1946 IMPL_LINK_NOARG(SfxHelpTextWindow_Impl, CloseHdl, LinkParamNone*, void)
1948 m_xSrchDlg.reset();
1951 IMPL_LINK_NOARG(SfxHelpTextWindow_Impl, CheckHdl, weld::Toggleable&, void)
1953 if ( !xConfiguration.is() )
1954 return;
1956 bool bChecked = xOnStartupCB->get_active();
1959 ConfigurationHelper::writeRelativeKey(
1960 xConfiguration, PATH_OFFICE_FACTORIES + sCurrentFactory, KEY_HELP_ON_OPEN, makeAny( bChecked ) );
1961 ConfigurationHelper::flush( xConfiguration );
1963 catch( Exception const & )
1965 TOOLS_WARN_EXCEPTION( "sfx.appl", "SfxHelpTextWindow_Impl::CheckHdl()" );
1969 void SfxHelpTextWindow_Impl::Resize()
1971 Size aSize = GetOutputSizePixel();
1972 pTextWin->SetPosSizePixel( Point(0, 0), aSize );
1975 bool SfxHelpTextWindow_Impl::PreNotify( NotifyEvent& rNEvt )
1977 bool bDone = false;
1978 MouseNotifyEvent nType = rNEvt.GetType();
1979 if ( MouseNotifyEvent::COMMAND == nType && rNEvt.GetCommandEvent() )
1981 const CommandEvent* pCmdEvt = rNEvt.GetCommandEvent();
1982 vcl::Window* pCmdWin = rNEvt.GetWindow();
1984 if ( pCmdEvt->GetCommand() == CommandEventId::ContextMenu && pCmdWin != this )
1986 Point aPos;
1987 if ( pCmdEvt->IsMouseEvent() )
1988 aPos = pCmdEvt->GetMousePosPixel();
1989 else
1990 aPos = Point( pTextWin->GetPosPixel().X() + 20, 20 );
1992 xMenu->clear();
1994 if (bIsIndexOn)
1995 xMenu->append("index", aIndexOffText, BMP_HELP_TOOLBOX_INDEX_OFF);
1996 else
1997 xMenu->append("index", aIndexOnText, BMP_HELP_TOOLBOX_INDEX_ON);
1999 xMenu->append_separator("separator1");
2000 xMenu->append("backward", SfxResId(STR_HELP_BUTTON_PREV), BMP_HELP_TOOLBOX_PREV);
2001 xMenu->set_sensitive("backward", xHelpWin->HasHistoryPredecessor());
2002 xMenu->append("forward", SfxResId(STR_HELP_BUTTON_NEXT), BMP_HELP_TOOLBOX_NEXT);
2003 xMenu->set_sensitive("forward", xHelpWin->HasHistorySuccessor());
2004 xMenu->append("start", SfxResId(STR_HELP_BUTTON_START), BMP_HELP_TOOLBOX_START);
2005 xMenu->append_separator("separator2");
2006 xMenu->append("print", SfxResId(STR_HELP_BUTTON_PRINT), BMP_HELP_TOOLBOX_PRINT);
2007 xMenu->append("bookmarks", SfxResId(STR_HELP_BUTTON_ADDBOOKMARK), BMP_HELP_TOOLBOX_BOOKMARKS);
2008 xMenu->append("searchdialog", SfxResId(STR_HELP_BUTTON_SEARCHDIALOG), BMP_HELP_TOOLBOX_SEARCHDIALOG);
2009 xMenu->append_separator("separator3");
2010 xMenu->append_check("selectionmode", SfxResId(STR_HELP_MENU_TEXT_SELECTION_MODE));
2011 URL aURL;
2012 aURL.Complete = ".uno:SelectTextMode";
2013 Reference< util::XURLTransformer > xTrans( util::URLTransformer::create( ::comphelper::getProcessComponentContext() ) );
2014 xTrans->parseStrict(aURL);
2015 Reference < XDispatch > xDisp = xFrame->queryDispatch( aURL, OUString(), 0 );
2016 if(xDisp.is())
2018 rtl::Reference<HelpStatusListener_Impl> pStateListener =
2019 new HelpStatusListener_Impl(xDisp, aURL );
2020 FeatureStateEvent rEvent = pStateListener->GetStateEvent();
2021 bool bCheck = false;
2022 rEvent.State >>= bCheck;
2023 xMenu->set_active("selectionmode", bCheck);
2025 xMenu->append_separator("separator4");
2026 xMenu->append("copy", SfxResId(STR_HELP_MENU_TEXT_COPY), BMP_HELP_TOOLBOX_COPY);
2027 xMenu->set_sensitive("copy", HasSelection());
2029 if ( bIsDebug )
2031 xMenu->append_separator("separator5");
2032 xMenu->append("sourceview", SfxResId(STR_HELP_BUTTON_SOURCEVIEW));
2035 int x, y, width, height;
2036 weld::Window* pTopLevel = GetFrameWeld();
2037 xHelpWin->GetContainer()->get_extents_relative_to(*pTopLevel, x, y, width, height);
2038 aPos.AdjustX(x);
2039 aPos.AdjustY(y);
2041 xHelpWin->DoAction(xMenu->popup_at_rect(pTopLevel, tools::Rectangle(aPos, Size(1,1))));
2042 bDone = true;
2045 else if ( MouseNotifyEvent::KEYINPUT == nType && rNEvt.GetKeyEvent() )
2047 const KeyEvent* pKEvt = rNEvt.GetKeyEvent();
2048 const vcl::KeyCode& rKeyCode = pKEvt->GetKeyCode();
2049 sal_uInt16 nKeyGroup = rKeyCode.GetGroup();
2050 sal_uInt16 nKey = rKeyCode.GetCode();
2051 if ( KEYGROUP_ALPHA == nKeyGroup && !isHandledKey( rKeyCode ) )
2053 // do nothing disables the writer accelerators
2054 bDone = true;
2056 else if ( rKeyCode.IsMod1() && ( KEY_F4 == nKey || KEY_W == nKey ) )
2058 // <CTRL><F4> or <CTRL><W> -> close top frame
2059 xHelpWin->CloseWindow();
2060 bDone = true;
2062 else if ( KEY_TAB == nKey && xOnStartupCB->has_focus() )
2064 xToolBox->grab_focus();
2065 bDone = true;
2069 return bDone || Window::PreNotify( rNEvt );
2073 void SfxHelpTextWindow_Impl::GetFocus()
2075 if ( bIsInClose )
2076 return;
2080 if( xFrame.is() )
2082 Reference< css::awt::XWindow > xWindow = xFrame->getComponentWindow();
2083 if( xWindow.is() )
2084 xWindow->setFocus();
2087 catch( Exception const & )
2089 TOOLS_WARN_EXCEPTION( "sfx.appl", "SfxHelpTextWindow_Impl::GetFocus()" );
2094 void SfxHelpTextWindow_Impl::DataChanged( const DataChangedEvent& rDCEvt )
2096 Window::DataChanged( rDCEvt );
2098 if ( ( ( rDCEvt.GetType() == DataChangedEventType::SETTINGS ) ||
2099 ( rDCEvt.GetType() == DataChangedEventType::DISPLAY ) ) &&
2100 ( rDCEvt.GetFlags() & AllSettingsFlags::STYLE ) )
2102 SetBackground( Wallpaper( GetSettings().GetStyleSettings().GetFaceColor() ) );
2103 InitToolBoxImages();
2107 void SfxHelpTextWindow_Impl::ToggleIndex( bool bOn )
2109 bIsIndexOn = bOn;
2110 if ( bIsIndexOn )
2112 xToolBox->set_item_icon_name("index", aIndexOffImage);
2113 xToolBox->set_item_tooltip_text("index", aIndexOffText);
2115 else
2117 xToolBox->set_item_icon_name("index", aIndexOnImage);
2118 xToolBox->set_item_tooltip_text("index", aIndexOnText);
2122 void SfxHelpTextWindow_Impl::SelectSearchText( const OUString& rSearchText, bool _bIsFullWordSearch )
2124 aSearchText = rSearchText;
2125 bIsFullWordSearch = _bIsFullWordSearch;
2126 aSelectIdle.Start();
2130 void SfxHelpTextWindow_Impl::SetPageStyleHeaderOff() const
2132 bool bSetOff = false;
2133 // set off the pagestyle header to prevent print output of the help URL
2136 Reference < XController > xController = xFrame->getController();
2137 Reference < XSelectionSupplier > xSelSup( xController, UNO_QUERY );
2138 if ( xSelSup.is() )
2140 Reference < XIndexAccess > xSelection;
2141 if ( xSelSup->getSelection() >>= xSelection )
2143 Reference < XTextRange > xRange;
2144 if ( xSelection->getByIndex(0) >>= xRange )
2146 Reference < XText > xText = xRange->getText();
2147 Reference < XPropertySet > xProps( xText->createTextCursorByRange( xRange ), UNO_QUERY );
2148 OUString sStyleName;
2149 if ( xProps->getPropertyValue( "PageStyleName" ) >>= sStyleName )
2151 Reference < XStyleFamiliesSupplier > xStyles( xController->getModel(), UNO_QUERY );
2152 Reference < XNameContainer > xContainer;
2153 if ( xStyles->getStyleFamilies()->getByName( "PageStyles" )
2154 >>= xContainer )
2156 Reference < XStyle > xStyle;
2157 if ( xContainer->getByName( sStyleName ) >>= xStyle )
2159 Reference < XPropertySet > xPropSet( xStyle, UNO_QUERY );
2160 xPropSet->setPropertyValue( "HeaderIsOn", makeAny( false ) );
2162 Reference< XModifiable > xReset(xStyles, UNO_QUERY);
2163 xReset->setModified(false);
2164 bSetOff = true;
2172 catch( Exception const & )
2174 TOOLS_WARN_EXCEPTION( "sfx.appl", "SfxHelpTextWindow_Impl::SetPageStyleHeaderOff()" );
2177 SAL_WARN_IF( !bSetOff, "sfx.appl", "SfxHelpTextWindow_Impl::SetPageStyleHeaderOff(): set off failed" );
2181 void SfxHelpTextWindow_Impl::CloseFrame()
2183 bIsInClose = true;
2186 css::uno::Reference< css::util::XCloseable > xCloseable ( xFrame, css::uno::UNO_QUERY );
2187 if (xCloseable.is())
2188 xCloseable->close(true);
2190 catch( css::util::CloseVetoException& )
2196 void SfxHelpTextWindow_Impl::DoSearch()
2198 if (m_xSrchDlg)
2199 return;
2201 // create the search dialog
2202 m_xSrchDlg = std::make_shared<sfx2::SearchDialog>(pTextWin->GetFrameWeld(), "HelpSearchDialog");
2203 // set handler
2204 m_xSrchDlg->SetFindHdl( LINK( this, SfxHelpTextWindow_Impl, FindHdl ) );
2205 m_xSrchDlg->SetCloseHdl( LINK( this, SfxHelpTextWindow_Impl, CloseHdl ) );
2206 // get selected text of the help page to set it as the search text
2207 Reference< XTextRange > xCursor = getCursor();
2208 if ( xCursor.is() )
2210 OUString sText = xCursor->getString();
2211 if ( !sText.isEmpty() )
2212 m_xSrchDlg->SetSearchText( sText );
2214 sfx2::SearchDialog::runAsync(m_xSrchDlg);
2217 void SfxHelpWindow_Impl::GetFocus()
2219 if (pTextWin)
2220 pTextWin->GrabFocus();
2221 else
2222 ResizableDockingWindow::GetFocus();
2225 void SfxHelpWindow_Impl::MakeLayout()
2227 Split();
2229 m_xHelpPaneWindow->set_visible(bIndex);
2232 IMPL_LINK(SfxHelpWindow_Impl, ResizeHdl, const Size&, rSize, void)
2234 int nNewWidth = rSize.Width();
2235 if (!nNewWidth)
2236 return;
2237 if (bSplit)
2238 nIndexSize = round(m_xContainer->get_position() * 100.0 / nNewWidth);
2239 nWidth = nNewWidth;
2240 Split();
2241 nIndexSize = round(m_xContainer->get_position() * 100.0 / nWidth);
2244 void SfxHelpWindow_Impl::Split()
2246 if (!nWidth)
2247 return;
2248 m_xContainer->set_position(nWidth * nIndexSize / 100);
2249 bSplit = true;
2252 void SfxHelpWindow_Impl::LoadConfig()
2254 SvtViewOptions aViewOpt( EViewType::Window, CONFIGNAME_HELPWIN );
2255 if ( !aViewOpt.Exists() )
2256 return;
2257 bIndex = aViewOpt.IsVisible();
2259 Any aUserItem = aViewOpt.GetUserItem( USERITEM_NAME );
2260 OUString aUserData;
2261 if ( aUserItem >>= aUserData )
2263 DBG_ASSERT( comphelper::string::getTokenCount(aUserData, ';') == 6, "invalid user data" );
2264 sal_Int32 nIdx = 0;
2265 nIndexSize = aUserData.getToken( 0, ';', nIdx ).toInt32();
2266 aUserData.getToken(0, ';', nIdx); // ignore nTextSize
2267 sal_Int32 nOldWidth = aUserData.getToken( 0, ';', nIdx ).toInt32();
2268 sal_Int32 nOldHeight = aUserData.getToken( 0, ';', nIdx ).toInt32();
2269 aWinSize = Size(nOldWidth, nOldHeight);
2270 aWinPos.setX( aUserData.getToken( 0, ';', nIdx ).toInt32() );
2271 aWinPos.setY( aUserData.getToken( 0, ';', nIdx ).toInt32() );
2274 pTextWin->ToggleIndex( bIndex );
2277 void SfxHelpWindow_Impl::SaveConfig()
2279 SvtViewOptions aViewOpt( EViewType::Window, CONFIGNAME_HELPWIN );
2280 sal_Int32 nW = 0, nH = 0;
2282 if ( xWindow.is() )
2284 css::awt::Rectangle aRect = xWindow->getPosSize();
2285 nW = aRect.Width;
2286 nH = aRect.Height;
2289 aViewOpt.SetVisible( bIndex );
2290 VclPtr<vcl::Window> pScreenWin = VCLUnoHelper::GetWindow( xWindow );
2291 aWinPos = pScreenWin->GetWindowExtentsRelative( nullptr ).TopLeft();
2292 if (bSplit)
2293 nIndexSize = round(m_xContainer->get_position() * 100.0 / nWidth);
2294 const OUString aUserData = OUString::number( nIndexSize )
2295 + ";" + OUString::number( 100 - nIndexSize )
2296 + ";" + OUString::number( nW )
2297 + ";" + OUString::number( nH )
2298 + ";" + OUString::number( aWinPos.X() )
2299 + ";" + OUString::number( aWinPos.Y() );
2301 aViewOpt.SetUserItem( USERITEM_NAME, makeAny( aUserData ) );
2304 void SfxHelpWindow_Impl::ShowStartPage()
2306 loadHelpContent(SfxHelpWindow_Impl::buildHelpURL(xIndexWin->GetFactory(), u"/start", u""));
2309 IMPL_LINK(SfxHelpWindow_Impl, SelectHdl, const OString&, rCurItem, void)
2311 bGrabFocusToToolBox = pTextWin->GetToolBox().has_focus();
2312 DoAction(rCurItem);
2315 IMPL_LINK_NOARG(SfxHelpWindow_Impl, OpenHdl, LinkParamNone*, void)
2317 xIndexWin->SelectExecutableEntry();
2318 OUString aEntry = xIndexWin->GetSelectedEntry();
2320 if ( aEntry.isEmpty() )
2321 return;
2323 OUString sHelpURL;
2325 bool bComplete = aEntry.toAsciiLowerCase().match("vnd.sun.star.help");
2327 if (bComplete)
2328 sHelpURL = aEntry;
2329 else
2331 OUString aId;
2332 OUString aAnchor('#');
2333 if ( comphelper::string::getTokenCount(aEntry, '#') == 2 )
2335 sal_Int32 nIdx{ 0 };
2336 aId = aEntry.getToken( 0, '#', nIdx );
2337 aAnchor += aEntry.getToken( 0, '#', nIdx );
2339 else
2340 aId = aEntry;
2342 sHelpURL = SfxHelpWindow_Impl::buildHelpURL(xIndexWin->GetFactory(), OUStringConcatenation("/" + aId), aAnchor);
2345 loadHelpContent(sHelpURL);
2348 IMPL_LINK( SfxHelpWindow_Impl, SelectFactoryHdl, SfxHelpIndexWindow_Impl* , pWin, void )
2350 if ( sTitle.isEmpty() )
2351 sTitle = GetParent()->GetText();
2353 Reference< XTitle > xTitle(xFrame, UNO_QUERY);
2354 if (xTitle.is ())
2355 xTitle->setTitle(sTitle + " - " + xIndexWin->GetActiveFactoryTitle());
2357 if ( pWin )
2358 ShowStartPage();
2359 xIndexWin->ClearSearchPage();
2363 IMPL_LINK( SfxHelpWindow_Impl, ChangeHdl, HelpListener_Impl&, rListener, void )
2365 SetFactory( rListener.GetFactory() );
2369 void SfxHelpWindow_Impl::openDone(const OUString& sURL ,
2370 bool bSuccess)
2372 INetURLObject aObj( sURL );
2373 if ( aObj.GetProtocol() == INetProtocol::VndSunStarHelp )
2374 SetFactory( aObj.GetHost() );
2375 if ( IsWait() )
2376 LeaveWait();
2377 if ( bGrabFocusToToolBox )
2379 pTextWin->GetToolBox().grab_focus();
2380 bGrabFocusToToolBox = false;
2382 else
2383 xIndexWin->GrabFocusBack();
2384 if ( !bSuccess )
2385 return;
2387 // set some view settings: "prevent help tips" and "helpid == 68245"
2390 Reference < XController > xController = pTextWin->getFrame()->getController();
2391 if ( xController.is() )
2393 Reference < XViewSettingsSupplier > xSettings( xController, UNO_QUERY );
2394 Reference < XPropertySet > xViewProps = xSettings->getViewSettings();
2395 Reference< XPropertySetInfo > xInfo = xViewProps->getPropertySetInfo();
2396 xViewProps->setPropertyValue( "ShowContentTips", makeAny( false ) );
2397 xViewProps->setPropertyValue( "ShowGraphics", makeAny( true ) );
2398 xViewProps->setPropertyValue( "ShowTables", makeAny( true ) );
2399 xViewProps->setPropertyValue( "HelpURL", makeAny( OUString("HID:SFX2_HID_HELP_ONHELP") ) );
2400 OUString sProperty( "IsExecuteHyperlinks" );
2401 if ( xInfo->hasPropertyByName( sProperty ) )
2402 xViewProps->setPropertyValue( sProperty, makeAny( true ) );
2403 xController->restoreViewData(Any());
2406 catch( Exception& )
2408 TOOLS_WARN_EXCEPTION( "sfx.appl", "SfxHelpWindow_Impl::OpenDoneHdl(): unexpected exception" );
2411 // When the SearchPage opens the help doc, then select all words, which are equal to its text
2412 OUString sSearchText = comphelper::string::strip(xIndexWin->GetSearchText(), ' ');
2413 if ( !sSearchText.isEmpty() )
2414 pTextWin->SelectSearchText( sSearchText, xIndexWin->IsFullWordSearch() );
2416 // no page style header -> this prevents a print output of the URL
2417 pTextWin->SetPageStyleHeaderOff();
2421 SfxHelpWindow_Impl::SfxHelpWindow_Impl(
2422 const css::uno::Reference < css::frame::XFrame2 >& rFrame,
2423 vcl::Window* pParent ) :
2425 ResizableDockingWindow(pParent),
2427 xFrame ( rFrame ),
2428 pTextWin ( nullptr ),
2429 pHelpInterceptor ( new HelpInterceptor_Impl() ),
2430 pHelpListener ( new HelpListener_Impl( pHelpInterceptor ) ),
2431 bIndex ( true ),
2432 bGrabFocusToToolBox ( false ),
2433 bSplit ( false ),
2434 nWidth ( 0 ),
2435 nIndexSize ( 40 ), // % of width
2436 aWinPos ( 0, 0 ),
2437 aWinSize ( 0, 0 ),
2438 sTitle ( pParent->GetText() )
2440 SetStyle(GetStyle() & ~WB_DOCKABLE);
2442 SetHelpId( HID_HELP_WINDOW );
2444 m_xBuilder = Application::CreateInterimBuilder(m_xBox.get(), "sfx/ui/helpwindow.ui", false);
2445 m_xContainer = m_xBuilder->weld_paned("HelpWindow");
2446 m_xContainer->connect_size_allocate(LINK(this, SfxHelpWindow_Impl, ResizeHdl));
2447 m_xHelpPaneWindow = m_xBuilder->weld_container("helppanewindow");
2448 m_xHelpTextWindow = m_xBuilder->weld_container("helptextwindow");
2449 m_xHelpTextXWindow = m_xHelpTextWindow->CreateChildFrame();
2451 pHelpInterceptor->InitWaiter( this );
2452 xIndexWin.reset(new SfxHelpIndexWindow_Impl(this, m_xHelpPaneWindow.get()));
2453 xIndexWin->SetDoubleClickHdl( LINK( this, SfxHelpWindow_Impl, OpenHdl ) );
2454 xIndexWin->SetSelectFactoryHdl( LINK( this, SfxHelpWindow_Impl, SelectFactoryHdl ) );
2456 pTextWin = VclPtr<SfxHelpTextWindow_Impl>::Create(this, *m_xBuilder, VCLUnoHelper::GetWindow(m_xHelpTextXWindow));
2457 Reference < XFrames > xFrames = rFrame->getFrames();
2458 xFrames->append( Reference<XFrame>(pTextWin->getFrame(), UNO_QUERY_THROW) );
2459 pTextWin->SetSelectHdl( LINK( this, SfxHelpWindow_Impl, SelectHdl ) );
2460 pTextWin->Show();
2461 pHelpInterceptor->setInterception( Reference<XFrame>(pTextWin->getFrame(), UNO_QUERY_THROW) );
2462 pHelpListener->SetChangeHdl( LINK( this, SfxHelpWindow_Impl, ChangeHdl ) );
2463 LoadConfig();
2466 SfxHelpWindow_Impl::~SfxHelpWindow_Impl()
2468 disposeOnce();
2471 void SfxHelpWindow_Impl::dispose()
2473 SaveConfig();
2474 xIndexWin.reset();
2475 pTextWin->CloseFrame();
2476 pTextWin.disposeAndClear();
2478 m_xHelpTextXWindow->dispose();
2479 m_xHelpTextXWindow.clear();
2480 m_xHelpTextWindow.reset();
2481 m_xHelpPaneWindow.reset();
2482 m_xContainer.reset();
2483 m_xBuilder.reset();
2485 ResizableDockingWindow::dispose();
2488 bool SfxHelpWindow_Impl::PreNotify( NotifyEvent& rNEvt )
2490 bool bHandled = false;
2491 if ( rNEvt.GetType() == MouseNotifyEvent::KEYINPUT )
2493 // Backward == <ALT><LEFT> or <BACKSPACE> Forward == <ALT><RIGHT>
2494 const vcl::KeyCode& rKeyCode = rNEvt.GetKeyEvent()->GetKeyCode();
2495 sal_uInt16 nKey = rKeyCode.GetCode();
2496 if ( ( rKeyCode.IsMod2() && ( KEY_LEFT == nKey || KEY_RIGHT == nKey ) ) ||
2497 ( !rKeyCode.GetModifier() && KEY_BACKSPACE == nKey && !xIndexWin->HasFocusOnEdit() ) )
2499 DoAction( rKeyCode.GetCode() == KEY_RIGHT ? "forward" : "backward" );
2500 bHandled = true;
2502 else if ( rKeyCode.IsMod1() && ( KEY_F4 == nKey || KEY_W == nKey ) )
2504 // <CTRL><F4> or <CTRL><W> -> close top frame
2505 CloseWindow();
2506 bHandled = true;
2509 return bHandled || Window::PreNotify( rNEvt );
2512 void SfxHelpWindow_Impl::setContainerWindow( const Reference < css::awt::XWindow >& xWin )
2514 xWindow = xWin;
2515 MakeLayout();
2516 if (xWindow.is())
2518 VclPtr<vcl::Window> pScreenWin = VCLUnoHelper::GetWindow(xWindow);
2519 if (aWinSize.Width() && aWinSize.Height())
2520 pScreenWin->SetPosSizePixel(aWinPos, aWinSize);
2521 else
2522 pScreenWin->SetPosPixel(aWinPos);
2526 void SfxHelpWindow_Impl::SetFactory( const OUString& rFactory )
2528 xIndexWin->SetFactory( rFactory, true );
2531 void SfxHelpWindow_Impl::SetHelpURL( const OUString& rURL )
2533 INetURLObject aObj( rURL );
2534 if ( aObj.GetProtocol() == INetProtocol::VndSunStarHelp )
2535 SetFactory( aObj.GetHost() );
2538 void SfxHelpWindow_Impl::DoAction(std::string_view rActionId)
2540 if (rActionId == "index")
2542 bIndex = !bIndex;
2543 MakeLayout();
2544 pTextWin->ToggleIndex( bIndex );
2546 else if (rActionId == "start")
2548 ShowStartPage();
2550 else if (rActionId == "backward" || rActionId == "forward")
2552 URL aURL;
2553 aURL.Complete = ".uno:Backward";
2554 if (rActionId == "forward")
2555 aURL.Complete = ".uno:Forward";
2556 Reference< util::XURLTransformer > xTrans( util::URLTransformer::create( ::comphelper::getProcessComponentContext() ) );
2557 xTrans->parseStrict(aURL);
2558 pHelpInterceptor->dispatch( aURL, Sequence < PropertyValue >() );
2560 else if (rActionId == "searchdialog")
2562 pTextWin->DoSearch();
2564 else if (rActionId == "print" || rActionId == "sourceview" || rActionId == "copy" || rActionId == "selectionmode")
2566 Reference < XDispatchProvider > xProv = pTextWin->getFrame();
2567 if ( xProv.is() )
2569 URL aURL;
2570 if (rActionId == "print")
2571 aURL.Complete = ".uno:Print";
2572 else if (rActionId == "sourceview")
2573 aURL.Complete = ".uno:SourceView";
2574 else if (rActionId == "copy")
2575 aURL.Complete = ".uno:Copy";
2576 else // rActionId == "selectionmode"
2577 aURL.Complete = ".uno:SelectTextMode";
2578 Reference< util::XURLTransformer > xTrans( util::URLTransformer::create( ::comphelper::getProcessComponentContext() ) );
2579 xTrans->parseStrict(aURL);
2580 Reference < XDispatch > xDisp = xProv->queryDispatch( aURL, OUString(), 0 );
2581 if ( xDisp.is() )
2582 xDisp->dispatch( aURL, Sequence < PropertyValue >() );
2585 else if (rActionId == "bookmarks")
2587 OUString aURL = pHelpInterceptor->GetCurrentURL();
2588 if ( !aURL.isEmpty() )
2592 Content aCnt( aURL, Reference< css::ucb::XCommandEnvironment >(), comphelper::getProcessComponentContext() );
2593 css::uno::Reference< css::beans::XPropertySetInfo > xInfo = aCnt.getProperties();
2594 if ( xInfo->hasPropertyByName( PROPERTY_TITLE ) )
2596 css::uno::Any aAny = aCnt.getPropertyValue( PROPERTY_TITLE );
2597 OUString aValue;
2598 if ( aAny >>= aValue )
2600 SfxAddHelpBookmarkDialog_Impl aDlg(GetFrameWeld(), false);
2601 aDlg.SetTitle(aValue);
2602 if (aDlg.run() == RET_OK )
2604 xIndexWin->AddBookmarks( aDlg.GetTitle(), aURL );
2609 catch( Exception& )
2611 TOOLS_WARN_EXCEPTION( "sfx.appl", "SfxHelpWindow_Impl::DoAction(): unexpected exception" );
2617 void SfxHelpWindow_Impl::CloseWindow()
2621 // search for top frame
2622 Reference< XFramesSupplier > xCreator = getTextFrame()->getCreator();
2623 while ( xCreator.is() && !xCreator->isTop() )
2625 xCreator = xCreator->getCreator();
2628 // when found, close it
2629 if ( xCreator.is() && xCreator->isTop() )
2631 Reference < XCloseable > xCloser( xCreator, UNO_QUERY );
2632 if ( xCloser.is() )
2633 xCloser->close( false );
2636 catch( Exception const & )
2638 TOOLS_WARN_EXCEPTION( "sfx.appl", "SfxHelpWindow_Impl::CloseWindow()" );
2643 void SfxHelpWindow_Impl::UpdateToolbox()
2645 pTextWin->GetToolBox().set_item_sensitive("backward", pHelpInterceptor->HasHistoryPred());
2646 pTextWin->GetToolBox().set_item_sensitive("forward", pHelpInterceptor->HasHistorySucc());
2650 bool SfxHelpWindow_Impl::HasHistoryPredecessor() const
2652 return pHelpInterceptor->HasHistoryPred();
2656 bool SfxHelpWindow_Impl::HasHistorySuccessor() const
2658 return pHelpInterceptor->HasHistorySucc();
2661 // class SfxAddHelpBookmarkDialog_Impl -----------------------------------
2663 SfxAddHelpBookmarkDialog_Impl::SfxAddHelpBookmarkDialog_Impl(weld::Widget* pParent, bool bRename)
2664 : GenericDialogController(pParent, "sfx/ui/bookmarkdialog.ui", "BookmarkDialog")
2665 , m_xTitleED(m_xBuilder->weld_entry("entry"))
2666 , m_xAltTitle(m_xBuilder->weld_label("alttitle"))
2668 if (bRename)
2669 m_xDialog->set_title(m_xAltTitle->get_label());
2672 void SfxAddHelpBookmarkDialog_Impl::SetTitle(const OUString& rTitle)
2674 m_xTitleED->set_text(rTitle);
2675 m_xTitleED->select_region(0, -1);
2678 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */