tdf#130857 qt weld: Implement QtInstanceWidget::get_text_height
[LibreOffice.git] / cui / source / dialogs / hlmarkwn.cxx
blobf35be2db2aea2a9a18731e5e51668c11464ab959
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <dialmgr.hxx>
21 #include <o3tl/any.hxx>
22 #include <comphelper/propertyvalue.hxx>
23 #include <unotools/viewoptions.hxx>
24 #include <vcl/graph.hxx>
26 // UNO-Stuff
27 #include <comphelper/processfactory.hxx>
28 #include <comphelper/sequence.hxx>
29 #include <com/sun/star/awt/XBitmap.hpp>
30 #include <com/sun/star/frame/Desktop.hpp>
31 #include <com/sun/star/beans/NamedValue.hpp>
32 #include <com/sun/star/beans/PropertyValue.hpp>
33 #include <com/sun/star/document/XLinkTargetSupplier.hpp>
34 #include <com/sun/star/beans/XPropertySet.hpp>
35 #include <com/sun/star/io/IOException.hpp>
37 #include <toolkit/helper/vclunohelper.hxx>
39 #include <strings.hrc>
40 #include <hlmarkwn.hxx>
41 #include <hltpbase.hxx>
42 #include <hlmarkwn_def.hxx>
44 #include <stack>
46 using namespace ::com::sun::star;
48 namespace {
50 // Userdata-struct for tree-entries
51 struct TargetData
53 OUString aUStrLinkname;
54 bool bIsTarget;
56 TargetData (const OUString& aUStrLName, bool bTarget)
57 : bIsTarget(bTarget)
59 if (bIsTarget)
60 aUStrLinkname = aUStrLName;
66 //*** Window-Class ***
67 // Constructor / Destructor
68 SvxHlinkDlgMarkWnd::SvxHlinkDlgMarkWnd(weld::Window* pParentDialog, SvxHyperlinkTabPageBase *pParentPage)
69 : GenericDialogController(pParentDialog, u"cui/ui/hyperlinkmarkdialog.ui"_ustr, u"HyperlinkMark"_ustr)
70 , mpParent(pParentPage)
71 , mnError(LERR_NOERROR)
72 , mxBtApply(m_xBuilder->weld_button(u"ok"_ustr))
73 , mxBtClose(m_xBuilder->weld_button(u"close"_ustr))
74 , mxLbTree(m_xBuilder->weld_tree_view(u"TreeListBox"_ustr))
75 , mxError(m_xBuilder->weld_label(u"error"_ustr))
77 mxLbTree->set_size_request(mxLbTree->get_approximate_digit_width() * 25,
78 mxLbTree->get_height_rows(12));
79 mxBtApply->connect_clicked( LINK ( this, SvxHlinkDlgMarkWnd, ClickApplyHdl_Impl ) );
80 mxBtClose->connect_clicked( LINK ( this, SvxHlinkDlgMarkWnd, ClickCloseHdl_Impl ) );
81 mxLbTree->connect_row_activated( LINK ( this, SvxHlinkDlgMarkWnd, DoubleClickApplyHdl_Impl ) );
83 // tdf#149935 - remember last used position and size
84 SvtViewOptions aDlgOpt(EViewType::Dialog, m_xDialog->get_help_id());
85 if (aDlgOpt.Exists())
86 m_xDialog->set_window_state(aDlgOpt.GetWindowState());
89 SvxHlinkDlgMarkWnd::~SvxHlinkDlgMarkWnd()
91 ClearTree();
92 // tdf#149935 - remember last used position and size
93 SvtViewOptions aDlgOpt(EViewType::Dialog, m_xDialog->get_help_id());
94 aDlgOpt.SetWindowState(m_xDialog->get_window_state(vcl::WindowDataMask::PosSize));
97 void SvxHlinkDlgMarkWnd::ErrorChanged()
99 if (mnError == LERR_NOENTRIES)
101 OUString aStrMessage = CuiResId( RID_CUISTR_HYPDLG_ERR_LERR_NOENTRIES );
102 mxError->set_label(aStrMessage);
103 mxError->show();
104 mxLbTree->hide();
106 else if (mnError == LERR_DOCNOTOPEN)
108 OUString aStrMessage = CuiResId( RID_CUISTR_HYPDLG_ERR_LERR_DOCNOTOPEN );
109 mxError->set_label(aStrMessage);
110 mxError->show();
111 mxLbTree->hide();
113 else
115 mxLbTree->show();
116 mxError->hide();
120 // Set an errorstatus
121 sal_uInt16 SvxHlinkDlgMarkWnd::SetError( sal_uInt16 nError)
123 sal_uInt16 nOldError = mnError;
124 mnError = nError;
126 if( mnError != LERR_NOERROR )
127 ClearTree();
129 ErrorChanged();
131 return nOldError;
134 // Move window
135 void SvxHlinkDlgMarkWnd::MoveTo(const Point& rNewPos)
137 // tdf#149935 - remember last used position and size
138 SvtViewOptions aDlgOpt(EViewType::Dialog, m_xDialog->get_help_id());
139 if (aDlgOpt.Exists())
140 m_xDialog->set_window_state(aDlgOpt.GetWindowState());
141 else
142 m_xDialog->window_move(rNewPos.X(), rNewPos.Y());
145 namespace
147 void SelectPath(weld::TreeIter* pEntry, weld::TreeView& rLbTree,
148 std::deque<OUString> &rLastSelectedPath)
150 OUString sTitle(rLastSelectedPath.front());
151 rLastSelectedPath.pop_front();
152 if (sTitle.isEmpty())
153 return;
154 while (pEntry)
156 if (sTitle == rLbTree.get_text(*pEntry))
158 rLbTree.select(*pEntry);
159 rLbTree.scroll_to_row(*pEntry);
160 if (!rLastSelectedPath.empty())
162 rLbTree.expand_row(*pEntry);
163 if (!rLbTree.iter_children(*pEntry))
164 pEntry = nullptr;
165 SelectPath(pEntry, rLbTree, rLastSelectedPath);
167 break;
169 if (!rLbTree.iter_next_sibling(*pEntry))
170 pEntry = nullptr;
175 constexpr OUString TG_SETTING_MANAGER = u"TargetInDocument"_ustr;
176 constexpr OUString TG_SETTING_LASTMARK = u"LastSelectedMark"_ustr;
177 constexpr OUString TG_SETTING_LASTPATH = u"LastSelectedPath"_ustr;
179 void SvxHlinkDlgMarkWnd::RestoreLastSelection()
181 bool bSelectedEntry = false;
183 OUString sLastSelectedMark;
184 std::deque<OUString> aLastSelectedPath;
185 SvtViewOptions aViewSettings( EViewType::Dialog, TG_SETTING_MANAGER );
186 if (aViewSettings.Exists())
188 //Maybe we might want to have some sort of mru list and keep a mapping
189 //per document, rather than the current reuse of "the last thing
190 //selected, regardless of the document"
191 aViewSettings.GetUserItem(TG_SETTING_LASTMARK) >>= sLastSelectedMark;
192 uno::Sequence<OUString> aTmp;
193 aViewSettings.GetUserItem(TG_SETTING_LASTPATH) >>= aTmp;
194 aLastSelectedPath = comphelper::sequenceToContainer< std::deque<OUString> >(aTmp);
196 //fallback to previous entry selected the last time we executed this dialog.
197 //First see if the exact mark exists and re-use that
198 if (!sLastSelectedMark.isEmpty())
199 bSelectedEntry = SelectEntry(sLastSelectedMark);
200 //Otherwise just select the closest path available
201 //now to what was available at dialog close time
202 if (!bSelectedEntry && !aLastSelectedPath.empty())
204 std::deque<OUString> aTmpSelectedPath(std::move(aLastSelectedPath));
205 std::unique_ptr<weld::TreeIter> xEntry(mxLbTree->make_iterator());
206 if (!mxLbTree->get_iter_first(*xEntry))
207 xEntry.reset();
208 SelectPath(xEntry.get(), *mxLbTree, aTmpSelectedPath);
212 // Interface to refresh tree
213 void SvxHlinkDlgMarkWnd::RefreshTree (const OUString& aStrURL)
215 OUString aUStrURL;
217 weld::WaitObject aWait(m_xDialog.get());
219 ClearTree();
221 sal_Int32 nPos = aStrURL.indexOf('#');
223 if (nPos != 0)
224 aUStrURL = aStrURL;
226 if (!RefreshFromDoc(aUStrURL))
227 ErrorChanged();
229 bool bSelectedEntry = false;
231 if ( nPos != -1 )
233 OUString aStrMark = aStrURL.copy(nPos+1);
234 bSelectedEntry = SelectEntry(aStrMark);
237 if (!bSelectedEntry)
238 RestoreLastSelection();
241 // get links from document
242 bool SvxHlinkDlgMarkWnd::RefreshFromDoc(const OUString& aURL)
244 mnError = LERR_NOERROR;
246 uno::Reference< frame::XDesktop2 > xDesktop = frame::Desktop::create( ::comphelper::getProcessComponentContext() );
247 uno::Reference< lang::XComponent > xComp;
249 if( !aURL.isEmpty() )
251 // load from url
252 if( xDesktop.is() )
256 uno::Sequence< beans::PropertyValue > aArg { comphelper::makePropertyValue(u"Hidden"_ustr, true) };
257 xComp = xDesktop->loadComponentFromURL( aURL, u"_blank"_ustr, 0, aArg );
259 catch( const io::IOException& )
263 catch( const lang::IllegalArgumentException& )
269 else
271 // the component with user focus ( current document )
272 xComp = xDesktop->getCurrentComponent();
275 if( xComp.is() )
277 uno::Reference< document::XLinkTargetSupplier > xLTS( xComp, uno::UNO_QUERY );
279 if( xLTS.is() )
281 if( FillTree( xLTS->getLinks() ) == 0 )
282 mnError = LERR_NOENTRIES;
284 else
285 mnError = LERR_DOCNOTOPEN;
287 if ( !aURL.isEmpty() )
288 xComp->dispose();
290 else
292 if( !aURL.isEmpty() )
293 mnError=LERR_DOCNOTOPEN;
295 return (mnError==0);
298 // Fill Tree-Control
299 int SvxHlinkDlgMarkWnd::FillTree( const uno::Reference< container::XNameAccess >& xLinks, const weld::TreeIter* pParentEntry )
301 // used to create the Headings outline parent children tree view relation
302 std::stack<std::pair<std::unique_ptr<weld::TreeIter>, const sal_Int32>> aHeadingsParentEntryStack;
304 int nEntries=0;
306 static constexpr OUStringLiteral aProp_LinkDisplayName( u"LinkDisplayName" );
307 static constexpr OUStringLiteral aProp_LinkTarget( u"com.sun.star.document.LinkTarget" );
308 static constexpr OUStringLiteral aProp_LinkDisplayBitmap( u"LinkDisplayBitmap" );
309 for (auto& aLink : xLinks->getElementNames())
311 uno::Any aAny;
315 aAny = xLinks->getByName( aLink );
317 catch(const uno::Exception&)
319 // if the name of the target was invalid (like empty headings)
320 // no object can be provided
321 continue;
324 uno::Reference< beans::XPropertySet > xTarget;
326 if( aAny >>= xTarget )
330 // get name to display
331 aAny = xTarget->getPropertyValue( aProp_LinkDisplayName );
332 OUString aDisplayName;
333 aAny >>= aDisplayName;
334 OUString aStrDisplayname ( aDisplayName );
336 // is it a target ?
337 uno::Reference< lang::XServiceInfo > xSI( xTarget, uno::UNO_QUERY );
338 bool bIsTarget = xSI->supportsService( aProp_LinkTarget );
340 // create userdata
341 TargetData *pData = new TargetData ( aLink, bIsTarget );
342 OUString sId(weld::toId(pData));
344 std::unique_ptr<weld::TreeIter> xEntry(mxLbTree->make_iterator());
345 if (pParentEntry)
347 OUString sContentType = mxLbTree->get_text(*pParentEntry);
348 if (sContentType == "Headings")
350 if (aHeadingsParentEntryStack.empty())
351 aHeadingsParentEntryStack.push(
352 std::pair(mxLbTree->make_iterator(pParentEntry), -1));
354 // get the headings name to display
355 aAny = xTarget->getPropertyValue(u"ActualOutlineName"_ustr);
356 OUString sActualOutlineName;
357 aAny >>= sActualOutlineName;
359 // get the headings outline level
360 aAny = xTarget->getPropertyValue(u"OutlineLevel"_ustr);
361 sal_Int32 nOutlineLevel = *o3tl::doAccess<sal_Int32>(aAny);
363 // pop until the top of stack entry has an outline level less than
364 // the to be inserted heading outline level
365 while (nOutlineLevel <= aHeadingsParentEntryStack.top().second)
366 aHeadingsParentEntryStack.pop();
368 mxLbTree->insert(aHeadingsParentEntryStack.top().first.get(), -1,
369 &sActualOutlineName, &sId, nullptr, nullptr, false,
370 xEntry.get());
372 // push if the inserted entry is a child
373 if (nOutlineLevel > aHeadingsParentEntryStack.top().second)
374 aHeadingsParentEntryStack.push(
375 std::pair(mxLbTree->make_iterator(xEntry.get()), nOutlineLevel));
377 else
379 mxLbTree->insert(pParentEntry, -1, &aStrDisplayname, &sId, nullptr,
380 nullptr, false, xEntry.get());
383 else
385 mxLbTree->insert(pParentEntry, -1, &aStrDisplayname, &sId, nullptr, nullptr,
386 false, xEntry.get());
391 // get bitmap for the tree-entry
392 uno::Reference< awt::XBitmap >
393 aXBitmap( xTarget->getPropertyValue( aProp_LinkDisplayBitmap ), uno::UNO_QUERY );
394 if (aXBitmap.is())
396 Graphic aBmp(Graphic(VCLUnoHelper::GetBitmap(aXBitmap)));
397 // insert Displayname into treelist with bitmaps
398 mxLbTree->set_image(*xEntry, aBmp.GetXGraphic(), -1);
401 catch(const css::uno::Exception&)
405 nEntries++;
407 uno::Reference< document::XLinkTargetSupplier > xLTS( xTarget, uno::UNO_QUERY );
408 if( xLTS.is() )
409 nEntries += FillTree( xLTS->getLinks(), xEntry.get() );
411 catch(const css::uno::Exception&)
417 return nEntries;
420 // Clear Tree
421 void SvxHlinkDlgMarkWnd::ClearTree()
423 std::unique_ptr<weld::TreeIter> xEntry = mxLbTree->make_iterator();
424 bool bEntry = mxLbTree->get_iter_first(*xEntry);
426 while (bEntry)
428 TargetData* pUserData = weld::fromId<TargetData*>(mxLbTree->get_id(*xEntry));
429 delete pUserData;
431 bEntry = mxLbTree->iter_next(*xEntry);
434 mxLbTree->clear();
437 // Find Entry for String
438 std::unique_ptr<weld::TreeIter> SvxHlinkDlgMarkWnd::FindEntry (std::u16string_view aStrName)
440 bool bFound=false;
441 std::unique_ptr<weld::TreeIter> xEntry = mxLbTree->make_iterator();
442 bool bEntry = mxLbTree->get_iter_first(*xEntry);
444 while (bEntry && !bFound)
446 TargetData* pUserData = weld::fromId<TargetData*>(mxLbTree->get_id(*xEntry));
447 if (aStrName == pUserData->aUStrLinkname)
448 bFound = true;
449 else
450 bEntry = mxLbTree->iter_next(*xEntry);
453 if (!bFound)
454 xEntry.reset();
456 return xEntry;
459 // Select Entry
460 bool SvxHlinkDlgMarkWnd::SelectEntry(std::u16string_view aStrMark)
462 std::unique_ptr<weld::TreeIter> xEntry = FindEntry(aStrMark);
463 if (!xEntry)
464 return false;
465 mxLbTree->set_cursor(*xEntry);
466 return true;
469 // Click on Apply-Button / Double-click on item in tree
470 IMPL_LINK_NOARG(SvxHlinkDlgMarkWnd, DoubleClickApplyHdl_Impl, weld::TreeView&, bool)
472 ClickApplyHdl_Impl(*mxBtApply);
473 return true;
476 IMPL_LINK_NOARG(SvxHlinkDlgMarkWnd, ClickApplyHdl_Impl, weld::Button&, void)
478 std::unique_ptr<weld::TreeIter> xEntry(mxLbTree->make_iterator());
479 bool bEntry = mxLbTree->get_cursor(xEntry.get());
480 if (bEntry)
482 TargetData* pData = weld::fromId<TargetData*>(mxLbTree->get_id(*xEntry));
483 if (pData->bIsTarget)
485 mpParent->SetMarkStr(pData->aUStrLinkname);
490 // Click on Close-Button
491 IMPL_LINK_NOARG(SvxHlinkDlgMarkWnd, ClickCloseHdl_Impl, weld::Button&, void)
493 std::unique_ptr<weld::TreeIter> xEntry(mxLbTree->make_iterator());
494 bool bEntry = mxLbTree->get_cursor(xEntry.get());
495 if (bEntry)
497 TargetData* pUserData = weld::fromId<TargetData*>(mxLbTree->get_id(*xEntry));
498 OUString sLastSelectedMark = pUserData->aUStrLinkname;
500 std::deque<OUString> aLastSelectedPath;
501 //If the bottommost entry is expanded but nothing
502 //underneath it is selected leave a dummy entry
503 if (mxLbTree->get_row_expanded(*xEntry))
504 aLastSelectedPath.push_front(OUString());
505 while (bEntry)
507 aLastSelectedPath.push_front(mxLbTree->get_text(*xEntry));
508 bEntry = mxLbTree->iter_parent(*xEntry);
511 uno::Sequence< beans::NamedValue > aSettings
513 { TG_SETTING_LASTMARK, css::uno::Any(sLastSelectedMark) },
514 { TG_SETTING_LASTPATH, css::uno::Any(comphelper::containerToSequence(aLastSelectedPath)) }
517 // write
518 SvtViewOptions aViewSettings( EViewType::Dialog, TG_SETTING_MANAGER );
519 aViewSettings.SetUserData( aSettings );
522 m_xDialog->response(RET_CANCEL);
525 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */