1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 <unotools/viewoptions.hxx>
22 #include <vcl/graph.hxx>
25 #include <comphelper/processfactory.hxx>
26 #include <comphelper/sequence.hxx>
27 #include <com/sun/star/awt/XBitmap.hpp>
28 #include <com/sun/star/frame/Desktop.hpp>
29 #include <com/sun/star/beans/NamedValue.hpp>
30 #include <com/sun/star/beans/PropertyValue.hpp>
31 #include <com/sun/star/document/XLinkTargetSupplier.hpp>
32 #include <com/sun/star/beans/XPropertySet.hpp>
33 #include <com/sun/star/io/IOException.hpp>
35 #include <toolkit/helper/vclunohelper.hxx>
37 #include <strings.hrc>
38 #include <hlmarkwn.hxx>
39 #include <hltpbase.hxx>
40 #include <hlmarkwn_def.hxx>
42 using namespace ::com::sun::star
;
44 // Userdata-struct for tree-entries
47 OUString aUStrLinkname
;
50 TargetData (const OUString
& aUStrLName
, bool bTarget
)
54 aUStrLinkname
= aUStrLName
;
58 //*** Window-Class ***
59 // Constructor / Destructor
60 SvxHlinkDlgMarkWnd::SvxHlinkDlgMarkWnd(weld::Window
* pParentDialog
, SvxHyperlinkTabPageBase
*pParentPage
)
61 : GenericDialogController(pParentDialog
, "cui/ui/hyperlinkmarkdialog.ui", "HyperlinkMark")
62 , mpParent(pParentPage
)
63 , mnError(LERR_NOERROR
)
64 , mxBtApply(m_xBuilder
->weld_button("ok"))
65 , mxBtClose(m_xBuilder
->weld_button("close"))
66 , mxLbTree(m_xBuilder
->weld_tree_view("TreeListBox"))
67 , mxError(m_xBuilder
->weld_label("error"))
69 mxLbTree
->set_size_request(mxLbTree
->get_approximate_digit_width() * 25,
70 mxLbTree
->get_height_rows(12));
71 mxBtApply
->connect_clicked( LINK ( this, SvxHlinkDlgMarkWnd
, ClickApplyHdl_Impl
) );
72 mxBtClose
->connect_clicked( LINK ( this, SvxHlinkDlgMarkWnd
, ClickCloseHdl_Impl
) );
73 mxLbTree
->connect_row_activated( LINK ( this, SvxHlinkDlgMarkWnd
, DoubleClickApplyHdl_Impl
) );
76 SvxHlinkDlgMarkWnd::~SvxHlinkDlgMarkWnd()
81 void SvxHlinkDlgMarkWnd::ErrorChanged()
83 if (mnError
== LERR_NOENTRIES
)
85 OUString aStrMessage
= CuiResId( RID_SVXSTR_HYPDLG_ERR_LERR_NOENTRIES
);
86 mxError
->set_label(aStrMessage
);
90 else if (mnError
== LERR_DOCNOTOPEN
)
92 OUString aStrMessage
= CuiResId( RID_SVXSTR_HYPDLG_ERR_LERR_DOCNOTOPEN
);
93 mxError
->set_label(aStrMessage
);
104 // Set an errorstatus
105 sal_uInt16
SvxHlinkDlgMarkWnd::SetError( sal_uInt16 nError
)
107 sal_uInt16 nOldError
= mnError
;
110 if( mnError
!= LERR_NOERROR
)
119 void SvxHlinkDlgMarkWnd::MoveTo(const Point
& rNewPos
)
121 m_xDialog
->window_move(rNewPos
.X(), rNewPos
.Y());
126 void SelectPath(weld::TreeIter
* pEntry
, weld::TreeView
& rLbTree
,
127 std::deque
<OUString
> &rLastSelectedPath
)
129 OUString
sTitle(rLastSelectedPath
.front());
130 rLastSelectedPath
.pop_front();
131 if (sTitle
.isEmpty())
135 if (sTitle
== rLbTree
.get_text(*pEntry
))
137 rLbTree
.select(*pEntry
);
138 rLbTree
.scroll_to_row(*pEntry
);
139 if (!rLastSelectedPath
.empty())
141 rLbTree
.expand_row(*pEntry
);
142 if (!rLbTree
.iter_children(*pEntry
))
144 SelectPath(pEntry
, rLbTree
, rLastSelectedPath
);
148 if (!rLbTree
.iter_next_sibling(*pEntry
))
154 #define TG_SETTING_MANAGER "TargetInDocument"
155 #define TG_SETTING_LASTMARK "LastSelectedMark"
156 #define TG_SETTING_LASTPATH "LastSelectedPath"
158 void SvxHlinkDlgMarkWnd::RestoreLastSelection()
160 bool bSelectedEntry
= false;
162 OUString sLastSelectedMark
;
163 std::deque
<OUString
> aLastSelectedPath
;
164 SvtViewOptions
aViewSettings( EViewType::Dialog
, TG_SETTING_MANAGER
);
165 if (aViewSettings
.Exists())
167 //Maybe we might want to have some sort of mru list and keep a mapping
168 //per document, rather than the current reuse of "the last thing
169 //selected, regardless of the document"
170 aViewSettings
.GetUserItem(TG_SETTING_LASTMARK
) >>= sLastSelectedMark
;
171 uno::Sequence
<OUString
> aTmp
;
172 aViewSettings
.GetUserItem(TG_SETTING_LASTPATH
) >>= aTmp
;
173 aLastSelectedPath
= comphelper::sequenceToContainer
< std::deque
<OUString
> >(aTmp
);
175 //fallback to previous entry selected the last time we executed this dialog.
176 //First see if the exact mark exists and re-use that
177 if (!sLastSelectedMark
.isEmpty())
178 bSelectedEntry
= SelectEntry(sLastSelectedMark
);
179 //Otherwise just select the closest path available
180 //now to what was available at dialog close time
181 if (!bSelectedEntry
&& !aLastSelectedPath
.empty())
183 std::deque
<OUString
> aTmpSelectedPath(aLastSelectedPath
);
184 std::unique_ptr
<weld::TreeIter
> xEntry(mxLbTree
->make_iterator());
185 if (!mxLbTree
->get_iter_first(*xEntry
))
187 SelectPath(xEntry
.get(), *mxLbTree
, aTmpSelectedPath
);
191 // Interface to refresh tree
192 void SvxHlinkDlgMarkWnd::RefreshTree (const OUString
& aStrURL
)
196 weld::WaitObject
aWait(m_xDialog
.get());
200 sal_Int32 nPos
= aStrURL
.indexOf('#');
205 if (!RefreshFromDoc(aUStrURL
))
208 bool bSelectedEntry
= false;
212 OUString aStrMark
= aStrURL
.copy(nPos
+1);
213 bSelectedEntry
= SelectEntry(aStrMark
);
217 RestoreLastSelection();
220 // get links from document
221 bool SvxHlinkDlgMarkWnd::RefreshFromDoc(const OUString
& aURL
)
223 mnError
= LERR_NOERROR
;
225 uno::Reference
< frame::XDesktop2
> xDesktop
= frame::Desktop::create( ::comphelper::getProcessComponentContext() );
226 uno::Reference
< lang::XComponent
> xComp
;
228 if( !aURL
.isEmpty() )
235 uno::Sequence
< beans::PropertyValue
> aArg(1);
236 aArg
.getArray()[0].Name
= "Hidden";
237 aArg
.getArray()[0].Value
<<= true;
238 xComp
= xDesktop
->loadComponentFromURL( aURL
, "_blank", 0, aArg
);
240 catch( const io::IOException
& )
244 catch( const lang::IllegalArgumentException
& )
252 // the component with user focus ( current document )
253 xComp
= xDesktop
->getCurrentComponent();
258 uno::Reference
< document::XLinkTargetSupplier
> xLTS( xComp
, uno::UNO_QUERY
);
262 if( FillTree( xLTS
->getLinks() ) == 0 )
263 mnError
= LERR_NOENTRIES
;
266 mnError
= LERR_DOCNOTOPEN
;
268 if ( !aURL
.isEmpty() )
273 if( !aURL
.isEmpty() )
274 mnError
=LERR_DOCNOTOPEN
;
280 int SvxHlinkDlgMarkWnd::FillTree( const uno::Reference
< container::XNameAccess
>& xLinks
, const weld::TreeIter
* pParentEntry
)
283 const uno::Sequence
< OUString
> aNames( xLinks
->getElementNames() );
284 const sal_uLong nLinks
= aNames
.getLength();
285 const OUString
* pNames
= aNames
.getConstArray();
287 const OUString
aProp_LinkDisplayName( "LinkDisplayName" );
288 const OUString
aProp_LinkTarget( "com.sun.star.document.LinkTarget" );
289 const OUString
aProp_LinkDisplayBitmap( "LinkDisplayBitmap" );
290 for( sal_uLong i
= 0; i
< nLinks
; i
++ )
293 OUString
aLink( *pNames
++ );
298 aAny
= xLinks
->getByName( aLink
);
300 catch(const uno::Exception
&)
302 // if the name of the target was invalid (like empty headings)
303 // no object can be provided
309 uno::Reference
< beans::XPropertySet
> xTarget
;
311 if( aAny
>>= xTarget
)
315 // get name to display
316 aAny
= xTarget
->getPropertyValue( aProp_LinkDisplayName
);
317 OUString aDisplayName
;
318 aAny
>>= aDisplayName
;
319 OUString
aStrDisplayname ( aDisplayName
);
322 uno::Reference
< lang::XServiceInfo
> xSI( xTarget
, uno::UNO_QUERY
);
323 bool bIsTarget
= xSI
->supportsService( aProp_LinkTarget
);
326 TargetData
*pData
= new TargetData ( aLink
, bIsTarget
);
327 OUString
sId(OUString::number(reinterpret_cast<sal_Int64
>(pData
)));
329 std::unique_ptr
<weld::TreeIter
> xEntry(mxLbTree
->make_iterator());
330 mxLbTree
->insert(pParentEntry
, -1, &aStrDisplayname
, &sId
, nullptr, nullptr, nullptr, false, xEntry
.get());
334 // get bitmap for the tree-entry
335 uno::Reference
< awt::XBitmap
>
336 aXBitmap( xTarget
->getPropertyValue( aProp_LinkDisplayBitmap
), uno::UNO_QUERY
);
339 Graphic
aBmp(Graphic(VCLUnoHelper::GetBitmap(aXBitmap
)));
340 // insert Displayname into treelist with bitmaps
341 mxLbTree
->set_image(*xEntry
, aBmp
.GetXGraphic(), -1);
344 catch(const css::uno::Exception
&)
350 uno::Reference
< document::XLinkTargetSupplier
> xLTS( xTarget
, uno::UNO_QUERY
);
352 nEntries
+= FillTree( xLTS
->getLinks(), xEntry
.get() );
354 catch(const css::uno::Exception
&)
364 void SvxHlinkDlgMarkWnd::ClearTree()
366 std::unique_ptr
<weld::TreeIter
> xEntry
= mxLbTree
->make_iterator();
367 bool bEntry
= mxLbTree
->get_iter_first(*xEntry
);
371 TargetData
* pUserData
= reinterpret_cast<TargetData
*>(mxLbTree
->get_id(*xEntry
).toInt64());
374 bEntry
= mxLbTree
->iter_next(*xEntry
);
380 // Find Entry for String
381 std::unique_ptr
<weld::TreeIter
> SvxHlinkDlgMarkWnd::FindEntry (const OUString
& aStrName
)
384 std::unique_ptr
<weld::TreeIter
> xEntry
= mxLbTree
->make_iterator();
385 bool bEntry
= mxLbTree
->get_iter_first(*xEntry
);
387 while (bEntry
&& !bFound
)
389 TargetData
* pUserData
= reinterpret_cast<TargetData
*>(mxLbTree
->get_id(*xEntry
).toInt64());
390 if (aStrName
== pUserData
->aUStrLinkname
)
393 bEntry
= mxLbTree
->iter_next(*xEntry
);
403 bool SvxHlinkDlgMarkWnd::SelectEntry(const OUString
& aStrMark
)
405 std::unique_ptr
<weld::TreeIter
> xEntry
= FindEntry(aStrMark
);
408 mxLbTree
->select(*xEntry
);
409 mxLbTree
->scroll_to_row(*xEntry
);
413 // Click on Apply-Button / Double-click on item in tree
414 IMPL_LINK_NOARG(SvxHlinkDlgMarkWnd
, DoubleClickApplyHdl_Impl
, weld::TreeView
&, bool)
416 ClickApplyHdl_Impl(*mxBtApply
);
420 IMPL_LINK_NOARG(SvxHlinkDlgMarkWnd
, ClickApplyHdl_Impl
, weld::Button
&, void)
422 std::unique_ptr
<weld::TreeIter
> xEntry(mxLbTree
->make_iterator());
423 bool bEntry
= mxLbTree
->get_cursor(xEntry
.get());
426 TargetData
* pData
= reinterpret_cast<TargetData
*>(mxLbTree
->get_id(*xEntry
).toInt64());
427 if (pData
->bIsTarget
)
429 mpParent
->SetMarkStr(pData
->aUStrLinkname
);
434 // Click on Close-Button
435 IMPL_LINK_NOARG(SvxHlinkDlgMarkWnd
, ClickCloseHdl_Impl
, weld::Button
&, void)
437 std::unique_ptr
<weld::TreeIter
> xEntry(mxLbTree
->make_iterator());
438 bool bEntry
= mxLbTree
->get_cursor(xEntry
.get());
441 TargetData
* pUserData
= reinterpret_cast<TargetData
*>(mxLbTree
->get_id(*xEntry
).toInt64());
442 OUString sLastSelectedMark
= pUserData
->aUStrLinkname
;
444 std::deque
<OUString
> aLastSelectedPath
;
445 //If the bottommost entry is expanded but nothing
446 //underneath it is selected leave a dummy entry
447 if (mxLbTree
->get_row_expanded(*xEntry
))
448 aLastSelectedPath
.push_front(OUString());
451 aLastSelectedPath
.push_front(mxLbTree
->get_text(*xEntry
));
452 bEntry
= mxLbTree
->iter_parent(*xEntry
);
455 uno::Sequence
< beans::NamedValue
> aSettings
457 { TG_SETTING_LASTMARK
, css::uno::Any(sLastSelectedMark
) },
458 { TG_SETTING_LASTPATH
, css::uno::Any(comphelper::containerToSequence(aLastSelectedPath
)) }
462 SvtViewOptions
aViewSettings( EViewType::Dialog
, TG_SETTING_MANAGER
);
463 aViewSettings
.SetUserData( aSettings
);
466 m_xDialog
->response(RET_CANCEL
);
469 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */