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 <sfx2/docfile.hxx>
22 #include <unotools/viewoptions.hxx>
23 #include <vcl/svapp.hxx>
24 #include <vcl/settings.hxx>
25 #include <vcl/wrkwin.hxx>
26 #include <vcl/builderfactory.hxx>
29 #include <comphelper/processfactory.hxx>
30 #include <comphelper/sequence.hxx>
31 #include <com/sun/star/awt/XBitmap.hpp>
32 #include <com/sun/star/frame/Desktop.hpp>
33 #include <com/sun/star/frame/XComponentLoader.hpp>
34 #include <com/sun/star/beans/NamedValue.hpp>
35 #include <com/sun/star/beans/PropertyValue.hpp>
36 #include <com/sun/star/document/XLinkTargetSupplier.hpp>
37 #include <com/sun/star/beans/XPropertySet.hpp>
38 #include <com/sun/star/io/IOException.hpp>
40 #include <toolkit/helper/vclunohelper.hxx>
41 #include <vcl/treelistentry.hxx>
43 #include <strings.hrc>
44 #include <hlmarkwn.hxx>
45 #include <hltpbase.hxx>
47 using namespace ::com::sun::star
;
49 // Userdata-struct for tree-entries
52 OUString aUStrLinkname
;
55 TargetData (const OUString
& aUStrLName
, bool bTarget
)
59 aUStrLinkname
= aUStrLName
;
64 SvxHlmarkTreeLBox::SvxHlmarkTreeLBox(vcl::Window
* pParent
, WinBits nStyle
)
65 : SvTreeListBox(pParent
, nStyle
)
66 , mpParentWnd(nullptr)
68 SetNodeDefaultImages();
71 SvxHlmarkTreeLBox::~SvxHlmarkTreeLBox()
76 void SvxHlmarkTreeLBox::dispose()
79 SvTreeListBox::dispose();
82 VCL_BUILDER_FACTORY_CONSTRUCTOR(SvxHlmarkTreeLBox
, WB_TABSTOP
)
84 Size
SvxHlmarkTreeLBox::GetOptimalSize() const
86 return LogicToPixel(Size(103, 162), MapMode(MapUnit::MapAppFont
));
89 void SvxHlmarkTreeLBox::Paint(vcl::RenderContext
& rRenderContext
, const ::tools::Rectangle
& rRect
)
91 if (!mpParentWnd
|| mpParentWnd
->mnError
== LERR_NOERROR
)
93 SvTreeListBox::Paint(rRenderContext
, rRect
);
97 Erase(rRenderContext
);
99 ::tools::Rectangle
aDrawRect(Point( 0, 0 ), GetSizePixel());
101 OUString aStrMessage
;
103 switch (mpParentWnd
->mnError
)
105 case LERR_NOENTRIES
:
106 aStrMessage
= CuiResId( RID_SVXSTR_HYPDLG_ERR_LERR_NOENTRIES
);
108 case LERR_DOCNOTOPEN
:
109 aStrMessage
= CuiResId( RID_SVXSTR_HYPDLG_ERR_LERR_DOCNOTOPEN
);
113 rRenderContext
.DrawText(aDrawRect
, aStrMessage
, DrawTextFlags::Left
114 | DrawTextFlags::MultiLine
| DrawTextFlags::WordBreak
);
119 //*** Window-Class ***
120 // Constructor / Destructor
121 SvxHlinkDlgMarkWnd::SvxHlinkDlgMarkWnd( SvxHyperlinkTabPageBase
*pParent
)
122 : FloatingWindow(pParent
, "HyperlinkMark", "cui/ui/hyperlinkmarkdialog.ui")
125 , mnError(LERR_NOERROR
)
127 get(mpBtApply
, "apply");
128 get(mpBtClose
, "close");
129 get(mpLbTree
, "TreeListBox");
130 mpLbTree
->SetParentWnd(this);
132 mpBtApply
->SetClickHdl ( LINK ( this, SvxHlinkDlgMarkWnd
, ClickApplyHdl_Impl
) );
133 mpBtClose
->SetClickHdl ( LINK ( this, SvxHlinkDlgMarkWnd
, ClickCloseHdl_Impl
) );
134 mpLbTree
->SetDoubleClickHdl ( LINK ( this, SvxHlinkDlgMarkWnd
, DoubleClickApplyHdl_Impl
) );
136 // add lines to the Tree-ListBox
137 mpLbTree
->SetStyle( mpLbTree
->GetStyle() | WB_TABSTOP
| WB_BORDER
| WB_HASLINES
|
138 WB_HASBUTTONS
| //WB_HASLINESATROOT |
139 WB_HSCROLL
| WB_HASBUTTONSATROOT
);
142 SvxHlinkDlgMarkWnd::~SvxHlinkDlgMarkWnd()
147 void SvxHlinkDlgMarkWnd::dispose()
154 FloatingWindow::dispose();
157 // Set an errorstatus
158 sal_uInt16
SvxHlinkDlgMarkWnd::SetError( sal_uInt16 nError
)
160 sal_uInt16 nOldError
= mnError
;
163 if( mnError
!= LERR_NOERROR
)
166 mpLbTree
->Invalidate();
172 bool SvxHlinkDlgMarkWnd::MoveTo ( Point aNewPos
)
176 bool bOldStatus
= mbUserMoved
;
177 SetPosPixel ( aNewPos
);
178 mbUserMoved
= bOldStatus
;
184 void SvxHlinkDlgMarkWnd::Move ()
188 if ( IsReallyVisible() )
192 bool SvxHlinkDlgMarkWnd::ConnectToDialog()
194 bool bOldStatus
= mbUserMoved
;
203 void SelectPath(SvTreeListEntry
*pEntry
, SvxHlmarkTreeLBox
&rLbTree
,
204 std::deque
<OUString
> &rLastSelectedPath
)
206 OUString
sTitle(rLastSelectedPath
.front());
207 rLastSelectedPath
.pop_front();
208 if (sTitle
.isEmpty())
212 if (sTitle
== rLbTree
.GetEntryText(pEntry
))
214 rLbTree
.Select(pEntry
);
215 rLbTree
.MakeVisible(pEntry
);
216 if (!rLastSelectedPath
.empty())
218 rLbTree
.Expand(pEntry
);
219 SelectPath(rLbTree
.FirstChild(pEntry
), rLbTree
, rLastSelectedPath
);
223 pEntry
= pEntry
->NextSibling();
228 #define TG_SETTING_MANAGER "TargetInDocument"
229 #define TG_SETTING_LASTMARK "LastSelectedMark"
230 #define TG_SETTING_LASTPATH "LastSelectedPath"
232 void SvxHlinkDlgMarkWnd::RestoreLastSelection()
234 bool bSelectedEntry
= false;
236 OUString sLastSelectedMark
;
237 std::deque
<OUString
> aLastSelectedPath
;
238 SvtViewOptions
aViewSettings( EViewType::Dialog
, TG_SETTING_MANAGER
);
239 if (aViewSettings
.Exists())
241 //Maybe we might want to have some sort of mru list and keep a mapping
242 //per document, rather than the current reuse of "the last thing
243 //selected, regardless of the document"
244 aViewSettings
.GetUserItem(TG_SETTING_LASTMARK
) >>= sLastSelectedMark
;
245 uno::Sequence
<OUString
> aTmp
;
246 aViewSettings
.GetUserItem(TG_SETTING_LASTPATH
) >>= aTmp
;
247 aLastSelectedPath
= comphelper::sequenceToContainer
< std::deque
<OUString
> >(aTmp
);
249 //fallback to previous entry selected the last time we executed this dialog.
250 //First see if the exact mark exists and re-use that
251 if (!sLastSelectedMark
.isEmpty())
252 bSelectedEntry
= SelectEntry(sLastSelectedMark
);
253 //Otherwise just select the closest path available
254 //now to what was available at dialog close time
255 if (!bSelectedEntry
&& !aLastSelectedPath
.empty())
257 std::deque
<OUString
> aTmpSelectedPath(aLastSelectedPath
);
258 SelectPath(mpLbTree
->First(), *mpLbTree
, aTmpSelectedPath
);
262 // Interface to refresh tree
263 void SvxHlinkDlgMarkWnd::RefreshTree (const OUString
& aStrURL
)
271 sal_Int32 nPos
= aStrURL
.indexOf('#');
276 if (!RefreshFromDoc(aUStrURL
))
277 mpLbTree
->Invalidate();
279 bool bSelectedEntry
= false;
283 OUString aStrMark
= aStrURL
.copy(nPos
+1);
284 bSelectedEntry
= SelectEntry(aStrMark
);
288 RestoreLastSelection();
293 // get links from document
294 bool SvxHlinkDlgMarkWnd::RefreshFromDoc(const OUString
& aURL
)
296 mnError
= LERR_NOERROR
;
298 uno::Reference
< frame::XDesktop2
> xDesktop
= frame::Desktop::create( ::comphelper::getProcessComponentContext() );
299 uno::Reference
< lang::XComponent
> xComp
;
301 if( !aURL
.isEmpty() )
304 uno::Reference
< frame::XComponentLoader
> xLoader( xDesktop
, uno::UNO_QUERY
);
309 uno::Sequence
< beans::PropertyValue
> aArg(1);
310 aArg
.getArray()[0].Name
= "Hidden";
311 aArg
.getArray()[0].Value
<<= true;
312 xComp
= xLoader
->loadComponentFromURL( aURL
, "_blank", 0, aArg
);
314 catch( const io::IOException
& )
318 catch( const lang::IllegalArgumentException
& )
326 // the component with user focus ( current document )
327 xComp
= xDesktop
->getCurrentComponent();
332 uno::Reference
< document::XLinkTargetSupplier
> xLTS( xComp
, uno::UNO_QUERY
);
336 if( FillTree( xLTS
->getLinks() ) == 0 )
337 mnError
= LERR_NOENTRIES
;
340 mnError
= LERR_DOCNOTOPEN
;
342 if ( !aURL
.isEmpty() )
347 if( !aURL
.isEmpty() )
348 mnError
=LERR_DOCNOTOPEN
;
354 int SvxHlinkDlgMarkWnd::FillTree( const uno::Reference
< container::XNameAccess
>& xLinks
, SvTreeListEntry
* pParentEntry
)
357 const uno::Sequence
< OUString
> aNames( xLinks
->getElementNames() );
358 const sal_uLong nLinks
= aNames
.getLength();
359 const OUString
* pNames
= aNames
.getConstArray();
361 const OUString
aProp_LinkDisplayName( "LinkDisplayName" );
362 const OUString
aProp_LinkTarget( "com.sun.star.document.LinkTarget" );
363 const OUString
aProp_LinkDisplayBitmap( "LinkDisplayBitmap" );
364 for( sal_uLong i
= 0; i
< nLinks
; i
++ )
367 OUString
aLink( *pNames
++ );
372 aAny
= xLinks
->getByName( aLink
);
374 catch(const uno::Exception
&)
376 // if the name of the target was invalid (like empty headings)
377 // no object can be provided
383 uno::Reference
< beans::XPropertySet
> xTarget
;
385 if( aAny
>>= xTarget
)
389 // get name to display
390 aAny
= xTarget
->getPropertyValue( aProp_LinkDisplayName
);
391 OUString aDisplayName
;
392 aAny
>>= aDisplayName
;
393 OUString
aStrDisplayname ( aDisplayName
);
396 uno::Reference
< lang::XServiceInfo
> xSI( xTarget
, uno::UNO_QUERY
);
397 bool bIsTarget
= xSI
->supportsService( aProp_LinkTarget
);
400 TargetData
*pData
= new TargetData ( aLink
, bIsTarget
);
402 SvTreeListEntry
* pEntry
;
406 // get bitmap for the tree-entry
407 uno::Reference
< awt::XBitmap
>
408 aXBitmap( xTarget
->getPropertyValue( aProp_LinkDisplayBitmap
), uno::UNO_QUERY
);
411 Image
aBmp(BitmapEx(VCLUnoHelper::GetBitmap(aXBitmap
).GetBitmap(), /*mask*/COL_LIGHTMAGENTA
));
412 // insert Displayname into treelist with bitmaps
413 pEntry
= mpLbTree
->InsertEntry ( aStrDisplayname
,
416 false, TREELIST_APPEND
,
417 static_cast<void*>(pData
) );
422 // insert Displayname into treelist without bitmaps
423 pEntry
= mpLbTree
->InsertEntry ( aStrDisplayname
,
425 false, TREELIST_APPEND
,
426 static_cast<void*>(pData
) );
430 catch(const css::uno::Exception
&)
432 // insert Displayname into treelist without bitmaps
433 pEntry
= mpLbTree
->InsertEntry ( aStrDisplayname
,
435 false, TREELIST_APPEND
,
436 static_cast<void*>(pData
) );
440 uno::Reference
< document::XLinkTargetSupplier
> xLTS( xTarget
, uno::UNO_QUERY
);
442 nEntries
+= FillTree( xLTS
->getLinks(), pEntry
);
444 catch(const css::uno::Exception
&)
454 void SvxHlinkDlgMarkWnd::ClearTree()
456 SvTreeListEntry
* pEntry
= mpLbTree
->First();
460 TargetData
* pUserData
= static_cast<TargetData
*>(pEntry
->GetUserData());
463 pEntry
= mpLbTree
->Next( pEntry
);
469 // Find Entry for String
470 SvTreeListEntry
* SvxHlinkDlgMarkWnd::FindEntry (const OUString
& aStrName
)
473 SvTreeListEntry
* pEntry
= mpLbTree
->First();
475 while ( pEntry
&& !bFound
)
477 TargetData
* pUserData
= static_cast<TargetData
*>(pEntry
->GetUserData ());
478 if (aStrName
== pUserData
->aUStrLinkname
)
481 pEntry
= mpLbTree
->Next( pEntry
);
488 bool SvxHlinkDlgMarkWnd::SelectEntry(const OUString
& aStrMark
)
490 SvTreeListEntry
* pEntry
= FindEntry(aStrMark
);
493 mpLbTree
->Select(pEntry
);
494 mpLbTree
->MakeVisible (pEntry
);
498 // Click on Apply-Button / Double-click on item in tree
499 IMPL_LINK_NOARG(SvxHlinkDlgMarkWnd
, DoubleClickApplyHdl_Impl
, SvTreeListBox
*, bool)
501 ClickApplyHdl_Impl(nullptr);
505 IMPL_LINK_NOARG(SvxHlinkDlgMarkWnd
, ClickApplyHdl_Impl
, Button
*, void)
507 SvTreeListEntry
* pEntry
= mpLbTree
->GetCurEntry();
511 TargetData
*pData
= static_cast<TargetData
*>(pEntry
->GetUserData());
513 if ( pData
->bIsTarget
)
515 mpParent
->SetMarkStr(pData
->aUStrLinkname
);
520 // Click on Close-Button
521 IMPL_LINK_NOARG(SvxHlinkDlgMarkWnd
, ClickCloseHdl_Impl
, Button
*, void)
523 SvTreeListEntry
* pEntry
= mpLbTree
->GetCurEntry();
526 TargetData
* pUserData
= static_cast<TargetData
*>(pEntry
->GetUserData());
527 OUString sLastSelectedMark
= pUserData
->aUStrLinkname
;
529 std::deque
<OUString
> aLastSelectedPath
;
532 //If the bottommost entry is expanded but nothing
533 //underneath it is selected leave a dummy entry
534 if (mpLbTree
->IsExpanded(pEntry
))
535 aLastSelectedPath
.push_front(OUString());
538 aLastSelectedPath
.push_front(mpLbTree
->GetEntryText(pEntry
));
539 pEntry
= mpLbTree
->GetParent(pEntry
);
543 uno::Sequence
< beans::NamedValue
> aSettings
545 { TG_SETTING_LASTMARK
, css::uno::Any(sLastSelectedMark
) },
546 { TG_SETTING_LASTPATH
, css::uno::Any(comphelper::containerToSequence(aLastSelectedPath
)) }
550 SvtViewOptions
aViewSettings( EViewType::Dialog
, TG_SETTING_MANAGER
);
551 aViewSettings
.SetUserData( aSettings
);
557 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */