1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20
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>
31
32 #include <sfx2/strings.hrc>
33 #include <helpids.h>
34 #include <bitmaps.hlst>
35
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>
84
85 #include <ucbhelper/content.hxx>
86 #include <unotools/ucbhelper.hxx>
87
88 #include <string_view>
89 #include <unordered_map>
90 #include <vector>
91
92 using namespace ::ucbhelper;
93 using namespace ::com::sun::star::ucb;
94
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;
107
108 using namespace ::comphelper;
109
110 // defines ---------------------------------------------------------------
111
112 #define CONFIGNAME_HELPWIN "OfficeHelp"
113 #define CONFIGNAME_INDEXWIN "OfficeHelpIndex"
114 #define CONFIGNAME_SEARCHPAGE "OfficeHelpSearch"
115 #define IMAGE_URL "private:factory/"
116
117 #define PROPERTY_KEYWORDLIST "KeywordList"
118 #define PROPERTY_KEYWORDREF "KeywordRef"
119 #define PROPERTY_ANCHORREF "KeywordAnchorForRef"
120 #define PROPERTY_TITLEREF "KeywordTitleForRef"
121 #define PROPERTY_TITLE "Title"
122 #define HELP_URL "vnd.sun.star.help://"
123 #define HELP_SEARCH_TAG "/?Query="
124 #define USERITEM_NAME "UserItem"
125
126 #define PACKAGE_SETUP "/org.openoffice.Setup"
127 #define PATH_OFFICE_FACTORIES "Office/Factories/"
128 #define KEY_HELP_ON_OPEN "ooSetupFactoryHelpOnOpen"
129 #define KEY_UI_NAME "ooSetupFactoryUIName"
130
131 namespace sfx2
132 {
133
134
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"
144 */
PrepareSearchString(const OUString & rSearchString,const Reference<XBreakIterator> & xBreak,bool bForSearch)145 static OUString PrepareSearchString( const OUString& rSearchString,
146 const Reference< XBreakIterator >& xBreak, bool bForSearch )
147 {
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 );
153
154 while ( aBoundary.startPos < aBoundary.endPos )
155 {
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] != '.' ) )
160 {
161 if ( bForSearch && sSearchToken[ sSearchToken.getLength() - 1 ] != '*' )
162 sSearchToken += "*";
163
164 if ( sSearchToken.getLength() > 1 ||
165 ( sSearchToken.getLength() > 0 && sSearchToken[ 0 ] != '*' ) )
166 {
167 if ( !sSearchStr.isEmpty() )
168 {
169 if ( bForSearch )
170 sSearchStr.append(" ");
171 else
172 sSearchStr.append("|");
173 }
174 sSearchStr.append(sSearchToken);
175 }
176 }
177 aBoundary = xBreak->nextWord( rSearchString, nStartPos,
178 aLocale, WordType::ANYWORD_IGNOREWHITESPACES );
179 }
180
181 return sSearchStr.makeStringAndClear();
182 }
183
184 // namespace sfx2
185 }
186
187
188 // struct IndexEntry_Impl ------------------------------------------------
189
190 namespace {
191
192 struct IndexEntry_Impl
193 {
194 bool m_bSubEntry;
195 OUString m_aURL;
196
IndexEntry_Impl__anon68e9030f0111::IndexEntry_Impl197 IndexEntry_Impl( const OUString& rURL, bool bSubEntry ) :
198 m_bSubEntry( bSubEntry ), m_aURL( rURL ) {}
199 };
200
201 // struct ContentEntry_Impl ----------------------------------------------
202
203 struct ContentEntry_Impl
204 {
205 OUString aURL;
206 bool bIsFolder;
207
ContentEntry_Impl__anon68e9030f0111::ContentEntry_Impl208 ContentEntry_Impl( const OUString& rURL, bool bFolder ) :
209 aURL( rURL ), bIsFolder( bFolder ) {}
210 };
211
212 }
213
InitRoot()214 void ContentTabPage_Impl::InitRoot()
215 {
216 std::vector< OUString > aList =
217 SfxContentHelper::GetHelpTreeViewContents( "vnd.sun.star.hier://com.sun.star.help.TreeView/" );
218
219 for (const OUString & aRow : aList)
220 {
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);
231 }
232 }
233
ClearChildren(const weld::TreeIter * pParent)234 void ContentTabPage_Impl::ClearChildren(const weld::TreeIter* pParent)
235 {
236 std::unique_ptr<weld::TreeIter> xEntry = m_xContentBox->make_iterator(pParent);
237 bool bEntry = m_xContentBox->iter_children(*xEntry);
238 while (bEntry)
239 {
240 ClearChildren(xEntry.get());
241 delete reinterpret_cast<ContentEntry_Impl*>(m_xContentBox->get_id(*xEntry).toInt64());
242 bEntry = m_xContentBox->iter_next_sibling(*xEntry);
243 }
244
245 }
246
IMPL_LINK(ContentTabPage_Impl,ExpandingHdl,const weld::TreeIter &,rIter,bool)247 IMPL_LINK(ContentTabPage_Impl, ExpandingHdl, const weld::TreeIter&, rIter, bool)
248 {
249 ContentEntry_Impl* pContentEntry = reinterpret_cast<ContentEntry_Impl*>(m_xContentBox->get_id(rIter).toInt64());
250 if (!m_xContentBox->iter_has_child(rIter))
251 {
252 try
253 {
254 if (pContentEntry)
255 {
256 std::vector<OUString > aList = SfxContentHelper::GetHelpTreeViewContents(pContentEntry->aURL);
257
258 for (const OUString & aRow : aList)
259 {
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 )
266 {
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);
270 }
271 else
272 {
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);
280 }
281 }
282 }
283 }
284 catch (const Exception&)
285 {
286 TOOLS_WARN_EXCEPTION( "sfx.appl", "ContentListBox_Impl::RequestingChildren(): unexpected exception" );
287 }
288 }
289
290 if (!pContentEntry || pContentEntry->bIsFolder)
291 m_xContentBox->set_image(rIter, aOpenBookImage);
292
293 return true;
294 }
295
IMPL_LINK(ContentTabPage_Impl,CollapsingHdl,const weld::TreeIter &,rIter,bool)296 IMPL_LINK(ContentTabPage_Impl, CollapsingHdl, const weld::TreeIter&, rIter, bool)
297 {
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);
301
302 return true;
303 }
304
GetSelectedEntry() const305 OUString ContentTabPage_Impl::GetSelectedEntry() const
306 {
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;
312 }
313
314 // class HelpTabPage_Impl ------------------------------------------------
HelpTabPage_Impl(weld::Widget * pParent,SfxHelpIndexWindow_Impl * pIdxWin,const OString & rID,const OUString & rUIXMLDescription)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)
319 {
320 }
321
~HelpTabPage_Impl()322 HelpTabPage_Impl::~HelpTabPage_Impl()
323 {
324 }
325
326 // class ContentTabPage_Impl ---------------------------------------------
ContentTabPage_Impl(weld::Widget * pParent,SfxHelpIndexWindow_Impl * pIdxWin)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)
335 {
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));
341
342 InitRoot();
343 }
344
IMPL_LINK_NOARG(ContentTabPage_Impl,DoubleClickHdl,weld::TreeView &,bool)345 IMPL_LINK_NOARG(ContentTabPage_Impl, DoubleClickHdl, weld::TreeView&, bool)
346 {
347 aDoubleClickHdl.Call(nullptr);
348 return false;
349 }
350
SetDoubleClickHdl(const Link<LinkParamNone *,void> & rLink)351 void ContentTabPage_Impl::SetDoubleClickHdl(const Link<LinkParamNone*, void>& rLink)
352 {
353 aDoubleClickHdl = rLink;
354 }
355
~ContentTabPage_Impl()356 ContentTabPage_Impl::~ContentTabPage_Impl()
357 {
358 std::unique_ptr<weld::TreeIter> xEntry = m_xContentBox->make_iterator();
359 bool bEntry = m_xContentBox->get_iter_first(*xEntry);
360 while (bEntry)
361 {
362 ClearChildren(xEntry.get());
363 delete reinterpret_cast<ContentEntry_Impl*>(m_xContentBox->get_id(*xEntry).toInt64());
364 bEntry = m_xContentBox->iter_next_sibling(*xEntry);
365 }
366 }
367
SelectExecutableEntry()368 void IndexTabPage_Impl::SelectExecutableEntry()
369 {
370 sal_Int32 nPos = m_xIndexList->find_text(m_xIndexEntry->get_text());
371 if (nPos == -1)
372 return;
373
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() ) )
379 {
380 pEntry = reinterpret_cast<IndexEntry_Impl*>(m_xIndexList->get_id(++nPos).toInt64());
381 aEntryText = m_xIndexList->get_text(nPos);
382 }
383
384 if ( nOldPos != nPos )
385 m_xIndexEntry->set_text(aEntryText);
386 }
387
388 // class IndexTabPage_Impl -----------------------------------------------
IndexTabPage_Impl(weld::Widget * pParent,SfxHelpIndexWindow_Impl * pIdxWin)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 , bIsActivated(false)
397 , nRowHeight(m_xIndexList->get_height_rows(1))
398 , nAllHeight(0)
399 {
400 m_xIndexList->set_size_request(m_xIndexList->get_approximate_digit_width() * 30, -1);
401
402 m_xOpenBtn->connect_clicked(LINK(this, IndexTabPage_Impl, OpenHdl));
403 aFactoryIdle.SetInvokeHandler( LINK(this, IndexTabPage_Impl, IdleHdl ));
404 aAutoCompleteIdle.SetInvokeHandler( LINK(this, IndexTabPage_Impl, AutoCompleteHdl ));
405 aKeywordTimer.SetInvokeHandler( LINK( this, IndexTabPage_Impl, TimeoutHdl ) );
406 m_xIndexList->connect_row_activated(LINK(this, IndexTabPage_Impl, DoubleClickHdl));
407 m_xIndexList->connect_changed(LINK(this, IndexTabPage_Impl, TreeChangeHdl));
408 m_xIndexList->connect_custom_get_size(LINK(this, IndexTabPage_Impl, CustomGetSizeHdl));
409 m_xIndexList->connect_custom_render(LINK(this, IndexTabPage_Impl, CustomRenderHdl));
410 m_xIndexList->set_column_custom_renderer(0, true);
411 m_xIndexList->connect_size_allocate(LINK(this, IndexTabPage_Impl, ResizeHdl));
412 m_xIndexEntry->connect_key_press(LINK(this, IndexTabPage_Impl, KeyInputHdl));
413 m_xIndexEntry->connect_changed(LINK(this, IndexTabPage_Impl, EntryChangeHdl));
414 m_xIndexEntry->connect_activate(LINK(this, IndexTabPage_Impl, ActivateHdl));
415 }
416
IMPL_LINK(IndexTabPage_Impl,ResizeHdl,const Size &,rSize,void)417 IMPL_LINK(IndexTabPage_Impl, ResizeHdl, const Size&, rSize, void)
418 {
419 nAllHeight = rSize.Height();
420 }
421
IMPL_LINK_NOARG(IndexTabPage_Impl,CustomGetSizeHdl,weld::TreeView::get_size_args,Size)422 IMPL_LINK_NOARG(IndexTabPage_Impl, CustomGetSizeHdl, weld::TreeView::get_size_args, Size)
423 {
424 return Size(m_xIndexList->get_size_request().Width(), nRowHeight);
425 }
426
IMPL_LINK(IndexTabPage_Impl,CustomRenderHdl,weld::TreeView::render_args,aPayload,void)427 IMPL_LINK(IndexTabPage_Impl, CustomRenderHdl, weld::TreeView::render_args, aPayload, void)
428 {
429 vcl::RenderContext& rRenderContext = std::get<0>(aPayload);
430 const ::tools::Rectangle& rRect = std::get<1>(aPayload);
431 bool bSelected = std::get<2>(aPayload);
432 const OUString& rId = std::get<3>(aPayload);
433
434 rRenderContext.Push(PushFlags::TEXTCOLOR);
435 const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
436 if (bSelected)
437 rRenderContext.SetTextColor(rStyleSettings.GetHighlightTextColor());
438 else
439 rRenderContext.SetTextColor(rStyleSettings.GetDialogTextColor());
440
441 Point aPos(rRect.TopLeft());
442 aPos.AdjustY((rRect.GetHeight() - rRenderContext.GetTextHeight()) / 2);
443
444 int nIndex = m_xIndexList->find_id(rId);
445 OUString aEntry(m_xIndexList->get_text(nIndex));
446
447 IndexEntry_Impl* pEntry = reinterpret_cast<IndexEntry_Impl*>(rId.toInt64());
448 if (pEntry && pEntry->m_bSubEntry)
449 {
450 // indent sub entries
451 aPos.AdjustX(8);
452 sal_Int32 nPos = aEntry.indexOf(';');
453 rRenderContext.DrawText(aPos, (nPos !=-1) ? aEntry.copy(nPos + 1) : aEntry);
454 }
455 else
456 rRenderContext.DrawText(aPos, aEntry);
457
458 rRenderContext.Pop();
459 }
460
IMPL_LINK_NOARG(IndexTabPage_Impl,TreeChangeHdl,weld::TreeView &,void)461 IMPL_LINK_NOARG(IndexTabPage_Impl, TreeChangeHdl, weld::TreeView&, void)
462 {
463 m_xIndexEntry->set_text(m_xIndexList->get_selected_text());
464 }
465
IMPL_LINK_NOARG(IndexTabPage_Impl,EntryChangeHdl,weld::Entry &,void)466 IMPL_LINK_NOARG(IndexTabPage_Impl, EntryChangeHdl, weld::Entry&, void)
467 {
468 aAutoCompleteIdle.Start();
469 }
470
IMPL_LINK(IndexTabPage_Impl,KeyInputHdl,const KeyEvent &,rKEvt,bool)471 IMPL_LINK(IndexTabPage_Impl, KeyInputHdl, const KeyEvent&, rKEvt, bool)
472 {
473 const vcl::KeyCode& rKCode = rKEvt.GetKeyCode();
474 if (rKCode.GetModifier()) // only with no modifiers held
475 return false;
476
477 sal_uInt16 nCode = rKCode.GetCode();
478
479 if (nCode == KEY_UP || nCode == KEY_PAGEUP ||
480 nCode == KEY_DOWN || nCode == KEY_PAGEDOWN)
481 {
482 // disable_notify_events();
483 sal_Int32 nIndex = m_xIndexList->get_selected_index();
484 sal_Int32 nOrigIndex = nIndex;
485 sal_Int32 nCount = m_xIndexList->n_children();
486 if (nIndex == -1)
487 {
488 m_xIndexList->set_cursor(0);
489 m_xIndexList->select(0);
490 m_xIndexEntry->set_text(m_xIndexList->get_selected_text());
491 }
492 else
493 {
494 if (nCode == KEY_UP)
495 --nIndex;
496 else if (nCode == KEY_DOWN)
497 ++nIndex;
498 else if (nCode == KEY_PAGEUP)
499 {
500 int nVisRows = nAllHeight / nRowHeight;
501 nIndex -= nVisRows;
502 }
503 else if (nCode == KEY_PAGEDOWN)
504 {
505 int nVisRows = nAllHeight / nRowHeight;
506 nIndex += nVisRows;
507 }
508
509 if (nIndex < 0)
510 nIndex = 0;
511 if (nIndex >= nCount)
512 nIndex = nCount - 1;
513
514 if (nIndex != nOrigIndex)
515 {
516 m_xIndexList->set_cursor(nIndex);
517 m_xIndexList->select(nIndex);
518 m_xIndexEntry->set_text(m_xIndexList->get_selected_text());
519 }
520
521 // m_xIndexList->grab_focus();
522 // g_signal_emit_by_name(pWidget, "key-press-event", pEvent, &ret);
523 // m_xIndexEntry->set_text(m_xIndexList->get_selected_text());
524 // m_xIndexEntry->grab_focus();
525 }
526 m_xIndexEntry->select_region(0, -1);
527 // enable_notify_events();
528 // m_bTreeChange = true;
529 // m_pEntry->fire_signal_changed();
530 // m_bTreeChange = false;
531 return true;
532 }
533 return false;
534 }
535
~IndexTabPage_Impl()536 IndexTabPage_Impl::~IndexTabPage_Impl()
537 {
538 ClearIndex();
539 }
540
541 namespace sfx2 {
542
543 typedef std::unordered_map< OUString, int > KeywordInfo;
544 }
545
InitializeIndex()546 void IndexTabPage_Impl::InitializeIndex()
547 {
548 weld::WaitObject aWaitCursor(m_pIdxWin->GetFrameWeld());
549
550 // By now more than 256 equal entries are not allowed
551 sal_Unicode append[256];
552 for(sal_Unicode & k : append)
553 k = ' ';
554
555 sfx2::KeywordInfo aInfo;
556 m_xIndexList->freeze();
557
558 try
559 {
560 OUStringBuffer aURL = HELP_URL;
561 aURL.append(sFactory);
562 AppendConfigToken(aURL, true);
563
564 Content aCnt( aURL.makeStringAndClear(), Reference< css::ucb::XCommandEnvironment >(), comphelper::getProcessComponentContext() );
565 css::uno::Reference< css::beans::XPropertySetInfo > xInfo = aCnt.getProperties();
566 if ( xInfo->hasPropertyByName( PROPERTY_ANCHORREF ) )
567 {
568 css::uno::Sequence< OUString > aPropSeq( 4 );
569 aPropSeq[0] = PROPERTY_KEYWORDLIST;
570 aPropSeq[1] = PROPERTY_KEYWORDREF;
571 aPropSeq[2] = PROPERTY_ANCHORREF;
572 aPropSeq[3] = PROPERTY_TITLEREF;
573
574 // abi: use one possibly remote call only
575 css::uno::Sequence< css::uno::Any > aAnySeq =
576 aCnt.getPropertyValues( aPropSeq );
577
578 css::uno::Sequence< OUString > aKeywordList;
579 css::uno::Sequence< css::uno::Sequence< OUString > > aKeywordRefList;
580 css::uno::Sequence< css::uno::Sequence< OUString > > aAnchorRefList;
581 css::uno::Sequence< css::uno::Sequence< OUString > > aTitleRefList;
582
583 if ( ( aAnySeq[0] >>= aKeywordList ) && ( aAnySeq[1] >>= aKeywordRefList ) &&
584 ( aAnySeq[2] >>= aAnchorRefList ) && ( aAnySeq[3] >>= aTitleRefList ) )
585 {
586 int ndx,tmp;
587 OUString aIndex, aTempString;
588 OUStringBuffer aData( 128 ); // Capacity of up to 128 characters
589 sfx2::KeywordInfo::iterator it;
590
591 for ( int i = 0; i < aKeywordList.getLength(); ++i )
592 {
593 // abi: Do not copy, but use references
594 const OUString& aKeywordPair = aKeywordList[i];
595 DBG_ASSERT( !aKeywordPair.isEmpty(), "invalid help index" );
596 const css::uno::Sequence< OUString >& aRefList = aKeywordRefList[i];
597 const css::uno::Sequence< OUString >& aAnchorList = aAnchorRefList[i];
598 const css::uno::Sequence< OUString >& aTitleList = aTitleRefList[i];
599
600 DBG_ASSERT( aRefList.getLength() == aAnchorList.getLength(),"reference list and title list of different length" );
601
602 ndx = aKeywordPair.indexOf( ';' );
603 const bool insert = ndx != -1;
604
605 OUString sId;
606
607 if ( insert )
608 {
609 aTempString = aKeywordPair.copy( 0, ndx );
610 if ( aIndex != aTempString )
611 {
612 aIndex = aTempString;
613 it = aInfo.emplace(aTempString, 0).first;
614 sId = OUString::number(reinterpret_cast<sal_Int64>(new IndexEntry_Impl(OUString(), false)));
615 if ( (tmp = it->second++) != 0)
616 m_xIndexList->append(
617 sId, aTempString + std::u16string_view(append, tmp));
618 else
619 m_xIndexList->append(sId, aTempString);
620 }
621 }
622 else
623 aIndex.clear();
624
625 sal_uInt32 nRefListLen = aRefList.getLength();
626
627 DBG_ASSERT( aAnchorList.hasElements(), "*IndexTabPage_Impl::InitializeIndex(): AnchorList is empty!" );
628 DBG_ASSERT( nRefListLen, "*IndexTabPage_Impl::InitializeIndex(): RefList is empty!" );
629
630 if ( aAnchorList.hasElements() && nRefListLen )
631 {
632 if ( aAnchorList[0].getLength() > 0 )
633 {
634 aData.append( aRefList[0] ).append( '#' ).append( aAnchorList[0] );
635 sId = OUString::number(reinterpret_cast<sal_Int64>(new IndexEntry_Impl(aData.makeStringAndClear(), insert)));
636 }
637 else
638 sId = OUString::number(reinterpret_cast<sal_Int64>(new IndexEntry_Impl(aRefList[0], insert)));
639 }
640
641 // Assume the token is trimmed
642 it = aInfo.emplace(aKeywordPair, 0).first;
643 if ((tmp = it->second++) != 0)
644 m_xIndexList->append(sId, aKeywordPair + std::u16string_view(append, tmp));
645 else
646 m_xIndexList->append(sId, aKeywordPair);
647
648 for ( sal_uInt32 j = 1; j < nRefListLen ; ++j )
649 {
650 aData
651 .append( aKeywordPair )
652 .append( ' ' )
653 .append( '-' )
654 .append( ' ' )
655 .append( aTitleList[j] );
656
657 aTempString = aData.makeStringAndClear();
658
659 if ( aAnchorList[j].getLength() > 0 )
660 {
661 aData.append( aRefList[j] ).append( '#' ).append( aAnchorList[j] );
662 sId = OUString::number(reinterpret_cast<sal_Int64>(new IndexEntry_Impl(aData.makeStringAndClear(), insert)));
663 }
664 else
665 sId = OUString::number(reinterpret_cast<sal_Int64>(new IndexEntry_Impl(aRefList[j], insert)));
666
667 it = aInfo.emplace(aTempString, 0).first;
668 if ( (tmp = it->second++) != 0 )
669 m_xIndexList->append(
670 sId, aTempString + std::u16string_view(append, tmp));
671 else
672 m_xIndexList->append(sId, aTempString);
673 }
674 }
675 }
676 }
677 }
678 catch( Exception& )
679 {
680 TOOLS_WARN_EXCEPTION( "sfx.appl", "IndexTabPage_Impl::InitializeIndex(): unexpected exception" );
681 }
682
683 m_xIndexList->thaw();
684
685 if ( !sKeyword.isEmpty() )
686 aKeywordLink.Call( *this );
687 }
688
ClearIndex()689 void IndexTabPage_Impl::ClearIndex()
690 {
691 const sal_Int32 nCount = m_xIndexList->n_children();
692 for ( sal_Int32 i = 0; i < nCount; ++i )
693 delete reinterpret_cast<IndexEntry_Impl*>(m_xIndexList->get_id(i).toInt64());
694 m_xIndexList->clear();
695 }
696
IMPL_LINK_NOARG(IndexTabPage_Impl,OpenHdl,weld::Button &,void)697 IMPL_LINK_NOARG(IndexTabPage_Impl, OpenHdl, weld::Button&, void)
698 {
699 aDoubleClickHdl.Call(nullptr);
700 }
701
IMPL_LINK_NOARG(IndexTabPage_Impl,ActivateHdl,weld::Entry &,bool)702 IMPL_LINK_NOARG(IndexTabPage_Impl, ActivateHdl, weld::Entry&, bool)
703 {
704 aDoubleClickHdl.Call(nullptr);
705 return true;
706 }
707
IMPL_LINK_NOARG(IndexTabPage_Impl,DoubleClickHdl,weld::TreeView &,bool)708 IMPL_LINK_NOARG(IndexTabPage_Impl, DoubleClickHdl, weld::TreeView&, bool)
709 {
710 aDoubleClickHdl.Call(nullptr);
711 return true;
712 }
713
IMPL_LINK_NOARG(IndexTabPage_Impl,IdleHdl,Timer *,void)714 IMPL_LINK_NOARG(IndexTabPage_Impl, IdleHdl, Timer*, void)
715 {
716 InitializeIndex();
717 }
718
starts_with(const OUString & rStr,int nStartRow,bool bCaseSensitive)719 int IndexTabPage_Impl::starts_with(const OUString& rStr, int nStartRow, bool bCaseSensitive)
720 {
721 const vcl::I18nHelper& rI18nHelper = Application::GetSettings().GetUILocaleI18nHelper();
722
723 int nRet = nStartRow;
724 int nCount = m_xIndexList->n_children();
725 while (nRet < nCount)
726 {
727 OUString aStr(m_xIndexList->get_text(nRet));
728 const bool bMatch = !bCaseSensitive ? rI18nHelper.MatchString(rStr, aStr) : aStr.startsWith(rStr);
729 if (bMatch)
730 return nRet;
731 ++nRet;
732 }
733
734 return -1;
735 }
736
IMPL_LINK_NOARG(IndexTabPage_Impl,AutoCompleteHdl,Timer *,void)737 IMPL_LINK_NOARG(IndexTabPage_Impl, AutoCompleteHdl, Timer*, void)
738 {
739 OUString aStartText = m_xIndexEntry->get_text();
740 int nStartPos, nEndPos;
741 m_xIndexEntry->get_selection_bounds(nStartPos, nEndPos);
742 int nMaxSelection = std::max(nStartPos, nEndPos);
743 if (nMaxSelection != aStartText.getLength())
744 return;
745
746 int nActive = m_xIndexList->get_selected_index();
747 int nStart = nActive;
748
749 if (nStart == -1)
750 nStart = 0;
751
752 // Try match case insensitive from current position
753 int nPos = starts_with(aStartText, nStart, false);
754 if (nPos == -1 && nStart != 0)
755 {
756 // Try match case insensitive, but from start
757 nPos = starts_with(aStartText, 0, false);
758 }
759
760 if (nPos == -1)
761 {
762 // Try match case sensitive from current position
763 nPos = starts_with(aStartText, nStart, true);
764 if (nPos == -1 && nStart != 0)
765 {
766 // Try match case sensitive, but from start
767 nPos = starts_with(aStartText, 0, true);
768 }
769 }
770
771 if (nPos != -1)
772 {
773 m_xIndexList->set_cursor(nPos);
774 m_xIndexList->select(nPos);
775 OUString aText = m_xIndexList->get_text(nPos);
776 if (aText != aStartText)
777 m_xIndexEntry->set_text(aText);
778 m_xIndexEntry->select_region(aText.getLength(), aStartText.getLength());
779 }
780 }
781
IMPL_LINK(IndexTabPage_Impl,TimeoutHdl,Timer *,pTimer,void)782 IMPL_LINK( IndexTabPage_Impl, TimeoutHdl, Timer*, pTimer, void)
783 {
784 if(&aKeywordTimer == pTimer && !sKeyword.isEmpty())
785 aKeywordLink.Call(*this);
786 }
787
Activate()788 void IndexTabPage_Impl::Activate()
789 {
790 if ( !bIsActivated )
791 {
792 bIsActivated = true;
793 aFactoryIdle.Start();
794 }
795 }
796
SetDoubleClickHdl(const Link<LinkParamNone *,void> & rLink)797 void IndexTabPage_Impl::SetDoubleClickHdl(const Link<LinkParamNone*, void>& rLink)
798 {
799 aDoubleClickHdl = rLink;
800 }
801
SetFactory(const OUString & rFactory)802 void IndexTabPage_Impl::SetFactory( const OUString& rFactory )
803 {
804 OUString sNewFactory( rFactory );
805 DBG_ASSERT( !sNewFactory.isEmpty(), "empty factory" );
806 bool bValid = m_pIdxWin->IsValidFactory( rFactory );
807
808 if ( sFactory.isEmpty() && !bValid )
809 {
810 sNewFactory = SfxHelp::GetDefaultHelpModule();
811 bValid = true;
812 }
813
814 if ( sNewFactory != sFactory && bValid )
815 {
816 sFactory = sNewFactory;
817 ClearIndex();
818 if ( bIsActivated )
819 aFactoryIdle.Start();
820 }
821 }
822
GetSelectedEntry() const823 OUString IndexTabPage_Impl::GetSelectedEntry() const
824 {
825 OUString aRet;
826 IndexEntry_Impl* pEntry = reinterpret_cast<IndexEntry_Impl*>(m_xIndexList->get_id(m_xIndexList->find_text(m_xIndexEntry->get_text())).toInt64());
827 if (pEntry)
828 aRet = pEntry->m_aURL;
829 return aRet;
830 }
831
SetKeyword(const OUString & rKeyword)832 void IndexTabPage_Impl::SetKeyword( const OUString& rKeyword )
833 {
834 sKeyword = rKeyword;
835
836 if (m_xIndexList->n_children() > 0)
837 aKeywordTimer.Start();
838 else if ( !bIsActivated )
839 aFactoryIdle.Start();
840 }
841
842
HasKeyword() const843 bool IndexTabPage_Impl::HasKeyword() const
844 {
845 bool bRet = false;
846 if ( !sKeyword.isEmpty() )
847 {
848 sal_Int32 nPos = m_xIndexList->find_text( sKeyword );
849 bRet = nPos != -1;
850 }
851
852 return bRet;
853 }
854
855
HasKeywordIgnoreCase()856 bool IndexTabPage_Impl::HasKeywordIgnoreCase()
857 {
858 bool bRet = false;
859 if ( !sKeyword.isEmpty() )
860 {
861 sal_Int32 nEntries = m_xIndexList->n_children();
862 const vcl::I18nHelper& rI18nHelper = Application::GetSettings().GetLocaleI18nHelper();
863 for ( sal_Int32 n = 0; n < nEntries; n++)
864 {
865 const OUString sIndexItem {m_xIndexList->get_text(n)};
866 if (rI18nHelper.MatchString( sIndexItem, sKeyword ))
867 {
868 sKeyword = sIndexItem;
869 bRet = true;
870 }
871 }
872 }
873
874 return bRet;
875 }
876
OpenKeyword()877 void IndexTabPage_Impl::OpenKeyword()
878 {
879 if ( !sKeyword.isEmpty() )
880 {
881 m_xIndexEntry->set_text(sKeyword);
882 aDoubleClickHdl.Call(nullptr);
883 sKeyword.clear();
884 }
885 }
886
IMPL_LINK_NOARG(SearchTabPage_Impl,ActivateHdl,weld::ComboBox &,bool)887 IMPL_LINK_NOARG(SearchTabPage_Impl, ActivateHdl, weld::ComboBox&, bool)
888 {
889 Search();
890 return true;
891 }
892
893 // class SearchTabPage_Impl ----------------------------------------------
894
SearchTabPage_Impl(weld::Widget * pParent,SfxHelpIndexWindow_Impl * pIdxWin)895 SearchTabPage_Impl::SearchTabPage_Impl(weld::Widget* pParent, SfxHelpIndexWindow_Impl* pIdxWin)
896 : HelpTabPage_Impl(pParent, pIdxWin, "HelpSearchPage",
897 "sfx/ui/helpsearchpage.ui")
898 , m_xSearchED(m_xBuilder->weld_combo_box("search"))
899 , m_xSearchBtn(m_xBuilder->weld_button("find"))
900 , m_xFullWordsCB(m_xBuilder->weld_check_button("completewords"))
901 , m_xScopeCB(m_xBuilder->weld_check_button("headings"))
902 , m_xResultsLB(m_xBuilder->weld_tree_view("results"))
903 , m_xOpenBtn(m_xBuilder->weld_button("display"))
904 , xBreakIterator(vcl::unohelper::CreateBreakIterator())
905 {
906 m_xResultsLB->set_size_request(m_xResultsLB->get_approximate_digit_width() * 30,
907 m_xResultsLB->get_height_rows(15));
908
909 m_xSearchBtn->connect_clicked(LINK(this, SearchTabPage_Impl, ClickHdl));
910 m_xSearchED->connect_changed(LINK(this, SearchTabPage_Impl, ModifyHdl));
911 m_xSearchED->connect_entry_activate(LINK(this, SearchTabPage_Impl, ActivateHdl));
912 m_xOpenBtn->connect_clicked(LINK(this, SearchTabPage_Impl, OpenHdl));
913 m_xResultsLB->connect_row_activated(LINK(this, SearchTabPage_Impl, DoubleClickHdl));
914
915 SvtViewOptions aViewOpt( EViewType::TabPage, CONFIGNAME_SEARCHPAGE );
916 if ( aViewOpt.Exists() )
917 {
918 OUString aUserData;
919 Any aUserItem = aViewOpt.GetUserItem( USERITEM_NAME );
920 if ( aUserItem >>= aUserData )
921 {
922 sal_Int32 nIdx {0};
923 bool bChecked = aUserData.getToken(0, ';', nIdx).toInt32() == 1;
924 m_xFullWordsCB->set_active(bChecked);
925 bChecked = aUserData.getToken(0, ';', nIdx).toInt32() == 1;
926 m_xScopeCB->set_active(bChecked);
927
928 while ( nIdx > 0 )
929 {
930 m_xSearchED->append_text( INetURLObject::decode(
931 aUserData.getToken(0, ';', nIdx),
932 INetURLObject::DecodeMechanism::WithCharset ) );
933 }
934 }
935 }
936
937 ModifyHdl(*m_xSearchED);
938 }
939
~SearchTabPage_Impl()940 SearchTabPage_Impl::~SearchTabPage_Impl()
941 {
942 SvtViewOptions aViewOpt( EViewType::TabPage, CONFIGNAME_SEARCHPAGE );
943 OUStringBuffer aUserData =
944 OUString::number(m_xFullWordsCB->get_active() ? 1 : 0) +
945 ";" +
946 OUString::number(m_xScopeCB->get_active() ? 1 : 0);
947 sal_Int32 nCount = std::min(m_xSearchED->get_count(), 10); // save only 10 entries
948
949 for ( sal_Int32 i = 0; i < nCount; ++i )
950 {
951 aUserData.append(";" +
952 INetURLObject::encode(
953 m_xSearchED->get_text(i),
954 INetURLObject::PART_UNO_PARAM_VALUE,
955 INetURLObject::EncodeMechanism::All ));
956 }
957
958 Any aUserItem = makeAny( aUserData.makeStringAndClear() );
959 aViewOpt.SetUserItem( USERITEM_NAME, aUserItem );
960
961 m_xSearchED.reset();
962 m_xSearchBtn.reset();
963 m_xFullWordsCB.reset();
964 m_xScopeCB.reset();
965 m_xResultsLB.reset();
966 m_xOpenBtn.reset();
967 }
968
ClearSearchResults()969 void SearchTabPage_Impl::ClearSearchResults()
970 {
971 m_xResultsLB->clear();
972 }
973
RememberSearchText(const OUString & rSearchText)974 void SearchTabPage_Impl::RememberSearchText( const OUString& rSearchText )
975 {
976 for (sal_Int32 i = 0, nEntryCount = m_xSearchED->get_count(); i < nEntryCount; ++i)
977 {
978 if (rSearchText == m_xSearchED->get_text(i))
979 {
980 m_xSearchED->remove(i);
981 break;
982 }
983 }
984
985 m_xSearchED->insert_text(0, rSearchText);
986 }
987
IMPL_LINK_NOARG(SearchTabPage_Impl,ClickHdl,weld::Button &,void)988 IMPL_LINK_NOARG(SearchTabPage_Impl, ClickHdl, weld::Button&, void)
989 {
990 Search();
991 }
992
Search()993 void SearchTabPage_Impl::Search()
994 {
995 OUString aSearchText = comphelper::string::strip(m_xSearchED->get_active_text(), ' ');
996 if ( aSearchText.isEmpty() )
997 return;
998
999 std::unique_ptr<weld::WaitObject> xWaitCursor(new weld::WaitObject(m_pIdxWin->GetFrameWeld()));
1000 ClearSearchResults();
1001 RememberSearchText( aSearchText );
1002 OUStringBuffer aSearchURL(HELP_URL);
1003 aSearchURL.append(aFactory);
1004 aSearchURL.append(HELP_SEARCH_TAG);
1005 if (!m_xFullWordsCB->get_active())
1006 aSearchText = sfx2::PrepareSearchString( aSearchText, xBreakIterator, true );
1007 aSearchURL.append(aSearchText);
1008 AppendConfigToken(aSearchURL, false);
1009 if (m_xScopeCB->get_active())
1010 aSearchURL.append("&Scope=Heading");
1011 std::vector< OUString > aFactories = SfxContentHelper::GetResultSet(aSearchURL.makeStringAndClear());
1012 for (const OUString & rRow : aFactories)
1013 {
1014 sal_Int32 nIdx = 0;
1015 OUString aTitle = rRow.getToken(0, '\t', nIdx);
1016 OUString sURL(rRow.getToken(1, '\t', nIdx));
1017 m_xResultsLB->append(sURL, aTitle);
1018 }
1019 xWaitCursor.reset();
1020
1021 if ( aFactories.empty() )
1022 {
1023 std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_xContainer.get(),
1024 VclMessageType::Info, VclButtonsType::Ok,
1025 SfxResId(STR_INFO_NOSEARCHRESULTS)));
1026 xBox->run();
1027 }
1028 }
1029
IMPL_LINK_NOARG(SearchTabPage_Impl,OpenHdl,weld::Button &,void)1030 IMPL_LINK_NOARG(SearchTabPage_Impl, OpenHdl, weld::Button&, void)
1031 {
1032 aDoubleClickHdl.Call(nullptr);
1033 }
1034
IMPL_LINK(SearchTabPage_Impl,ModifyHdl,weld::ComboBox &,rComboBox,void)1035 IMPL_LINK(SearchTabPage_Impl, ModifyHdl, weld::ComboBox&, rComboBox, void)
1036 {
1037 OUString aSearchText = comphelper::string::strip(m_xSearchED->get_active_text(), ' ');
1038 m_xSearchBtn->set_sensitive(!aSearchText.isEmpty());
1039
1040 if (rComboBox.changed_by_direct_pick())
1041 Search();
1042 }
1043
IMPL_LINK_NOARG(SearchTabPage_Impl,DoubleClickHdl,weld::TreeView &,bool)1044 IMPL_LINK_NOARG(SearchTabPage_Impl, DoubleClickHdl, weld::TreeView&, bool)
1045 {
1046 aDoubleClickHdl.Call(nullptr);
1047 return true;
1048 }
1049
SetDoubleClickHdl(const Link<LinkParamNone *,void> & rLink)1050 void SearchTabPage_Impl::SetDoubleClickHdl(const Link<LinkParamNone*, void>& rLink)
1051 {
1052 aDoubleClickHdl = rLink;
1053 }
1054
GetSelectedEntry() const1055 OUString SearchTabPage_Impl::GetSelectedEntry() const
1056 {
1057 return m_xResultsLB->get_selected_id();
1058 }
1059
ClearPage()1060 void SearchTabPage_Impl::ClearPage()
1061 {
1062 ClearSearchResults();
1063 m_xSearchED->set_entry_text(OUString());
1064 }
1065
OpenKeyword(const OUString & rKeyword)1066 bool SearchTabPage_Impl::OpenKeyword( const OUString& rKeyword )
1067 {
1068 bool bRet = false;
1069 m_xSearchED->set_entry_text(rKeyword);
1070 Search();
1071 if (m_xResultsLB->n_children() > 0)
1072 {
1073 // found keyword -> open it
1074 m_xResultsLB->select(0);
1075 OpenHdl(*m_xOpenBtn);
1076 bRet = true;
1077 }
1078 return bRet;
1079 }
1080
1081 // class BookmarksTabPage_Impl -------------------------------------------
GetBookmarkEntry_Impl(const Sequence<PropertyValue> & aBookmarkEntry,OUString & rTitle,OUString & rURL)1082 static void GetBookmarkEntry_Impl
1083 (
1084 const Sequence< PropertyValue >& aBookmarkEntry,
1085 OUString& rTitle,
1086 OUString& rURL
1087 )
1088 {
1089 for ( const PropertyValue& aValue : aBookmarkEntry )
1090 {
1091 if ( aValue.Name == HISTORY_PROPERTYNAME_URL )
1092 aValue.Value >>= rURL;
1093 else if ( aValue.Name == HISTORY_PROPERTYNAME_TITLE )
1094 aValue.Value >>= rTitle;
1095 }
1096 }
1097
DoAction(std::string_view rAction)1098 void BookmarksTabPage_Impl::DoAction(std::string_view rAction)
1099 {
1100 if (rAction == "display")
1101 aDoubleClickHdl.Call(nullptr);
1102 else if (rAction == "rename")
1103 {
1104 sal_Int32 nPos = m_xBookmarksBox->get_selected_index();
1105 if (nPos != -1)
1106 {
1107 SfxAddHelpBookmarkDialog_Impl aDlg(m_xBookmarksBox.get(), true);
1108 aDlg.SetTitle(m_xBookmarksBox->get_text(nPos));
1109 if (aDlg.run() == RET_OK)
1110 {
1111 OUString sURL = m_xBookmarksBox->get_id(nPos);
1112 m_xBookmarksBox->remove(nPos);
1113 m_xBookmarksBox->append(sURL, aDlg.GetTitle(), SvFileInformationManager::GetImageId(INetURLObject(IMAGE_URL+INetURLObject(sURL).GetHost())));
1114 m_xBookmarksBox->select(m_xBookmarksBox->n_children() - 1);
1115 }
1116 }
1117 }
1118 else if (rAction == "delete")
1119 {
1120 sal_Int32 nPos = m_xBookmarksBox->get_selected_index();
1121 if (nPos != -1)
1122 {
1123 m_xBookmarksBox->remove(nPos);
1124 const sal_Int32 nCount = m_xBookmarksBox->n_children();
1125 if (nCount)
1126 {
1127 if (nPos >= nCount)
1128 nPos = nCount - 1;
1129 m_xBookmarksBox->select(nPos);
1130 }
1131 }
1132 }
1133 }
1134
IMPL_LINK(BookmarksTabPage_Impl,CommandHdl,const CommandEvent &,rCEvt,bool)1135 IMPL_LINK(BookmarksTabPage_Impl, CommandHdl, const CommandEvent&, rCEvt, bool)
1136 {
1137 if (rCEvt.GetCommand() != CommandEventId::ContextMenu)
1138 return false;
1139
1140 std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(m_xBookmarksBox.get(), "sfx/ui/bookmarkmenu.ui"));
1141 std::unique_ptr<weld::Menu> xMenu = xBuilder->weld_menu("menu");
1142
1143 OString sIdent = xMenu->popup_at_rect(m_xBookmarksBox.get(), ::tools::Rectangle(rCEvt.GetMousePosPixel(), Size(1,1)));
1144 if (!sIdent.isEmpty())
1145 DoAction(sIdent);
1146 return true;
1147 }
1148
IMPL_LINK(BookmarksTabPage_Impl,KeyInputHdl,const KeyEvent &,rKEvt,bool)1149 IMPL_LINK(BookmarksTabPage_Impl, KeyInputHdl, const KeyEvent&, rKEvt, bool)
1150 {
1151 bool bHandled = false;
1152 sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode();
1153 if (KEY_DELETE == nCode && m_xBookmarksBox->n_children() > 0)
1154 {
1155 DoAction("delete");
1156 bHandled = true;
1157 }
1158 return bHandled;
1159 }
1160
1161 // class BookmarksTabPage_Impl -------------------------------------------
BookmarksTabPage_Impl(weld::Widget * pParent,SfxHelpIndexWindow_Impl * _pIdxWin)1162 BookmarksTabPage_Impl::BookmarksTabPage_Impl(weld::Widget* pParent, SfxHelpIndexWindow_Impl* _pIdxWin)
1163 : HelpTabPage_Impl(pParent, _pIdxWin, "HelpBookmarkPage",
1164 "sfx/ui/helpbookmarkpage.ui")
1165 , m_xBookmarksBox(m_xBuilder->weld_tree_view("bookmarks"))
1166 , m_xBookmarksPB(m_xBuilder->weld_button("display"))
1167 {
1168 m_xBookmarksBox->set_size_request(m_xBookmarksBox->get_approximate_digit_width() * 30,
1169 m_xBookmarksBox->get_height_rows(20));
1170
1171 m_xBookmarksPB->connect_clicked( LINK(this, BookmarksTabPage_Impl, OpenHdl));
1172 m_xBookmarksBox->connect_row_activated(LINK(this, BookmarksTabPage_Impl, DoubleClickHdl));
1173 m_xBookmarksBox->connect_popup_menu(LINK(this, BookmarksTabPage_Impl, CommandHdl));
1174 m_xBookmarksBox->connect_key_press(LINK(this, BookmarksTabPage_Impl, KeyInputHdl));
1175
1176 // load bookmarks from configuration
1177 const Sequence< Sequence< PropertyValue > > aBookmarkSeq = SvtHistoryOptions().GetList( EHistoryType::HelpBookmarks );
1178
1179 OUString aTitle;
1180 OUString aURL;
1181
1182 for ( const auto& rBookmark : aBookmarkSeq )
1183 {
1184 GetBookmarkEntry_Impl( rBookmark, aTitle, aURL );
1185 AddBookmarks( aTitle, aURL );
1186 }
1187 }
1188
~BookmarksTabPage_Impl()1189 BookmarksTabPage_Impl::~BookmarksTabPage_Impl()
1190 {
1191 // save bookmarks to configuration
1192 SvtHistoryOptions aHistOpt;
1193 aHistOpt.Clear( EHistoryType::HelpBookmarks );
1194 const sal_Int32 nCount = m_xBookmarksBox->n_children();
1195 for (sal_Int32 i = 0; i < nCount; ++i)
1196 aHistOpt.AppendItem(EHistoryType::HelpBookmarks, m_xBookmarksBox->get_id(i), "", m_xBookmarksBox->get_text(i), std::nullopt);
1197
1198 m_xBookmarksBox.reset();
1199 m_xBookmarksPB.reset();
1200 }
1201
IMPL_LINK_NOARG(BookmarksTabPage_Impl,OpenHdl,weld::Button &,void)1202 IMPL_LINK_NOARG(BookmarksTabPage_Impl, OpenHdl, weld::Button&, void)
1203 {
1204 aDoubleClickHdl.Call(nullptr);
1205 }
1206
IMPL_LINK_NOARG(BookmarksTabPage_Impl,DoubleClickHdl,weld::TreeView &,bool)1207 IMPL_LINK_NOARG(BookmarksTabPage_Impl, DoubleClickHdl, weld::TreeView&, bool)
1208 {
1209 aDoubleClickHdl.Call(nullptr);
1210 return true;
1211 }
1212
SetDoubleClickHdl(const Link<LinkParamNone *,void> & rLink)1213 void BookmarksTabPage_Impl::SetDoubleClickHdl(const Link<LinkParamNone*, void>& rLink)
1214 {
1215 aDoubleClickHdl = rLink;
1216 }
1217
GetSelectedEntry() const1218 OUString BookmarksTabPage_Impl::GetSelectedEntry() const
1219 {
1220 return m_xBookmarksBox->get_selected_id();
1221 }
1222
AddBookmarks(const OUString & rTitle,const OUString & rURL)1223 void BookmarksTabPage_Impl::AddBookmarks(const OUString& rTitle, const OUString& rURL)
1224 {
1225 const OUString aImageURL {IMAGE_URL + INetURLObject(rURL).GetHost()};
1226 m_xBookmarksBox->append(rURL, rTitle, SvFileInformationManager::GetImageId(INetURLObject(aImageURL)));
1227 }
1228
buildHelpURL(std::u16string_view sFactory,std::u16string_view sContent,std::u16string_view sAnchor)1229 OUString SfxHelpWindow_Impl::buildHelpURL(std::u16string_view sFactory ,
1230 std::u16string_view sContent ,
1231 std::u16string_view sAnchor)
1232 {
1233 OUStringBuffer sHelpURL(256);
1234 sHelpURL.append(HELP_URL);
1235 sHelpURL.append(sFactory);
1236 sHelpURL.append(sContent);
1237 AppendConfigToken(sHelpURL, true/*bUseQuestionMark*/);
1238 if (!sAnchor.empty())
1239 sHelpURL.append(sAnchor);
1240 return sHelpURL.makeStringAndClear();
1241 }
1242
loadHelpContent(const OUString & sHelpURL,bool bAddToHistory)1243 void SfxHelpWindow_Impl::loadHelpContent(const OUString& sHelpURL, bool bAddToHistory)
1244 {
1245 Reference< XComponentLoader > xLoader(getTextFrame(), UNO_QUERY);
1246 if (!xLoader.is())
1247 return;
1248
1249 // If a print job runs do not open a new page
1250 Reference< XFrame2 > xTextFrame = pTextWin->getFrame();
1251 Reference< XController > xTextController ;
1252 if (xTextFrame.is())
1253 xTextController = xTextFrame->getController ();
1254 if ( xTextController.is() && !xTextController->suspend( true ) )
1255 {
1256 xTextController->suspend( false );
1257 return;
1258 }
1259
1260 // save url to history
1261 if (bAddToHistory)
1262 pHelpInterceptor->addURL(sHelpURL);
1263
1264 if ( !IsWait() )
1265 EnterWait();
1266 bool bSuccess = false;
1267 // TODO implement locale fallback ... see below while(true)
1268 {
1269 try
1270 {
1271 Reference< XComponent > xContent = xLoader->loadComponentFromURL(sHelpURL, "_self", 0, Sequence< PropertyValue >());
1272 if (xContent.is())
1273 {
1274 bSuccess = true;
1275 }
1276 }
1277 catch(const RuntimeException&)
1278 { throw; }
1279 catch(const Exception&)
1280 { /*break;*/ }
1281
1282 /* TODO try next locale ...
1283 no further locale available? => break loop and show error page
1284 */
1285 }
1286 openDone(sHelpURL, bSuccess);
1287 if ( IsWait() )
1288 LeaveWait();
1289 }
1290
IMPL_LINK(SfxHelpIndexWindow_Impl,ActivatePageHdl,const OString &,rPage,void)1291 IMPL_LINK(SfxHelpIndexWindow_Impl, ActivatePageHdl, const OString&, rPage, void)
1292 {
1293 GetPage(rPage)->Activate();
1294 }
1295
SfxHelpIndexWindow_Impl(SfxHelpWindow_Impl * _pParent,weld::Container * pContainer)1296 SfxHelpIndexWindow_Impl::SfxHelpIndexWindow_Impl(SfxHelpWindow_Impl* _pParent, weld::Container* pContainer)
1297 : m_xBuilder(Application::CreateBuilder(pContainer, "sfx/ui/helpcontrol.ui"))
1298 , m_xContainer(m_xBuilder->weld_container("HelpControl"))
1299 , m_xActiveLB(m_xBuilder->weld_combo_box("active"))
1300 , m_xTabCtrl(m_xBuilder->weld_notebook("tabcontrol"))
1301 , aIdle("sfx2 appl SfxHelpIndexWindow_Impl")
1302 , aIndexKeywordLink(LINK(this, SfxHelpIndexWindow_Impl, KeywordHdl))
1303 , pParentWin(_pParent)
1304 , bIsInitDone(false)
1305 {
1306 // create the pages
1307 GetContentPage();
1308 GetIndexPage();
1309 GetSearchPage();
1310 GetBookmarksPage();
1311
1312 OString sPageId("index");
1313 SvtViewOptions aViewOpt( EViewType::TabDialog, CONFIGNAME_INDEXWIN );
1314 if ( aViewOpt.Exists() )
1315 sPageId = aViewOpt.GetPageID();
1316 m_xTabCtrl->set_current_page(sPageId);
1317 ActivatePageHdl(sPageId);
1318 m_xActiveLB->connect_changed(LINK(this, SfxHelpIndexWindow_Impl, SelectHdl));
1319
1320 m_xTabCtrl->connect_enter_page(LINK(this, SfxHelpIndexWindow_Impl, ActivatePageHdl));
1321
1322 aIdle.SetInvokeHandler( LINK( this, SfxHelpIndexWindow_Impl, InitHdl ) );
1323 aIdle.Start();
1324
1325 m_xContainer->show();
1326 }
1327
~SfxHelpIndexWindow_Impl()1328 SfxHelpIndexWindow_Impl::~SfxHelpIndexWindow_Impl()
1329 {
1330 SvtViewOptions aViewOpt(EViewType::TabDialog, CONFIGNAME_INDEXWIN);
1331 aViewOpt.SetPageID(m_xTabCtrl->get_current_page_ident());
1332
1333 xCPage.reset();
1334 xIPage.reset();
1335 xSPage.reset();
1336 xBPage.reset();
1337 }
1338
Initialize()1339 void SfxHelpIndexWindow_Impl::Initialize()
1340 {
1341 OUStringBuffer aHelpURL(HELP_URL);
1342 AppendConfigToken(aHelpURL, true);
1343 std::vector<OUString> aFactories = SfxContentHelper::GetResultSet(aHelpURL.makeStringAndClear());
1344 for (const OUString & rRow : aFactories)
1345 {
1346 sal_Int32 nIdx = 0;
1347 OUString aTitle = rRow.getToken( 0, '\t', nIdx ); // token 0
1348 OUString aURL = rRow.getToken( 1, '\t', nIdx ); // token 2
1349 OUString aFactory(INetURLObject(aURL).GetHost());
1350 m_xActiveLB->append(aFactory, aTitle);
1351 }
1352
1353 if (m_xActiveLB->get_active() == -1)
1354 SetActiveFactory();
1355 }
1356
SetActiveFactory()1357 void SfxHelpIndexWindow_Impl::SetActiveFactory()
1358 {
1359 DBG_ASSERT( xIPage, "index page not initialized" );
1360 if (!bIsInitDone && !m_xActiveLB->get_count())
1361 {
1362 aIdle.Stop();
1363 InitHdl( nullptr );
1364 }
1365
1366 for (sal_Int32 i = 0, nEntryCount = m_xActiveLB->get_count(); i < nEntryCount; ++i)
1367 {
1368 OUString aFactory = m_xActiveLB->get_id(i);
1369 aFactory = aFactory.toAsciiLowerCase();
1370 if (aFactory == xIPage->GetFactory())
1371 {
1372 if (m_xActiveLB->get_active() != i)
1373 {
1374 m_xActiveLB->set_active(i);
1375 aSelectFactoryLink.Call(nullptr);
1376 }
1377 break;
1378 }
1379 }
1380 }
1381
GetPage(std::string_view rName)1382 HelpTabPage_Impl* SfxHelpIndexWindow_Impl::GetPage(std::string_view rName)
1383 {
1384 HelpTabPage_Impl* pPage = nullptr;
1385
1386 if (rName == "contents")
1387 pPage = GetContentPage();
1388 else if (rName == "index")
1389 pPage = GetIndexPage();
1390 else if (rName == "find")
1391 pPage = GetSearchPage();
1392 else if (rName == "bookmarks")
1393 pPage = GetBookmarksPage();
1394
1395 assert(pPage && "SfxHelpIndexWindow_Impl::GetCurrentPage(): no current page");
1396
1397 return pPage;
1398 }
1399
IMPL_LINK_NOARG(SfxHelpIndexWindow_Impl,SelectHdl,weld::ComboBox &,void)1400 IMPL_LINK_NOARG(SfxHelpIndexWindow_Impl, SelectHdl, weld::ComboBox&, void)
1401 {
1402 aIdle.Start();
1403 }
1404
IMPL_LINK_NOARG(SfxHelpIndexWindow_Impl,InitHdl,Timer *,void)1405 IMPL_LINK_NOARG(SfxHelpIndexWindow_Impl, InitHdl, Timer *, void)
1406 {
1407 bIsInitDone = true;
1408 Initialize();
1409
1410 // now use the timer for selection
1411 aIdle.SetInvokeHandler( LINK( this, SfxHelpIndexWindow_Impl, SelectFactoryHdl ) );
1412 aIdle.SetPriority( TaskPriority::LOWEST );
1413 }
1414
IMPL_LINK_NOARG(SfxHelpIndexWindow_Impl,SelectFactoryHdl,Timer *,void)1415 IMPL_LINK_NOARG(SfxHelpIndexWindow_Impl, SelectFactoryHdl, Timer *, void)
1416 {
1417 OUString aFactory = m_xActiveLB->get_active_id();
1418 if (!aFactory.isEmpty())
1419 {
1420 SetFactory(aFactory.toAsciiLowerCase(), false);
1421 aSelectFactoryLink.Call(this);
1422 }
1423 }
1424
IMPL_LINK_NOARG(SfxHelpIndexWindow_Impl,KeywordHdl,IndexTabPage_Impl &,void)1425 IMPL_LINK_NOARG(SfxHelpIndexWindow_Impl, KeywordHdl, IndexTabPage_Impl&, void)
1426 {
1427 // keyword found on index?
1428 bool bIndex = xIPage->HasKeyword();
1429
1430 if( !bIndex)
1431 bIndex = xIPage->HasKeywordIgnoreCase();
1432 // then set index or search page as current.
1433 OString sPageId = bIndex ? "index" : "find";
1434 if (sPageId != m_xTabCtrl->get_current_page_ident())
1435 m_xTabCtrl->set_current_page(sPageId);
1436
1437 // at last we open the keyword
1438 if ( bIndex )
1439 xIPage->OpenKeyword();
1440 else if ( !xSPage->OpenKeyword( sKeyword ) )
1441 pParentWin->ShowStartPage();
1442 }
1443
IMPL_LINK_NOARG(SfxHelpIndexWindow_Impl,IndexTabPageDoubleClickHdl,LinkParamNone *,void)1444 IMPL_LINK_NOARG(SfxHelpIndexWindow_Impl, IndexTabPageDoubleClickHdl, LinkParamNone*, void)
1445 {
1446 aPageDoubleClickLink.Call(nullptr);
1447 }
1448
SetDoubleClickHdl(const Link<LinkParamNone *,void> & rLink)1449 void SfxHelpIndexWindow_Impl::SetDoubleClickHdl(const Link<LinkParamNone*, void>& rLink)
1450 {
1451 aPageDoubleClickLink = rLink;
1452 }
1453
IMPL_LINK_NOARG(SfxHelpIndexWindow_Impl,ContentTabPageDoubleClickHdl,LinkParamNone *,void)1454 IMPL_LINK_NOARG(SfxHelpIndexWindow_Impl, ContentTabPageDoubleClickHdl, LinkParamNone*, void)
1455 {
1456 aPageDoubleClickLink.Call(nullptr);
1457 }
1458
IMPL_LINK_NOARG(SfxHelpIndexWindow_Impl,TabPageDoubleClickHdl,LinkParamNone *,void)1459 IMPL_LINK_NOARG(SfxHelpIndexWindow_Impl, TabPageDoubleClickHdl, LinkParamNone*, void)
1460 {
1461 aPageDoubleClickLink.Call(nullptr);
1462 }
1463
SetFactory(const OUString & rFactory,bool bActive)1464 void SfxHelpIndexWindow_Impl::SetFactory( const OUString& rFactory, bool bActive )
1465 {
1466 if ( !rFactory.isEmpty() )
1467 {
1468 GetIndexPage()->SetFactory( rFactory );
1469 // the index page made a check if rFactory is valid,
1470 // so the index page always returns a valid factory
1471 GetSearchPage()->SetFactory( GetIndexPage()->GetFactory() );
1472 if ( bActive )
1473 SetActiveFactory();
1474 }
1475 }
1476
GetSelectedEntry() const1477 OUString SfxHelpIndexWindow_Impl::GetSelectedEntry() const
1478 {
1479 OUString sRet;
1480
1481 OString sName(m_xTabCtrl->get_current_page_ident());
1482
1483 if (sName == "contents")
1484 {
1485 sRet = xCPage->GetSelectedEntry();
1486 }
1487 else if (sName == "index")
1488 {
1489 sRet = xIPage->GetSelectedEntry();
1490 }
1491 else if (sName == "find")
1492 {
1493 sRet = xSPage->GetSelectedEntry();
1494 }
1495 else if (sName == "bookmarks")
1496 {
1497 sRet = xBPage->GetSelectedEntry();
1498 }
1499
1500 return sRet;
1501 }
1502
AddBookmarks(const OUString & rTitle,const OUString & rURL)1503 void SfxHelpIndexWindow_Impl::AddBookmarks( const OUString& rTitle, const OUString& rURL )
1504 {
1505 GetBookmarksPage()->AddBookmarks( rTitle, rURL );
1506 }
1507
IsValidFactory(std::u16string_view _rFactory)1508 bool SfxHelpIndexWindow_Impl::IsValidFactory( std::u16string_view _rFactory )
1509 {
1510 bool bValid = false;
1511 for (sal_Int32 i = 0, nEntryCount = m_xActiveLB->get_count(); i < nEntryCount; ++i)
1512 {
1513 OUString aFactory = m_xActiveLB->get_id(i);
1514 if (aFactory == _rFactory)
1515 {
1516 bValid = true;
1517 break;
1518 }
1519 }
1520 return bValid;
1521 }
1522
ClearSearchPage()1523 void SfxHelpIndexWindow_Impl::ClearSearchPage()
1524 {
1525 if ( xSPage )
1526 xSPage->ClearPage();
1527 }
1528
GrabFocusBack()1529 void SfxHelpIndexWindow_Impl::GrabFocusBack()
1530 {
1531 OString sName(m_xTabCtrl->get_current_page_ident());
1532
1533 if (sName == "contents" && xCPage)
1534 xCPage->SetFocusOnBox();
1535 else if (sName == "index" && xIPage)
1536 xIPage->SetFocusOnBox();
1537 else if (sName == "find" && xSPage)
1538 xSPage->SetFocusOnBox();
1539 else if (sName == "bookmarks" && xBPage)
1540 xBPage->SetFocusOnBox();
1541 }
1542
HasFocusOnEdit() const1543 bool SfxHelpIndexWindow_Impl::HasFocusOnEdit() const
1544 {
1545 bool bRet = false;
1546 OString sName(m_xTabCtrl->get_current_page_ident());
1547 if (sName == "index" && xIPage)
1548 bRet = xIPage->HasFocusOnEdit();
1549 else if (sName == "find" && xSPage)
1550 bRet = xSPage->HasFocusOnEdit();
1551 return bRet;
1552 }
1553
GetSearchText() const1554 OUString SfxHelpIndexWindow_Impl::GetSearchText() const
1555 {
1556 OUString sRet;
1557 OString sName(m_xTabCtrl->get_current_page_ident());
1558 if (sName == "find" && xSPage)
1559 sRet = xSPage->GetSearchText();
1560 return sRet;
1561 }
1562
IsFullWordSearch() const1563 bool SfxHelpIndexWindow_Impl::IsFullWordSearch() const
1564 {
1565 bool bRet = false;
1566 OString sName(m_xTabCtrl->get_current_page_ident());
1567 if (sName == "find" && xSPage)
1568 bRet = xSPage->IsFullWordSearch();
1569 return bRet;
1570 }
1571
OpenKeyword(const OUString & rKeyword)1572 void SfxHelpIndexWindow_Impl::OpenKeyword( const OUString& rKeyword )
1573 {
1574 sKeyword = rKeyword;
1575 DBG_ASSERT( xIPage, "invalid index page" );
1576 xIPage->SetKeyword( sKeyword );
1577 }
1578
SelectExecutableEntry()1579 void SfxHelpIndexWindow_Impl::SelectExecutableEntry()
1580 {
1581 OString sName(m_xTabCtrl->get_current_page_ident());
1582 if (sName == "index" && xIPage )
1583 xIPage->SelectExecutableEntry();
1584 }
1585
GetFrameWeld() const1586 weld::Window* SfxHelpIndexWindow_Impl::GetFrameWeld() const
1587 {
1588 return pParentWin->GetFrameWeld();
1589 }
1590
1591 // class TextWin_Impl ----------------------------------------------------
TextWin_Impl(vcl::Window * p)1592 TextWin_Impl::TextWin_Impl( vcl::Window* p ) : DockingWindow( p, 0 )
1593 {
1594 }
1595
EventNotify(NotifyEvent & rNEvt)1596 bool TextWin_Impl::EventNotify( NotifyEvent& rNEvt )
1597 {
1598 if( ( rNEvt.GetType() == MouseNotifyEvent::KEYINPUT ) && rNEvt.GetKeyEvent()->GetKeyCode().GetCode() == KEY_TAB )
1599 return GetParent()->EventNotify( rNEvt );
1600 else
1601 return DockingWindow::EventNotify( rNEvt );
1602 }
1603
1604
1605 // remove docking area acceptor from layoutmanager, so it will not layout anything further .-)
lcl_disableLayoutOfFrame(const Reference<XFrame2> & xFrame)1606 static void lcl_disableLayoutOfFrame(const Reference< XFrame2 >& xFrame)
1607 {
1608 xFrame->setLayoutManager( Reference< XLayoutManager >() );
1609 }
1610
1611 // class SfxHelpTextWindow_Impl ------------------------------------------
1612
SfxHelpTextWindow_Impl(SfxHelpWindow_Impl * pHelpWin,weld::Builder & rBuilder,vcl::Window * pParent)1613 SfxHelpTextWindow_Impl::SfxHelpTextWindow_Impl(SfxHelpWindow_Impl* pHelpWin, weld::Builder& rBuilder, vcl::Window* pParent) :
1614
1615 Window( pParent, WB_CLIPCHILDREN | WB_TABSTOP | WB_DIALOGCONTROL ),
1616
1617 xToolBox ( rBuilder.weld_toolbar("toolbar") ),
1618 xOnStartupCB ( rBuilder.weld_check_button("checkbutton") ),
1619 xMenu ( rBuilder.weld_menu("menu") ),
1620 aSelectIdle ( "sfx2 appl SfxHelpTextWindow_Impl Select" ),
1621 aIndexOnImage ( BMP_HELP_TOOLBOX_INDEX_ON ),
1622 aIndexOffImage ( BMP_HELP_TOOLBOX_INDEX_OFF ),
1623 aIndexOnText ( SfxResId( STR_HELP_BUTTON_INDEX_ON ) ),
1624 aIndexOffText ( SfxResId( STR_HELP_BUTTON_INDEX_OFF ) ),
1625 aOnStartupText ( SfxResId( RID_HELP_ONSTARTUP_TEXT ) ),
1626 xHelpWin ( pHelpWin ),
1627 pTextWin ( VclPtr<TextWin_Impl>::Create( this ) ),
1628 bIsDebug ( false ),
1629 bIsIndexOn ( false ),
1630 bIsInClose ( false ),
1631 bIsFullWordSearch ( false )
1632 {
1633 xFrame = Frame::create( ::comphelper::getProcessComponentContext() );
1634 xFrame->initialize( VCLUnoHelper::GetInterface ( pTextWin ) );
1635 xFrame->setName( "OFFICE_HELP" );
1636 lcl_disableLayoutOfFrame(xFrame);
1637
1638 xToolBox->set_help_id(HID_HELP_TOOLBOX);
1639
1640 xToolBox->set_item_tooltip_text("index", aIndexOffText );
1641 xToolBox->set_item_help_id("index", HID_HELP_TOOLBOXITEM_INDEX);
1642 xToolBox->set_item_help_id("backward", HID_HELP_TOOLBOXITEM_BACKWARD);
1643 xToolBox->set_item_help_id("forward", HID_HELP_TOOLBOXITEM_FORWARD);
1644 xToolBox->set_item_help_id("start", HID_HELP_TOOLBOXITEM_START);
1645 xToolBox->set_item_help_id("print", HID_HELP_TOOLBOXITEM_PRINT);
1646 xToolBox->set_item_help_id("bookmarks", HID_HELP_TOOLBOXITEM_BOOKMARKS );
1647 xToolBox->set_item_help_id("searchdialog", HID_HELP_TOOLBOXITEM_SEARCHDIALOG);
1648
1649 InitToolBoxImages();
1650 InitOnStartupBox();
1651 xOnStartupCB->connect_toggled(LINK(this, SfxHelpTextWindow_Impl, CheckHdl));
1652
1653 aSelectIdle.SetInvokeHandler( LINK( this, SfxHelpTextWindow_Impl, SelectHdl ) );
1654 aSelectIdle.SetPriority( TaskPriority::LOWEST );
1655
1656 char* pEnv = getenv( "help_debug" );
1657 if ( pEnv )
1658 bIsDebug = true;
1659
1660 SvtMiscOptions().AddListenerLink( LINK( this, SfxHelpTextWindow_Impl, NotifyHdl ) );
1661 }
1662
~SfxHelpTextWindow_Impl()1663 SfxHelpTextWindow_Impl::~SfxHelpTextWindow_Impl()
1664 {
1665 disposeOnce();
1666 }
1667
dispose()1668 void SfxHelpTextWindow_Impl::dispose()
1669 {
1670 bIsInClose = true;
1671 SvtMiscOptions().RemoveListenerLink( LINK( this, SfxHelpTextWindow_Impl, NotifyHdl ) );
1672 m_xSrchDlg.reset();
1673 xToolBox.reset();
1674 xOnStartupCB.reset();
1675 xHelpWin.clear();
1676 pTextWin.disposeAndClear();
1677 vcl::Window::dispose();
1678 }
1679
HasSelection() const1680 bool SfxHelpTextWindow_Impl::HasSelection() const
1681 {
1682 // is there any selection in the text and not only a cursor?
1683 bool bRet = false;
1684 Reference < XTextRange > xRange = getCursor();
1685 if ( xRange.is() )
1686 {
1687 Reference < XText > xText = xRange->getText();
1688 Reference < XTextCursor > xCursor = xText->createTextCursorByRange( xRange );
1689 bRet = !xCursor->isCollapsed();
1690 }
1691
1692 return bRet;
1693 }
1694
InitToolBoxImages()1695 void SfxHelpTextWindow_Impl::InitToolBoxImages()
1696 {
1697 xToolBox->set_item_icon_name("index", bIsIndexOn ? aIndexOffImage : aIndexOnImage);
1698 }
1699
InitOnStartupBox()1700 void SfxHelpTextWindow_Impl::InitOnStartupBox()
1701 {
1702 sCurrentFactory = SfxHelp::GetCurrentModuleIdentifier();
1703
1704 Reference< XComponentContext > xContext = ::comphelper::getProcessComponentContext();
1705 const OUString sPath { PATH_OFFICE_FACTORIES + sCurrentFactory };
1706
1707 // Attention: This check boy knows two states:
1708 // 1) Reading of the config key fails with an exception or by getting an empty Any (!) => check box must be hidden
1709 // 2) We read sal_True/sal_False => check box must be shown and enabled/disabled
1710
1711 bool bHideBox = true;
1712 bool bHelpAtStartup = false;
1713 try
1714 {
1715 xConfiguration = ConfigurationHelper::openConfig(
1716 xContext, PACKAGE_SETUP, EConfigurationModes::Standard );
1717 if ( xConfiguration.is() )
1718 {
1719 Any aAny = ConfigurationHelper::readRelativeKey( xConfiguration, sPath, KEY_HELP_ON_OPEN );
1720 if (aAny >>= bHelpAtStartup)
1721 bHideBox = false;
1722 }
1723 }
1724 catch( Exception& )
1725 {
1726 bHideBox = true;
1727 }
1728
1729 if ( bHideBox )
1730 xOnStartupCB->hide();
1731 else
1732 {
1733 // detect module name
1734 OUString sModuleName;
1735
1736 if ( xConfiguration.is() )
1737 {
1738 OUString sTemp;
1739 try
1740 {
1741 Any aAny = ConfigurationHelper::readRelativeKey( xConfiguration, sPath, KEY_UI_NAME );
1742 aAny >>= sTemp;
1743 }
1744 catch( Exception const & )
1745 {
1746 TOOLS_WARN_EXCEPTION( "sfx.appl", "SfxHelpTextWindow_Impl::InitOnStartupBox()" );
1747 }
1748 sModuleName = sTemp;
1749 }
1750
1751 if ( !sModuleName.isEmpty() )
1752 {
1753 // set module name in checkbox text
1754 xOnStartupCB->set_label(aOnStartupText.replaceFirst("%MODULENAME", sModuleName));
1755 // and show it
1756 xOnStartupCB->show();
1757 // set check state
1758 xOnStartupCB->set_active(bHelpAtStartup);
1759 xOnStartupCB->save_state();
1760 }
1761 }
1762 }
1763
GetBreakIterator()1764 Reference< XBreakIterator > const & SfxHelpTextWindow_Impl::GetBreakIterator()
1765 {
1766 if ( !xBreakIterator.is() )
1767 xBreakIterator = vcl::unohelper::CreateBreakIterator();
1768 DBG_ASSERT( xBreakIterator.is(), "Could not create BreakIterator" );
1769 return xBreakIterator;
1770 }
1771
getCursor() const1772 Reference< XTextRange > SfxHelpTextWindow_Impl::getCursor() const
1773 {
1774 // return the current cursor
1775 Reference< XTextRange > xCursor;
1776
1777 try
1778 {
1779 Reference < XSelectionSupplier > xSelSup( xFrame->getController(), UNO_QUERY );
1780 if ( xSelSup.is() )
1781 {
1782 Any aAny = xSelSup->getSelection();
1783 Reference < XIndexAccess > xSelection;
1784 if ( aAny >>= xSelection )
1785 {
1786 if ( xSelection->getCount() == 1 )
1787 {
1788 aAny = xSelection->getByIndex(0);
1789 aAny >>= xCursor;
1790 }
1791 }
1792 }
1793 }
1794 catch( Exception& )
1795 {
1796 TOOLS_WARN_EXCEPTION( "sfx.appl", "SfxHelpTextWindow_Impl::getCursor(): unexpected exception" );
1797 }
1798
1799 return xCursor;
1800 }
1801
1802
isHandledKey(const vcl::KeyCode & _rKeyCode)1803 bool SfxHelpTextWindow_Impl::isHandledKey( const vcl::KeyCode& _rKeyCode )
1804 {
1805 bool bRet = false;
1806 sal_uInt16 nCode = _rKeyCode.GetCode();
1807
1808 // the keys <CTRL><A> (select all), <CTRL><C> (copy),
1809 // <CTRL><F> (find), <CTRL><P> (print) and <CTRL><W> (close window)
1810 // were handled in help
1811 if ( _rKeyCode.IsMod1() &&
1812 ( KEY_A == nCode || KEY_C == nCode || KEY_F == nCode || KEY_P == nCode || KEY_W == nCode ) )
1813 {
1814 if ( KEY_F == nCode )
1815 DoSearch();
1816 else
1817 bRet = true;
1818 }
1819
1820 return bRet;
1821 }
1822
1823
IMPL_LINK_NOARG(SfxHelpTextWindow_Impl,SelectHdl,Timer *,void)1824 IMPL_LINK_NOARG(SfxHelpTextWindow_Impl, SelectHdl, Timer *, void)
1825 {
1826 try
1827 {
1828 // select the words, which are equal to the search text of the search page
1829 Reference < XController > xController = xFrame->getController();
1830 if ( xController.is() )
1831 {
1832 // get document
1833 Reference < XSearchable > xSearchable( xController->getModel(), UNO_QUERY );
1834 if ( xSearchable.is() )
1835 {
1836 // create descriptor, set string and find all words
1837 Reference < XSearchDescriptor > xSrchDesc = xSearchable->createSearchDescriptor();
1838 xSrchDesc->setPropertyValue( "SearchRegularExpression", makeAny( true ) );
1839 if ( bIsFullWordSearch )
1840 xSrchDesc->setPropertyValue( "SearchWords", makeAny( true ) );
1841
1842 xSrchDesc->setSearchString( sfx2::PrepareSearchString( aSearchText, GetBreakIterator(), false ) );
1843 Reference< XIndexAccess > xSelection = xSearchable->findAll( xSrchDesc );
1844
1845 // then select all found words
1846 Reference < XSelectionSupplier > xSelectionSup( xController, UNO_QUERY );
1847 if ( xSelectionSup.is() )
1848 {
1849 xSelectionSup->select( Any(xSelection) );
1850 }
1851 }
1852 }
1853 }
1854 catch( Exception& )
1855 {
1856 TOOLS_WARN_EXCEPTION( "sfx.appl", "SfxHelpTextWindow_Impl::SelectHdl(): unexpected exception" );
1857 }
1858 }
1859
1860
IMPL_LINK_NOARG(SfxHelpTextWindow_Impl,NotifyHdl,LinkParamNone *,void)1861 IMPL_LINK_NOARG( SfxHelpTextWindow_Impl, NotifyHdl, LinkParamNone*, void )
1862 {
1863 InitToolBoxImages();
1864 Resize();
1865 }
1866
IMPL_LINK(SfxHelpTextWindow_Impl,FindHdl,sfx2::SearchDialog &,rDlg,void)1867 IMPL_LINK( SfxHelpTextWindow_Impl, FindHdl, sfx2::SearchDialog&, rDlg, void )
1868 {
1869 FindHdl(&rDlg);
1870 }
FindHdl(sfx2::SearchDialog * pDlg)1871 void SfxHelpTextWindow_Impl::FindHdl(sfx2::SearchDialog* pDlg)
1872 {
1873 bool bWrapAround = ( nullptr == pDlg );
1874 if ( bWrapAround )
1875 pDlg = m_xSrchDlg.get();
1876 DBG_ASSERT( pDlg, "invalid search dialog" );
1877 try
1878 {
1879 // select the words, which are equal to the search text of the search page
1880 Reference < XController > xController = xFrame->getController();
1881 if ( xController.is() )
1882 {
1883 // get document
1884 Reference < XSearchable > xSearchable( xController->getModel(), UNO_QUERY );
1885 if ( xSearchable.is() )
1886 {
1887 // create descriptor, set string and find all words
1888 Reference < XSearchDescriptor > xSrchDesc = xSearchable->createSearchDescriptor();
1889 xSrchDesc->setPropertyValue( "SearchWords", makeAny(pDlg->IsOnlyWholeWords()) );
1890 xSrchDesc->setPropertyValue( "SearchCaseSensitive", makeAny(pDlg->IsMarchCase()) );
1891 xSrchDesc->setPropertyValue( "SearchBackwards", makeAny(pDlg->IsSearchBackwards()) );
1892 xSrchDesc->setSearchString( pDlg->GetSearchText() );
1893 Reference< XInterface > xSelection;
1894 Reference< XTextRange > xCursor = getCursor();
1895
1896 if ( xCursor.is() )
1897 {
1898 if ( pDlg->IsSearchBackwards() )
1899 xCursor = xCursor->getStart();
1900 xSelection = xSearchable->findNext( xCursor, xSrchDesc );
1901 }
1902 else
1903 xSelection = xSearchable->findFirst( xSrchDesc );
1904
1905 // then select the found word
1906 if ( xSelection.is() )
1907 {
1908 Reference < XSelectionSupplier > xSelectionSup( xController, UNO_QUERY );
1909 if ( xSelectionSup.is() )
1910 {
1911 xSelectionSup->select( Any(xSelection) );
1912 }
1913 }
1914 else if ( pDlg->IsWrapAround() && !bWrapAround )
1915 {
1916 Reference < text::XTextViewCursorSupplier > xCrsrSupp( xController, uno::UNO_QUERY );
1917 Reference < text::XTextViewCursor > xTVCrsr = xCrsrSupp->getViewCursor();
1918 if ( xTVCrsr.is() )
1919 {
1920 Reference < text::XTextDocument > xDoc( xController->getModel(), uno::UNO_QUERY );
1921 Reference < text::XText > xText = xDoc->getText();
1922 if ( xText.is() )
1923 {
1924 if ( pDlg->IsSearchBackwards() )
1925 xTVCrsr->gotoRange( xText->getEnd(), false );
1926 else
1927 xTVCrsr->gotoRange( xText->getStart(), false );
1928 FindHdl( nullptr );
1929 }
1930 }
1931 }
1932 else
1933 {
1934 assert(m_xSrchDlg && "no search dialog");
1935 std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_xSrchDlg->getDialog(),
1936 VclMessageType::Info, VclButtonsType::Ok, SfxResId(STR_INFO_NOSEARCHTEXTFOUND)));
1937 xBox->run();
1938 m_xSrchDlg->SetFocusOnEdit();
1939 }
1940 }
1941 }
1942 }
1943 catch( Exception& )
1944 {
1945 TOOLS_WARN_EXCEPTION( "sfx.appl", "SfxHelpTextWindow_Impl::SelectHdl(): unexpected exception" );
1946 }
1947 }
1948
IMPL_LINK_NOARG(SfxHelpTextWindow_Impl,CloseHdl,LinkParamNone *,void)1949 IMPL_LINK_NOARG(SfxHelpTextWindow_Impl, CloseHdl, LinkParamNone*, void)
1950 {
1951 m_xSrchDlg.reset();
1952 }
1953
IMPL_LINK_NOARG(SfxHelpTextWindow_Impl,CheckHdl,weld::Toggleable &,void)1954 IMPL_LINK_NOARG(SfxHelpTextWindow_Impl, CheckHdl, weld::Toggleable&, void)
1955 {
1956 if ( !xConfiguration.is() )
1957 return;
1958
1959 bool bChecked = xOnStartupCB->get_active();
1960 try
1961 {
1962 ConfigurationHelper::writeRelativeKey(
1963 xConfiguration, PATH_OFFICE_FACTORIES + sCurrentFactory, KEY_HELP_ON_OPEN, makeAny( bChecked ) );
1964 ConfigurationHelper::flush( xConfiguration );
1965 }
1966 catch( Exception const & )
1967 {
1968 TOOLS_WARN_EXCEPTION( "sfx.appl", "SfxHelpTextWindow_Impl::CheckHdl()" );
1969 }
1970 }
1971
Resize()1972 void SfxHelpTextWindow_Impl::Resize()
1973 {
1974 Size aSize = GetOutputSizePixel();
1975 pTextWin->SetPosSizePixel( Point(0, 0), aSize );
1976 }
1977
PreNotify(NotifyEvent & rNEvt)1978 bool SfxHelpTextWindow_Impl::PreNotify( NotifyEvent& rNEvt )
1979 {
1980 bool bDone = false;
1981 MouseNotifyEvent nType = rNEvt.GetType();
1982 if ( MouseNotifyEvent::COMMAND == nType && rNEvt.GetCommandEvent() )
1983 {
1984 const CommandEvent* pCmdEvt = rNEvt.GetCommandEvent();
1985 vcl::Window* pCmdWin = rNEvt.GetWindow();
1986
1987 if ( pCmdEvt->GetCommand() == CommandEventId::ContextMenu && pCmdWin != this )
1988 {
1989 Point aPos;
1990 if ( pCmdEvt->IsMouseEvent() )
1991 aPos = pCmdEvt->GetMousePosPixel();
1992 else
1993 aPos = Point( pTextWin->GetPosPixel().X() + 20, 20 );
1994
1995 xMenu->clear();
1996
1997 if (bIsIndexOn)
1998 xMenu->append("index", aIndexOffText, BMP_HELP_TOOLBOX_INDEX_OFF);
1999 else
2000 xMenu->append("index", aIndexOnText, BMP_HELP_TOOLBOX_INDEX_ON);
2001
2002 xMenu->append_separator("separator1");
2003 xMenu->append("backward", SfxResId(STR_HELP_BUTTON_PREV), BMP_HELP_TOOLBOX_PREV);
2004 xMenu->set_sensitive("backward", xHelpWin->HasHistoryPredecessor());
2005 xMenu->append("forward", SfxResId(STR_HELP_BUTTON_NEXT), BMP_HELP_TOOLBOX_NEXT);
2006 xMenu->set_sensitive("forward", xHelpWin->HasHistorySuccessor());
2007 xMenu->append("start", SfxResId(STR_HELP_BUTTON_START), BMP_HELP_TOOLBOX_START);
2008 xMenu->append_separator("separator2");
2009 xMenu->append("print", SfxResId(STR_HELP_BUTTON_PRINT), BMP_HELP_TOOLBOX_PRINT);
2010 xMenu->append("bookmarks", SfxResId(STR_HELP_BUTTON_ADDBOOKMARK), BMP_HELP_TOOLBOX_BOOKMARKS);
2011 xMenu->append("searchdialog", SfxResId(STR_HELP_BUTTON_SEARCHDIALOG), BMP_HELP_TOOLBOX_SEARCHDIALOG);
2012 xMenu->append_separator("separator3");
2013 xMenu->append_check("selectionmode", SfxResId(STR_HELP_MENU_TEXT_SELECTION_MODE));
2014 URL aURL;
2015 aURL.Complete = ".uno:SelectTextMode";
2016 Reference< util::XURLTransformer > xTrans( util::URLTransformer::create( ::comphelper::getProcessComponentContext() ) );
2017 xTrans->parseStrict(aURL);
2018 Reference < XDispatch > xDisp = xFrame->queryDispatch( aURL, OUString(), 0 );
2019 if(xDisp.is())
2020 {
2021 rtl::Reference<HelpStatusListener_Impl> pStateListener =
2022 new HelpStatusListener_Impl(xDisp, aURL );
2023 FeatureStateEvent rEvent = pStateListener->GetStateEvent();
2024 bool bCheck = false;
2025 rEvent.State >>= bCheck;
2026 xMenu->set_active("selectionmode", bCheck);
2027 }
2028 xMenu->append_separator("separator4");
2029 xMenu->append("copy", SfxResId(STR_HELP_MENU_TEXT_COPY), BMP_HELP_TOOLBOX_COPY);
2030 xMenu->set_sensitive("copy", HasSelection());
2031
2032 if ( bIsDebug )
2033 {
2034 xMenu->append_separator("separator5");
2035 xMenu->append("sourceview", SfxResId(STR_HELP_BUTTON_SOURCEVIEW));
2036 }
2037
2038 int x, y, width, height;
2039 weld::Window* pTopLevel = GetFrameWeld();
2040 xHelpWin->GetContainer()->get_extents_relative_to(*pTopLevel, x, y, width, height);
2041 aPos.AdjustX(x);
2042 aPos.AdjustY(y);
2043
2044 xHelpWin->DoAction(xMenu->popup_at_rect(pTopLevel, tools::Rectangle(aPos, Size(1,1))));
2045 bDone = true;
2046 }
2047 }
2048 else if ( MouseNotifyEvent::KEYINPUT == nType && rNEvt.GetKeyEvent() )
2049 {
2050 const KeyEvent* pKEvt = rNEvt.GetKeyEvent();
2051 const vcl::KeyCode& rKeyCode = pKEvt->GetKeyCode();
2052 sal_uInt16 nKeyGroup = rKeyCode.GetGroup();
2053 sal_uInt16 nKey = rKeyCode.GetCode();
2054 if ( KEYGROUP_ALPHA == nKeyGroup && !isHandledKey( rKeyCode ) )
2055 {
2056 // do nothing disables the writer accelerators
2057 bDone = true;
2058 }
2059 else if ( rKeyCode.IsMod1() && ( KEY_F4 == nKey || KEY_W == nKey ) )
2060 {
2061 // <CTRL><F4> or <CTRL><W> -> close top frame
2062 xHelpWin->CloseWindow();
2063 bDone = true;
2064 }
2065 else if ( KEY_TAB == nKey && xOnStartupCB->has_focus() )
2066 {
2067 xToolBox->grab_focus();
2068 bDone = true;
2069 }
2070 }
2071
2072 return bDone || Window::PreNotify( rNEvt );
2073 }
2074
2075
GetFocus()2076 void SfxHelpTextWindow_Impl::GetFocus()
2077 {
2078 if ( bIsInClose )
2079 return;
2080
2081 try
2082 {
2083 if( xFrame.is() )
2084 {
2085 Reference< css::awt::XWindow > xWindow = xFrame->getComponentWindow();
2086 if( xWindow.is() )
2087 xWindow->setFocus();
2088 }
2089 }
2090 catch( Exception const & )
2091 {
2092 TOOLS_WARN_EXCEPTION( "sfx.appl", "SfxHelpTextWindow_Impl::GetFocus()" );
2093 }
2094 }
2095
2096
DataChanged(const DataChangedEvent & rDCEvt)2097 void SfxHelpTextWindow_Impl::DataChanged( const DataChangedEvent& rDCEvt )
2098 {
2099 Window::DataChanged( rDCEvt );
2100
2101 if ( ( ( rDCEvt.GetType() == DataChangedEventType::SETTINGS ) ||
2102 ( rDCEvt.GetType() == DataChangedEventType::DISPLAY ) ) &&
2103 ( rDCEvt.GetFlags() & AllSettingsFlags::STYLE ) )
2104 {
2105 SetBackground( Wallpaper( GetSettings().GetStyleSettings().GetFaceColor() ) );
2106 InitToolBoxImages();
2107 }
2108 }
2109
ToggleIndex(bool bOn)2110 void SfxHelpTextWindow_Impl::ToggleIndex( bool bOn )
2111 {
2112 bIsIndexOn = bOn;
2113 if ( bIsIndexOn )
2114 {
2115 xToolBox->set_item_icon_name("index", aIndexOffImage);
2116 xToolBox->set_item_tooltip_text("index", aIndexOffText);
2117 }
2118 else
2119 {
2120 xToolBox->set_item_icon_name("index", aIndexOnImage);
2121 xToolBox->set_item_tooltip_text("index", aIndexOnText);
2122 }
2123 }
2124
SelectSearchText(const OUString & rSearchText,bool _bIsFullWordSearch)2125 void SfxHelpTextWindow_Impl::SelectSearchText( const OUString& rSearchText, bool _bIsFullWordSearch )
2126 {
2127 aSearchText = rSearchText;
2128 bIsFullWordSearch = _bIsFullWordSearch;
2129 aSelectIdle.Start();
2130 }
2131
2132
SetPageStyleHeaderOff() const2133 void SfxHelpTextWindow_Impl::SetPageStyleHeaderOff() const
2134 {
2135 bool bSetOff = false;
2136 // set off the pagestyle header to prevent print output of the help URL
2137 try
2138 {
2139 Reference < XController > xController = xFrame->getController();
2140 Reference < XSelectionSupplier > xSelSup( xController, UNO_QUERY );
2141 if ( xSelSup.is() )
2142 {
2143 Reference < XIndexAccess > xSelection;
2144 if ( xSelSup->getSelection() >>= xSelection )
2145 {
2146 Reference < XTextRange > xRange;
2147 if ( xSelection->getByIndex(0) >>= xRange )
2148 {
2149 Reference < XText > xText = xRange->getText();
2150 Reference < XPropertySet > xProps( xText->createTextCursorByRange( xRange ), UNO_QUERY );
2151 OUString sStyleName;
2152 if ( xProps->getPropertyValue( "PageStyleName" ) >>= sStyleName )
2153 {
2154 Reference < XStyleFamiliesSupplier > xStyles( xController->getModel(), UNO_QUERY );
2155 Reference < XNameContainer > xContainer;
2156 if ( xStyles->getStyleFamilies()->getByName( "PageStyles" )
2157 >>= xContainer )
2158 {
2159 Reference < XStyle > xStyle;
2160 if ( xContainer->getByName( sStyleName ) >>= xStyle )
2161 {
2162 Reference < XPropertySet > xPropSet( xStyle, UNO_QUERY );
2163 xPropSet->setPropertyValue( "HeaderIsOn", makeAny( false ) );
2164
2165 Reference< XModifiable > xReset(xStyles, UNO_QUERY);
2166 xReset->setModified(false);
2167 bSetOff = true;
2168 }
2169 }
2170 }
2171 }
2172 }
2173 }
2174 }
2175 catch( Exception const & )
2176 {
2177 TOOLS_WARN_EXCEPTION( "sfx.appl", "SfxHelpTextWindow_Impl::SetPageStyleHeaderOff()" );
2178 }
2179
2180 SAL_WARN_IF( !bSetOff, "sfx.appl", "SfxHelpTextWindow_Impl::SetPageStyleHeaderOff(): set off failed" );
2181 }
2182
2183
CloseFrame()2184 void SfxHelpTextWindow_Impl::CloseFrame()
2185 {
2186 bIsInClose = true;
2187 try
2188 {
2189 css::uno::Reference< css::util::XCloseable > xCloseable ( xFrame, css::uno::UNO_QUERY );
2190 if (xCloseable.is())
2191 xCloseable->close(true);
2192 }
2193 catch( css::util::CloseVetoException& )
2194 {
2195 }
2196 }
2197
2198
DoSearch()2199 void SfxHelpTextWindow_Impl::DoSearch()
2200 {
2201 if (m_xSrchDlg)
2202 return;
2203
2204 // create the search dialog
2205 m_xSrchDlg = std::make_shared<sfx2::SearchDialog>(pTextWin->GetFrameWeld(), "HelpSearchDialog");
2206 // set handler
2207 m_xSrchDlg->SetFindHdl( LINK( this, SfxHelpTextWindow_Impl, FindHdl ) );
2208 m_xSrchDlg->SetCloseHdl( LINK( this, SfxHelpTextWindow_Impl, CloseHdl ) );
2209 // get selected text of the help page to set it as the search text
2210 Reference< XTextRange > xCursor = getCursor();
2211 if ( xCursor.is() )
2212 {
2213 OUString sText = xCursor->getString();
2214 if ( !sText.isEmpty() )
2215 m_xSrchDlg->SetSearchText( sText );
2216 }
2217 sfx2::SearchDialog::runAsync(m_xSrchDlg);
2218 }
2219
GetFocus()2220 void SfxHelpWindow_Impl::GetFocus()
2221 {
2222 if (pTextWin)
2223 pTextWin->GrabFocus();
2224 else
2225 ResizableDockingWindow::GetFocus();
2226 }
2227
MakeLayout()2228 void SfxHelpWindow_Impl::MakeLayout()
2229 {
2230 Split();
2231
2232 m_xHelpPaneWindow->set_visible(bIndex);
2233 }
2234
IMPL_LINK(SfxHelpWindow_Impl,ResizeHdl,const Size &,rSize,void)2235 IMPL_LINK(SfxHelpWindow_Impl, ResizeHdl, const Size&, rSize, void)
2236 {
2237 int nNewWidth = rSize.Width();
2238 if (!nNewWidth)
2239 return;
2240 if (bSplit)
2241 nIndexSize = round(m_xContainer->get_position() * 100.0 / nNewWidth);
2242 nWidth = nNewWidth;
2243 Split();
2244 nIndexSize = round(m_xContainer->get_position() * 100.0 / nWidth);
2245 }
2246
Split()2247 void SfxHelpWindow_Impl::Split()
2248 {
2249 if (!nWidth)
2250 return;
2251 m_xContainer->set_position(nWidth * nIndexSize / 100);
2252 bSplit = true;
2253 }
2254
LoadConfig()2255 void SfxHelpWindow_Impl::LoadConfig()
2256 {
2257 SvtViewOptions aViewOpt( EViewType::Window, CONFIGNAME_HELPWIN );
2258 if ( !aViewOpt.Exists() )
2259 return;
2260 bIndex = aViewOpt.IsVisible();
2261
2262 Any aUserItem = aViewOpt.GetUserItem( USERITEM_NAME );
2263 OUString aUserData;
2264 if ( aUserItem >>= aUserData )
2265 {
2266 DBG_ASSERT( comphelper::string::getTokenCount(aUserData, ';') == 6, "invalid user data" );
2267 sal_Int32 nIdx = 0;
2268 nIndexSize = aUserData.getToken( 0, ';', nIdx ).toInt32();
2269 aUserData.getToken(0, ';', nIdx); // ignore nTextSize
2270 sal_Int32 nOldWidth = aUserData.getToken( 0, ';', nIdx ).toInt32();
2271 sal_Int32 nOldHeight = aUserData.getToken( 0, ';', nIdx ).toInt32();
2272 aWinSize = Size(nOldWidth, nOldHeight);
2273 aWinPos.setX( aUserData.getToken( 0, ';', nIdx ).toInt32() );
2274 aWinPos.setY( aUserData.getToken( 0, ';', nIdx ).toInt32() );
2275 }
2276
2277 pTextWin->ToggleIndex( bIndex );
2278 }
2279
SaveConfig()2280 void SfxHelpWindow_Impl::SaveConfig()
2281 {
2282 SvtViewOptions aViewOpt( EViewType::Window, CONFIGNAME_HELPWIN );
2283 sal_Int32 nW = 0, nH = 0;
2284
2285 if ( xWindow.is() )
2286 {
2287 css::awt::Rectangle aRect = xWindow->getPosSize();
2288 nW = aRect.Width;
2289 nH = aRect.Height;
2290 }
2291
2292 aViewOpt.SetVisible( bIndex );
2293 VclPtr<vcl::Window> pScreenWin = VCLUnoHelper::GetWindow( xWindow );
2294 aWinPos = pScreenWin->GetWindowExtentsRelative( nullptr ).TopLeft();
2295 if (bSplit)
2296 nIndexSize = round(m_xContainer->get_position() * 100.0 / nWidth);
2297 const OUString aUserData = OUString::number( nIndexSize )
2298 + ";" + OUString::number( 100 - nIndexSize )
2299 + ";" + OUString::number( nW )
2300 + ";" + OUString::number( nH )
2301 + ";" + OUString::number( aWinPos.X() )
2302 + ";" + OUString::number( aWinPos.Y() );
2303
2304 aViewOpt.SetUserItem( USERITEM_NAME, makeAny( aUserData ) );
2305 }
2306
ShowStartPage()2307 void SfxHelpWindow_Impl::ShowStartPage()
2308 {
2309 loadHelpContent(SfxHelpWindow_Impl::buildHelpURL(xIndexWin->GetFactory(), u"/start", u""));
2310 }
2311
IMPL_LINK(SfxHelpWindow_Impl,SelectHdl,const OString &,rCurItem,void)2312 IMPL_LINK(SfxHelpWindow_Impl, SelectHdl, const OString&, rCurItem, void)
2313 {
2314 bGrabFocusToToolBox = pTextWin->GetToolBox().has_focus();
2315 DoAction(rCurItem);
2316 }
2317
IMPL_LINK_NOARG(SfxHelpWindow_Impl,OpenHdl,LinkParamNone *,void)2318 IMPL_LINK_NOARG(SfxHelpWindow_Impl, OpenHdl, LinkParamNone*, void)
2319 {
2320 xIndexWin->SelectExecutableEntry();
2321 OUString aEntry = xIndexWin->GetSelectedEntry();
2322
2323 if ( aEntry.isEmpty() )
2324 return;
2325
2326 OUString sHelpURL;
2327
2328 bool bComplete = aEntry.toAsciiLowerCase().match("vnd.sun.star.help");
2329
2330 if (bComplete)
2331 sHelpURL = aEntry;
2332 else
2333 {
2334 OUString aId;
2335 OUString aAnchor('#');
2336 if ( comphelper::string::getTokenCount(aEntry, '#') == 2 )
2337 {
2338 sal_Int32 nIdx{ 0 };
2339 aId = aEntry.getToken( 0, '#', nIdx );
2340 aAnchor += aEntry.getToken( 0, '#', nIdx );
2341 }
2342 else
2343 aId = aEntry;
2344
2345 sHelpURL = SfxHelpWindow_Impl::buildHelpURL(xIndexWin->GetFactory(), OUString("/" + aId), aAnchor);
2346 }
2347
2348 loadHelpContent(sHelpURL);
2349 }
2350
IMPL_LINK(SfxHelpWindow_Impl,SelectFactoryHdl,SfxHelpIndexWindow_Impl *,pWin,void)2351 IMPL_LINK( SfxHelpWindow_Impl, SelectFactoryHdl, SfxHelpIndexWindow_Impl* , pWin, void )
2352 {
2353 if ( sTitle.isEmpty() )
2354 sTitle = GetParent()->GetText();
2355
2356 Reference< XTitle > xTitle(xFrame, UNO_QUERY);
2357 if (xTitle.is ())
2358 xTitle->setTitle(sTitle + " - " + xIndexWin->GetActiveFactoryTitle());
2359
2360 if ( pWin )
2361 ShowStartPage();
2362 xIndexWin->ClearSearchPage();
2363 }
2364
2365
IMPL_LINK(SfxHelpWindow_Impl,ChangeHdl,HelpListener_Impl &,rListener,void)2366 IMPL_LINK( SfxHelpWindow_Impl, ChangeHdl, HelpListener_Impl&, rListener, void )
2367 {
2368 SetFactory( rListener.GetFactory() );
2369 }
2370
2371
openDone(const OUString & sURL,bool bSuccess)2372 void SfxHelpWindow_Impl::openDone(const OUString& sURL ,
2373 bool bSuccess)
2374 {
2375 INetURLObject aObj( sURL );
2376 if ( aObj.GetProtocol() == INetProtocol::VndSunStarHelp )
2377 SetFactory( aObj.GetHost() );
2378 if ( IsWait() )
2379 LeaveWait();
2380 if ( bGrabFocusToToolBox )
2381 {
2382 pTextWin->GetToolBox().grab_focus();
2383 bGrabFocusToToolBox = false;
2384 }
2385 else
2386 xIndexWin->GrabFocusBack();
2387 if ( !bSuccess )
2388 return;
2389
2390 // set some view settings: "prevent help tips" and "helpid == 68245"
2391 try
2392 {
2393 Reference < XController > xController = pTextWin->getFrame()->getController();
2394 if ( xController.is() )
2395 {
2396 Reference < XViewSettingsSupplier > xSettings( xController, UNO_QUERY );
2397 Reference < XPropertySet > xViewProps = xSettings->getViewSettings();
2398 Reference< XPropertySetInfo > xInfo = xViewProps->getPropertySetInfo();
2399 xViewProps->setPropertyValue( "ShowContentTips", makeAny( false ) );
2400 xViewProps->setPropertyValue( "ShowGraphics", makeAny( true ) );
2401 xViewProps->setPropertyValue( "ShowTables", makeAny( true ) );
2402 xViewProps->setPropertyValue( "HelpURL", makeAny( OUString("HID:SFX2_HID_HELP_ONHELP") ) );
2403 OUString sProperty( "IsExecuteHyperlinks" );
2404 if ( xInfo->hasPropertyByName( sProperty ) )
2405 xViewProps->setPropertyValue( sProperty, makeAny( true ) );
2406 xController->restoreViewData(Any());
2407 }
2408 }
2409 catch( Exception& )
2410 {
2411 TOOLS_WARN_EXCEPTION( "sfx.appl", "SfxHelpWindow_Impl::OpenDoneHdl(): unexpected exception" );
2412 }
2413
2414 // When the SearchPage opens the help doc, then select all words, which are equal to its text
2415 OUString sSearchText = comphelper::string::strip(xIndexWin->GetSearchText(), ' ');
2416 if ( !sSearchText.isEmpty() )
2417 pTextWin->SelectSearchText( sSearchText, xIndexWin->IsFullWordSearch() );
2418
2419 // no page style header -> this prevents a print output of the URL
2420 pTextWin->SetPageStyleHeaderOff();
2421 }
2422
2423
SfxHelpWindow_Impl(const css::uno::Reference<css::frame::XFrame2> & rFrame,vcl::Window * pParent)2424 SfxHelpWindow_Impl::SfxHelpWindow_Impl(
2425 const css::uno::Reference < css::frame::XFrame2 >& rFrame,
2426 vcl::Window* pParent ) :
2427
2428 ResizableDockingWindow(pParent),
2429
2430 xFrame ( rFrame ),
2431 pTextWin ( nullptr ),
2432 pHelpInterceptor ( new HelpInterceptor_Impl() ),
2433 pHelpListener ( new HelpListener_Impl( pHelpInterceptor ) ),
2434 bIndex ( true ),
2435 bGrabFocusToToolBox ( false ),
2436 bSplit ( false ),
2437 nWidth ( 0 ),
2438 nIndexSize ( 40 ), // % of width
2439 aWinPos ( 0, 0 ),
2440 aWinSize ( 0, 0 ),
2441 sTitle ( pParent->GetText() )
2442 {
2443 SetStyle(GetStyle() & ~WB_DOCKABLE);
2444
2445 SetHelpId( HID_HELP_WINDOW );
2446
2447 m_xBuilder.reset(Application::CreateInterimBuilder(m_xBox.get(), "sfx/ui/helpwindow.ui", false));
2448 m_xContainer = m_xBuilder->weld_paned("HelpWindow");
2449 m_xContainer->connect_size_allocate(LINK(this, SfxHelpWindow_Impl, ResizeHdl));
2450 m_xHelpPaneWindow = m_xBuilder->weld_container("helppanewindow");
2451 m_xHelpTextWindow = m_xBuilder->weld_container("helptextwindow");
2452 m_xHelpTextXWindow = m_xHelpTextWindow->CreateChildFrame();
2453
2454 pHelpInterceptor->InitWaiter( this );
2455 xIndexWin.reset(new SfxHelpIndexWindow_Impl(this, m_xHelpPaneWindow.get()));
2456 xIndexWin->SetDoubleClickHdl( LINK( this, SfxHelpWindow_Impl, OpenHdl ) );
2457 xIndexWin->SetSelectFactoryHdl( LINK( this, SfxHelpWindow_Impl, SelectFactoryHdl ) );
2458
2459 pTextWin = VclPtr<SfxHelpTextWindow_Impl>::Create(this, *m_xBuilder, VCLUnoHelper::GetWindow(m_xHelpTextXWindow));
2460 Reference < XFrames > xFrames = rFrame->getFrames();
2461 xFrames->append( Reference<XFrame>(pTextWin->getFrame(), UNO_QUERY_THROW) );
2462 pTextWin->SetSelectHdl( LINK( this, SfxHelpWindow_Impl, SelectHdl ) );
2463 pTextWin->Show();
2464 pHelpInterceptor->setInterception( Reference<XFrame>(pTextWin->getFrame(), UNO_QUERY_THROW) );
2465 pHelpListener->SetChangeHdl( LINK( this, SfxHelpWindow_Impl, ChangeHdl ) );
2466 LoadConfig();
2467 }
2468
~SfxHelpWindow_Impl()2469 SfxHelpWindow_Impl::~SfxHelpWindow_Impl()
2470 {
2471 disposeOnce();
2472 }
2473
dispose()2474 void SfxHelpWindow_Impl::dispose()
2475 {
2476 SaveConfig();
2477 xIndexWin.reset();
2478 pTextWin->CloseFrame();
2479 pTextWin.disposeAndClear();
2480
2481 m_xHelpTextXWindow->dispose();
2482 m_xHelpTextXWindow.clear();
2483 m_xHelpTextWindow.reset();
2484 m_xHelpPaneWindow.reset();
2485 m_xContainer.reset();
2486 m_xBuilder.reset();
2487
2488 ResizableDockingWindow::dispose();
2489 }
2490
PreNotify(NotifyEvent & rNEvt)2491 bool SfxHelpWindow_Impl::PreNotify( NotifyEvent& rNEvt )
2492 {
2493 bool bHandled = false;
2494 if ( rNEvt.GetType() == MouseNotifyEvent::KEYINPUT )
2495 {
2496 // Backward == <ALT><LEFT> or <BACKSPACE> Forward == <ALT><RIGHT>
2497 const vcl::KeyCode& rKeyCode = rNEvt.GetKeyEvent()->GetKeyCode();
2498 sal_uInt16 nKey = rKeyCode.GetCode();
2499 if ( ( rKeyCode.IsMod2() && ( KEY_LEFT == nKey || KEY_RIGHT == nKey ) ) ||
2500 ( !rKeyCode.GetModifier() && KEY_BACKSPACE == nKey && !xIndexWin->HasFocusOnEdit() ) )
2501 {
2502 DoAction( rKeyCode.GetCode() == KEY_RIGHT ? "forward" : "backward" );
2503 bHandled = true;
2504 }
2505 else if ( rKeyCode.IsMod1() && ( KEY_F4 == nKey || KEY_W == nKey ) )
2506 {
2507 // <CTRL><F4> or <CTRL><W> -> close top frame
2508 CloseWindow();
2509 bHandled = true;
2510 }
2511 }
2512 return bHandled || Window::PreNotify( rNEvt );
2513 }
2514
setContainerWindow(const Reference<css::awt::XWindow> & xWin)2515 void SfxHelpWindow_Impl::setContainerWindow( const Reference < css::awt::XWindow >& xWin )
2516 {
2517 xWindow = xWin;
2518 MakeLayout();
2519 if (xWindow.is())
2520 {
2521 VclPtr<vcl::Window> pScreenWin = VCLUnoHelper::GetWindow(xWindow);
2522 if (aWinSize.Width() && aWinSize.Height())
2523 pScreenWin->SetPosSizePixel(aWinPos, aWinSize);
2524 else
2525 pScreenWin->SetPosPixel(aWinPos);
2526 }
2527 }
2528
SetFactory(const OUString & rFactory)2529 void SfxHelpWindow_Impl::SetFactory( const OUString& rFactory )
2530 {
2531 xIndexWin->SetFactory( rFactory, true );
2532 }
2533
SetHelpURL(const OUString & rURL)2534 void SfxHelpWindow_Impl::SetHelpURL( const OUString& rURL )
2535 {
2536 INetURLObject aObj( rURL );
2537 if ( aObj.GetProtocol() == INetProtocol::VndSunStarHelp )
2538 SetFactory( aObj.GetHost() );
2539 }
2540
DoAction(std::string_view rActionId)2541 void SfxHelpWindow_Impl::DoAction(std::string_view rActionId)
2542 {
2543 if (rActionId == "index")
2544 {
2545 bIndex = !bIndex;
2546 MakeLayout();
2547 pTextWin->ToggleIndex( bIndex );
2548 }
2549 else if (rActionId == "start")
2550 {
2551 ShowStartPage();
2552 }
2553 else if (rActionId == "backward" || rActionId == "forward")
2554 {
2555 URL aURL;
2556 aURL.Complete = ".uno:Backward";
2557 if (rActionId == "forward")
2558 aURL.Complete = ".uno:Forward";
2559 Reference< util::XURLTransformer > xTrans( util::URLTransformer::create( ::comphelper::getProcessComponentContext() ) );
2560 xTrans->parseStrict(aURL);
2561 pHelpInterceptor->dispatch( aURL, Sequence < PropertyValue >() );
2562 }
2563 else if (rActionId == "searchdialog")
2564 {
2565 pTextWin->DoSearch();
2566 }
2567 else if (rActionId == "print" || rActionId == "sourceview" || rActionId == "copy" || rActionId == "selectionmode")
2568 {
2569 Reference < XDispatchProvider > xProv = pTextWin->getFrame();
2570 if ( xProv.is() )
2571 {
2572 URL aURL;
2573 if (rActionId == "print")
2574 aURL.Complete = ".uno:Print";
2575 else if (rActionId == "sourceview")
2576 aURL.Complete = ".uno:SourceView";
2577 else if (rActionId == "copy")
2578 aURL.Complete = ".uno:Copy";
2579 else // rActionId == "selectionmode"
2580 aURL.Complete = ".uno:SelectTextMode";
2581 Reference< util::XURLTransformer > xTrans( util::URLTransformer::create( ::comphelper::getProcessComponentContext() ) );
2582 xTrans->parseStrict(aURL);
2583 Reference < XDispatch > xDisp = xProv->queryDispatch( aURL, OUString(), 0 );
2584 if ( xDisp.is() )
2585 xDisp->dispatch( aURL, Sequence < PropertyValue >() );
2586 }
2587 }
2588 else if (rActionId == "bookmarks")
2589 {
2590 OUString aURL = pHelpInterceptor->GetCurrentURL();
2591 if ( !aURL.isEmpty() )
2592 {
2593 try
2594 {
2595 Content aCnt( aURL, Reference< css::ucb::XCommandEnvironment >(), comphelper::getProcessComponentContext() );
2596 css::uno::Reference< css::beans::XPropertySetInfo > xInfo = aCnt.getProperties();
2597 if ( xInfo->hasPropertyByName( PROPERTY_TITLE ) )
2598 {
2599 css::uno::Any aAny = aCnt.getPropertyValue( PROPERTY_TITLE );
2600 OUString aValue;
2601 if ( aAny >>= aValue )
2602 {
2603 SfxAddHelpBookmarkDialog_Impl aDlg(GetFrameWeld(), false);
2604 aDlg.SetTitle(aValue);
2605 if (aDlg.run() == RET_OK )
2606 {
2607 xIndexWin->AddBookmarks( aDlg.GetTitle(), aURL );
2608 }
2609 }
2610 }
2611 }
2612 catch( Exception& )
2613 {
2614 TOOLS_WARN_EXCEPTION( "sfx.appl", "SfxHelpWindow_Impl::DoAction(): unexpected exception" );
2615 }
2616 }
2617 }
2618 }
2619
CloseWindow()2620 void SfxHelpWindow_Impl::CloseWindow()
2621 {
2622 try
2623 {
2624 // search for top frame
2625 Reference< XFramesSupplier > xCreator = getTextFrame()->getCreator();
2626 while ( xCreator.is() && !xCreator->isTop() )
2627 {
2628 xCreator = xCreator->getCreator();
2629 }
2630
2631 // when found, close it
2632 if ( xCreator.is() && xCreator->isTop() )
2633 {
2634 Reference < XCloseable > xCloser( xCreator, UNO_QUERY );
2635 if ( xCloser.is() )
2636 xCloser->close( false );
2637 }
2638 }
2639 catch( Exception const & )
2640 {
2641 TOOLS_WARN_EXCEPTION( "sfx.appl", "SfxHelpWindow_Impl::CloseWindow()" );
2642 }
2643 }
2644
2645
UpdateToolbox()2646 void SfxHelpWindow_Impl::UpdateToolbox()
2647 {
2648 pTextWin->GetToolBox().set_item_sensitive("backward", pHelpInterceptor->HasHistoryPred());
2649 pTextWin->GetToolBox().set_item_sensitive("forward", pHelpInterceptor->HasHistorySucc());
2650 }
2651
2652
HasHistoryPredecessor() const2653 bool SfxHelpWindow_Impl::HasHistoryPredecessor() const
2654 {
2655 return pHelpInterceptor->HasHistoryPred();
2656 }
2657
2658
HasHistorySuccessor() const2659 bool SfxHelpWindow_Impl::HasHistorySuccessor() const
2660 {
2661 return pHelpInterceptor->HasHistorySucc();
2662 }
2663
2664 // class SfxAddHelpBookmarkDialog_Impl -----------------------------------
2665
SfxAddHelpBookmarkDialog_Impl(weld::Widget * pParent,bool bRename)2666 SfxAddHelpBookmarkDialog_Impl::SfxAddHelpBookmarkDialog_Impl(weld::Widget* pParent, bool bRename)
2667 : GenericDialogController(pParent, "sfx/ui/bookmarkdialog.ui", "BookmarkDialog")
2668 , m_xTitleED(m_xBuilder->weld_entry("entry"))
2669 , m_xAltTitle(m_xBuilder->weld_label("alttitle"))
2670 {
2671 if (bRename)
2672 m_xDialog->set_title(m_xAltTitle->get_label());
2673 }
2674
SetTitle(const OUString & rTitle)2675 void SfxAddHelpBookmarkDialog_Impl::SetTitle(const OUString& rTitle)
2676 {
2677 m_xTitleED->set_text(rTitle);
2678 m_xTitleED->select_region(0, -1);
2679 }
2680
2681 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
2682