LibreOffice Module cui (master) 1
hlmarkwn.cxx
Go to the documentation of this file.
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#include <dialmgr.hxx>
21#include <o3tl/any.hxx>
24#include <vcl/graph.hxx>
25
26// UNO-Stuff
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>
36
38
39#include <strings.hrc>
40#include <hlmarkwn.hxx>
41#include <hltpbase.hxx>
42#include <hlmarkwn_def.hxx>
43
44#include <stack>
45
46using namespace ::com::sun::star;
47
48namespace {
49
50// Userdata-struct for tree-entries
51struct TargetData
52{
53 OUString aUStrLinkname;
54 bool bIsTarget;
55
56 TargetData (const OUString& aUStrLName, bool bTarget)
57 : bIsTarget(bTarget)
58 {
59 if (bIsTarget)
60 aUStrLinkname = aUStrLName;
61 }
62};
63
64}
65
66//*** Window-Class ***
67// Constructor / Destructor
69 : GenericDialogController(pParentDialog, "cui/ui/hyperlinkmarkdialog.ui", "HyperlinkMark")
70 , mpParent(pParentPage)
71 , mnError(LERR_NOERROR)
72 , mxBtApply(m_xBuilder->weld_button("ok"))
73 , mxBtClose(m_xBuilder->weld_button("close"))
74 , mxLbTree(m_xBuilder->weld_tree_view("TreeListBox"))
75 , mxError(m_xBuilder->weld_label("error"))
76{
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 ) );
82}
83
85{
86 ClearTree();
87}
88
90{
92 {
93 OUString aStrMessage = CuiResId( RID_CUISTR_HYPDLG_ERR_LERR_NOENTRIES );
94 mxError->set_label(aStrMessage);
95 mxError->show();
96 mxLbTree->hide();
97 }
98 else if (mnError == LERR_DOCNOTOPEN)
99 {
100 OUString aStrMessage = CuiResId( RID_CUISTR_HYPDLG_ERR_LERR_DOCNOTOPEN );
101 mxError->set_label(aStrMessage);
102 mxError->show();
103 mxLbTree->hide();
104 }
105 else
106 {
107 mxLbTree->show();
108 mxError->hide();
109 }
110}
111
112// Set an errorstatus
113sal_uInt16 SvxHlinkDlgMarkWnd::SetError( sal_uInt16 nError)
114{
115 sal_uInt16 nOldError = mnError;
116 mnError = nError;
117
118 if( mnError != LERR_NOERROR )
119 ClearTree();
120
121 ErrorChanged();
122
123 return nOldError;
124}
125
126// Move window
128{
129 m_xDialog->window_move(rNewPos.X(), rNewPos.Y());
130}
131
132namespace
133{
134 void SelectPath(weld::TreeIter* pEntry, weld::TreeView& rLbTree,
135 std::deque<OUString> &rLastSelectedPath)
136 {
137 OUString sTitle(rLastSelectedPath.front());
138 rLastSelectedPath.pop_front();
139 if (sTitle.isEmpty())
140 return;
141 while (pEntry)
142 {
143 if (sTitle == rLbTree.get_text(*pEntry))
144 {
145 rLbTree.select(*pEntry);
146 rLbTree.scroll_to_row(*pEntry);
147 if (!rLastSelectedPath.empty())
148 {
149 rLbTree.expand_row(*pEntry);
150 if (!rLbTree.iter_children(*pEntry))
151 pEntry = nullptr;
152 SelectPath(pEntry, rLbTree, rLastSelectedPath);
153 }
154 break;
155 }
156 if (!rLbTree.iter_next_sibling(*pEntry))
157 pEntry = nullptr;
158 }
159 }
160}
161
162constexpr OUStringLiteral TG_SETTING_MANAGER = u"TargetInDocument";
163constexpr OUStringLiteral TG_SETTING_LASTMARK = u"LastSelectedMark";
164constexpr OUStringLiteral TG_SETTING_LASTPATH = u"LastSelectedPath";
165
167{
168 bool bSelectedEntry = false;
169
170 OUString sLastSelectedMark;
171 std::deque<OUString> aLastSelectedPath;
172 SvtViewOptions aViewSettings( EViewType::Dialog, TG_SETTING_MANAGER );
173 if (aViewSettings.Exists())
174 {
175 //Maybe we might want to have some sort of mru list and keep a mapping
176 //per document, rather than the current reuse of "the last thing
177 //selected, regardless of the document"
178 aViewSettings.GetUserItem(TG_SETTING_LASTMARK) >>= sLastSelectedMark;
180 aViewSettings.GetUserItem(TG_SETTING_LASTPATH) >>= aTmp;
181 aLastSelectedPath = comphelper::sequenceToContainer< std::deque<OUString> >(aTmp);
182 }
183 //fallback to previous entry selected the last time we executed this dialog.
184 //First see if the exact mark exists and re-use that
185 if (!sLastSelectedMark.isEmpty())
186 bSelectedEntry = SelectEntry(sLastSelectedMark);
187 //Otherwise just select the closest path available
188 //now to what was available at dialog close time
189 if (!bSelectedEntry && !aLastSelectedPath.empty())
190 {
191 std::deque<OUString> aTmpSelectedPath(aLastSelectedPath);
192 std::unique_ptr<weld::TreeIter> xEntry(mxLbTree->make_iterator());
193 if (!mxLbTree->get_iter_first(*xEntry))
194 xEntry.reset();
195 SelectPath(xEntry.get(), *mxLbTree, aTmpSelectedPath);
196 }
197}
198
199// Interface to refresh tree
200void SvxHlinkDlgMarkWnd::RefreshTree (const OUString& aStrURL)
201{
202 OUString aUStrURL;
203
204 weld::WaitObject aWait(m_xDialog.get());
205
206 ClearTree();
207
208 sal_Int32 nPos = aStrURL.indexOf('#');
209
210 if (nPos != 0)
211 aUStrURL = aStrURL;
212
213 if (!RefreshFromDoc(aUStrURL))
214 ErrorChanged();
215
216 bool bSelectedEntry = false;
217
218 if ( nPos != -1 )
219 {
220 OUString aStrMark = aStrURL.copy(nPos+1);
221 bSelectedEntry = SelectEntry(aStrMark);
222 }
223
224 if (!bSelectedEntry)
226}
227
228// get links from document
229bool SvxHlinkDlgMarkWnd::RefreshFromDoc(const OUString& aURL)
230{
232
233 uno::Reference< frame::XDesktop2 > xDesktop = frame::Desktop::create( ::comphelper::getProcessComponentContext() );
235
236 if( !aURL.isEmpty() )
237 {
238 // load from url
239 if( xDesktop.is() )
240 {
241 try
242 {
244 xComp = xDesktop->loadComponentFromURL( aURL, "_blank", 0, aArg );
245 }
246 catch( const io::IOException& )
247 {
248
249 }
250 catch( const lang::IllegalArgumentException& )
251 {
252
253 }
254 }
255 }
256 else
257 {
258 // the component with user focus ( current document )
259 xComp = xDesktop->getCurrentComponent();
260 }
261
262 if( xComp.is() )
263 {
264 uno::Reference< document::XLinkTargetSupplier > xLTS( xComp, uno::UNO_QUERY );
265
266 if( xLTS.is() )
267 {
268 if( FillTree( xLTS->getLinks() ) == 0 )
270 }
271 else
273
274 if ( !aURL.isEmpty() )
275 xComp->dispose();
276 }
277 else
278 {
279 if( !aURL.isEmpty() )
281 }
282 return (mnError==0);
283}
284
285// Fill Tree-Control
287{
288 // used to create the Headings outline parent children tree view relation
289 std::stack<std::pair<std::unique_ptr<weld::TreeIter>, const sal_Int32>> aHeadingsParentEntryStack;
290
291 int nEntries=0;
292 const uno::Sequence< OUString > aNames( xLinks->getElementNames() );
293 const sal_Int32 nLinks = aNames.getLength();
294 const OUString* pNames = aNames.getConstArray();
295
296 static constexpr OUStringLiteral aProp_LinkDisplayName( u"LinkDisplayName" );
297 static constexpr OUStringLiteral aProp_LinkTarget( u"com.sun.star.document.LinkTarget" );
298 static constexpr OUStringLiteral aProp_LinkDisplayBitmap( u"LinkDisplayBitmap" );
299 for( sal_Int32 i = 0; i < nLinks; i++ )
300 {
301 uno::Any aAny;
302 OUString aLink( *pNames++ );
303
304 bool bError = false;
305 try
306 {
307 aAny = xLinks->getByName( aLink );
308 }
309 catch(const uno::Exception&)
310 {
311 // if the name of the target was invalid (like empty headings)
312 // no object can be provided
313 bError = true;
314 }
315 if(bError)
316 continue;
317
319
320 if( aAny >>= xTarget )
321 {
322 try
323 {
324 // get name to display
325 aAny = xTarget->getPropertyValue( aProp_LinkDisplayName );
326 OUString aDisplayName;
327 aAny >>= aDisplayName;
328 OUString aStrDisplayname ( aDisplayName );
329
330 // is it a target ?
331 uno::Reference< lang::XServiceInfo > xSI( xTarget, uno::UNO_QUERY );
332 bool bIsTarget = xSI->supportsService( aProp_LinkTarget );
333
334 // create userdata
335 TargetData *pData = new TargetData ( aLink, bIsTarget );
336 OUString sId(weld::toId(pData));
337
338 std::unique_ptr<weld::TreeIter> xEntry(mxLbTree->make_iterator());
339 if (pParentEntry)
340 {
341 OUString sContentType = mxLbTree->get_text(*pParentEntry);
342 if (sContentType == "Headings")
343 {
344 if (aHeadingsParentEntryStack.empty())
345 aHeadingsParentEntryStack.push(
346 std::pair(mxLbTree->make_iterator(pParentEntry), -1));
347
348 // get the headings name to display
349 aAny = xTarget->getPropertyValue("ActualOutlineName");
350 OUString sActualOutlineName;
351 aAny >>= sActualOutlineName;
352
353 // get the headings outline level
354 aAny = xTarget->getPropertyValue("OutlineLevel");
355 sal_Int32 nOutlineLevel = *o3tl::doAccess<sal_Int32>(aAny);
356
357 // pop until the top of stack entry has an outline level less than
358 // the to be inserted heading outline level
359 while (nOutlineLevel <= aHeadingsParentEntryStack.top().second)
360 aHeadingsParentEntryStack.pop();
361
362 mxLbTree->insert(aHeadingsParentEntryStack.top().first.get(), -1,
363 &sActualOutlineName, &sId, nullptr, nullptr, false,
364 xEntry.get());
365
366 // push if the inserted entry is a child
367 if (nOutlineLevel > aHeadingsParentEntryStack.top().second)
368 aHeadingsParentEntryStack.push(
369 std::pair(mxLbTree->make_iterator(xEntry.get()), nOutlineLevel));
370 }
371 else
372 {
373 mxLbTree->insert(pParentEntry, -1, &aStrDisplayname, &sId, nullptr,
374 nullptr, false, xEntry.get());
375 }
376 }
377 else
378 {
379 mxLbTree->insert(pParentEntry, -1, &aStrDisplayname, &sId, nullptr, nullptr,
380 false, xEntry.get());
381 }
382
383 try
384 {
385 // get bitmap for the tree-entry
387 aXBitmap( xTarget->getPropertyValue( aProp_LinkDisplayBitmap ), uno::UNO_QUERY );
388 if (aXBitmap.is())
389 {
390 Graphic aBmp(Graphic(VCLUnoHelper::GetBitmap(aXBitmap)));
391 // insert Displayname into treelist with bitmaps
392 mxLbTree->set_image(*xEntry, aBmp.GetXGraphic(), -1);
393 }
394 }
395 catch(const css::uno::Exception&)
396 {
397 }
398
399 nEntries++;
400
402 if( xLTS.is() )
403 nEntries += FillTree( xLTS->getLinks(), xEntry.get() );
404 }
405 catch(const css::uno::Exception&)
406 {
407 }
408 }
409 }
410
411 return nEntries;
412}
413
414// Clear Tree
416{
417 std::unique_ptr<weld::TreeIter> xEntry = mxLbTree->make_iterator();
418 bool bEntry = mxLbTree->get_iter_first(*xEntry);
419
420 while (bEntry)
421 {
422 TargetData* pUserData = weld::fromId<TargetData*>(mxLbTree->get_id(*xEntry));
423 delete pUserData;
424
425 bEntry = mxLbTree->iter_next(*xEntry);
426 }
427
428 mxLbTree->clear();
429}
430
431// Find Entry for String
432std::unique_ptr<weld::TreeIter> SvxHlinkDlgMarkWnd::FindEntry (std::u16string_view aStrName)
433{
434 bool bFound=false;
435 std::unique_ptr<weld::TreeIter> xEntry = mxLbTree->make_iterator();
436 bool bEntry = mxLbTree->get_iter_first(*xEntry);
437
438 while (bEntry && !bFound)
439 {
440 TargetData* pUserData = weld::fromId<TargetData*>(mxLbTree->get_id(*xEntry));
441 if (aStrName == pUserData->aUStrLinkname)
442 bFound = true;
443 else
444 bEntry = mxLbTree->iter_next(*xEntry);
445 }
446
447 if (!bFound)
448 xEntry.reset();
449
450 return xEntry;
451}
452
453// Select Entry
454bool SvxHlinkDlgMarkWnd::SelectEntry(std::u16string_view aStrMark)
455{
456 std::unique_ptr<weld::TreeIter> xEntry = FindEntry(aStrMark);
457 if (!xEntry)
458 return false;
459 mxLbTree->set_cursor(*xEntry);
460 return true;
461}
462
463// Click on Apply-Button / Double-click on item in tree
464IMPL_LINK_NOARG(SvxHlinkDlgMarkWnd, DoubleClickApplyHdl_Impl, weld::TreeView&, bool)
465{
466 ClickApplyHdl_Impl(*mxBtApply);
467 return true;
468}
469
471{
472 std::unique_ptr<weld::TreeIter> xEntry(mxLbTree->make_iterator());
473 bool bEntry = mxLbTree->get_cursor(xEntry.get());
474 if (bEntry)
475 {
476 TargetData* pData = weld::fromId<TargetData*>(mxLbTree->get_id(*xEntry));
477 if (pData->bIsTarget)
478 {
479 mpParent->SetMarkStr(pData->aUStrLinkname);
480 }
481 }
482}
483
484// Click on Close-Button
486{
487 std::unique_ptr<weld::TreeIter> xEntry(mxLbTree->make_iterator());
488 bool bEntry = mxLbTree->get_cursor(xEntry.get());
489 if (bEntry)
490 {
491 TargetData* pUserData = weld::fromId<TargetData*>(mxLbTree->get_id(*xEntry));
492 OUString sLastSelectedMark = pUserData->aUStrLinkname;
493
494 std::deque<OUString> aLastSelectedPath;
495 //If the bottommost entry is expanded but nothing
496 //underneath it is selected leave a dummy entry
497 if (mxLbTree->get_row_expanded(*xEntry))
498 aLastSelectedPath.push_front(OUString());
499 while (bEntry)
500 {
501 aLastSelectedPath.push_front(mxLbTree->get_text(*xEntry));
502 bEntry = mxLbTree->iter_parent(*xEntry);
503 }
504
506 {
507 { TG_SETTING_LASTMARK, css::uno::Any(sLastSelectedMark) },
508 { TG_SETTING_LASTPATH, css::uno::Any(comphelper::containerToSequence(aLastSelectedPath)) }
509 };
510
511 // write
512 SvtViewOptions aViewSettings( EViewType::Dialog, TG_SETTING_MANAGER );
513 aViewSettings.SetUserData( aSettings );
514 }
515
516 m_xDialog->response(RET_CANCEL);
517}
518
519/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Reference< XExecutableDialog > m_xDialog
css::uno::Reference< css::graphic::XGraphic > GetXGraphic() const
constexpr tools::Long Y() const
constexpr tools::Long X() const
css::uno::Any GetUserItem(const OUString &sName) const
void SetUserData(const css::uno::Sequence< css::beans::NamedValue > &lData)
bool Exists() const
void RestoreLastSelection()
Definition: hlmarkwn.cxx:166
bool RefreshFromDoc(const OUString &aURL)
Definition: hlmarkwn.cxx:229
std::unique_ptr< weld::Label > mxError
Definition: hlmarkwn.hxx:40
std::unique_ptr< weld::Button > mxBtClose
Definition: hlmarkwn.hxx:38
int FillTree(const css::uno::Reference< css::container::XNameAccess > &xLinks, const weld::TreeIter *pParentEntry=nullptr)
Definition: hlmarkwn.cxx:286
SvxHlinkDlgMarkWnd(weld::Window *pParentDialog, SvxHyperlinkTabPageBase *pParentPage)
Definition: hlmarkwn.cxx:68
std::unique_ptr< weld::TreeIter > FindEntry(std::u16string_view aStrName)
Definition: hlmarkwn.cxx:432
void RefreshTree(const OUString &aStrURL)
Definition: hlmarkwn.cxx:200
bool SelectEntry(std::u16string_view aStrMark)
Definition: hlmarkwn.cxx:454
std::unique_ptr< weld::Button > mxBtApply
Definition: hlmarkwn.hxx:37
virtual ~SvxHlinkDlgMarkWnd() override
Definition: hlmarkwn.cxx:84
void MoveTo(const Point &rNewPos)
Definition: hlmarkwn.cxx:127
std::unique_ptr< weld::TreeView > mxLbTree
Definition: hlmarkwn.hxx:39
sal_uInt16 mnError
Definition: hlmarkwn.hxx:35
sal_uInt16 SetError(sal_uInt16 nError)
Definition: hlmarkwn.cxx:113
Tabpage : Basisclass.
Definition: hltpbase.hxx:47
static BitmapEx GetBitmap(const css::uno::Reference< css::awt::XBitmap > &rxBitmap)
std::shared_ptr< weld::Dialog > m_xDialog
virtual void scroll_to_row(int row)=0
virtual void expand_row(const TreeIter &rIter)=0
virtual OUString get_text(int row, int col=-1) const=0
virtual bool iter_next_sibling(TreeIter &rIter) const=0
virtual void select(int pos)=0
virtual bool iter_children(TreeIter &rIter) const=0
OUString CuiResId(TranslateId aKey)
Definition: cuiresmgr.cxx:23
URL aURL
RegionData_Impl * mpParent
float u
Reference< XInterface > xTarget
IMPL_LINK_NOARG(SvxHlinkDlgMarkWnd, DoubleClickApplyHdl_Impl, weld::TreeView &, bool)
Definition: hlmarkwn.cxx:464
constexpr OUStringLiteral TG_SETTING_LASTMARK
Definition: hlmarkwn.cxx:163
constexpr OUStringLiteral TG_SETTING_LASTPATH
Definition: hlmarkwn.cxx:164
constexpr OUStringLiteral TG_SETTING_MANAGER
Definition: hlmarkwn.cxx:162
#define LERR_NOENTRIES
#define LERR_DOCNOTOPEN
#define LERR_NOERROR
sal_uInt16 nPos
std::unique_ptr< sal_Int32[]> pData
css::uno::Sequence< DstElementType > containerToSequence(const SrcType &i_Container)
css::beans::PropertyValue makePropertyValue(const OUString &rName, T &&rValue)
int i
OUString toId(const void *pValue)
OUString sId
RET_CANCEL