bump product version to 6.4.0.3
[LibreOffice.git] / cui / source / dialogs / hlmarkwn.cxx
blob08d1798b42e541452ec85ef06eae6045b177394f
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 <unotools/viewoptions.hxx>
22 #include <vcl/graph.hxx>
24 // UNO-Stuff
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
45 struct TargetData
47 OUString aUStrLinkname;
48 bool bIsTarget;
50 TargetData (const OUString& aUStrLName, bool bTarget)
51 : bIsTarget(bTarget)
53 if (bIsTarget)
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()
78 ClearTree();
81 void SvxHlinkDlgMarkWnd::ErrorChanged()
83 if (mnError == LERR_NOENTRIES)
85 OUString aStrMessage = CuiResId( RID_SVXSTR_HYPDLG_ERR_LERR_NOENTRIES );
86 mxError->set_label(aStrMessage);
87 mxError->show();
88 mxLbTree->hide();
90 else if (mnError == LERR_DOCNOTOPEN)
92 OUString aStrMessage = CuiResId( RID_SVXSTR_HYPDLG_ERR_LERR_DOCNOTOPEN );
93 mxError->set_label(aStrMessage);
94 mxError->show();
95 mxLbTree->hide();
97 else
99 mxLbTree->show();
100 mxError->hide();
104 // Set an errorstatus
105 sal_uInt16 SvxHlinkDlgMarkWnd::SetError( sal_uInt16 nError)
107 sal_uInt16 nOldError = mnError;
108 mnError = nError;
110 if( mnError != LERR_NOERROR )
111 ClearTree();
113 ErrorChanged();
115 return nOldError;
118 // Move window
119 void SvxHlinkDlgMarkWnd::MoveTo(const Point& rNewPos)
121 m_xDialog->window_move(rNewPos.X(), rNewPos.Y());
124 namespace
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())
132 return;
133 while (pEntry)
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))
143 pEntry = nullptr;
144 SelectPath(pEntry, rLbTree, rLastSelectedPath);
146 break;
148 if (!rLbTree.iter_next_sibling(*pEntry))
149 pEntry = nullptr;
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))
186 xEntry.reset();
187 SelectPath(xEntry.get(), *mxLbTree, aTmpSelectedPath);
191 // Interface to refresh tree
192 void SvxHlinkDlgMarkWnd::RefreshTree (const OUString& aStrURL)
194 OUString aUStrURL;
196 weld::WaitObject aWait(m_xDialog.get());
198 ClearTree();
200 sal_Int32 nPos = aStrURL.indexOf('#');
202 if (nPos != 0)
203 aUStrURL = aStrURL;
205 if (!RefreshFromDoc(aUStrURL))
206 ErrorChanged();
208 bool bSelectedEntry = false;
210 if ( nPos != -1 )
212 OUString aStrMark = aStrURL.copy(nPos+1);
213 bSelectedEntry = SelectEntry(aStrMark);
216 if (!bSelectedEntry)
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() )
230 // load from url
231 if( xDesktop.is() )
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& )
250 else
252 // the component with user focus ( current document )
253 xComp = xDesktop->getCurrentComponent();
256 if( xComp.is() )
258 uno::Reference< document::XLinkTargetSupplier > xLTS( xComp, uno::UNO_QUERY );
260 if( xLTS.is() )
262 if( FillTree( xLTS->getLinks() ) == 0 )
263 mnError = LERR_NOENTRIES;
265 else
266 mnError = LERR_DOCNOTOPEN;
268 if ( !aURL.isEmpty() )
269 xComp->dispose();
271 else
273 if( !aURL.isEmpty() )
274 mnError=LERR_DOCNOTOPEN;
276 return (mnError==0);
279 // Fill Tree-Control
280 int SvxHlinkDlgMarkWnd::FillTree( const uno::Reference< container::XNameAccess >& xLinks, const weld::TreeIter* pParentEntry )
282 int nEntries=0;
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++ )
292 uno::Any aAny;
293 OUString aLink( *pNames++ );
295 bool bError = false;
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
304 bError = true;
306 if(bError)
307 continue;
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 );
321 // is it a target ?
322 uno::Reference< lang::XServiceInfo > xSI( xTarget, uno::UNO_QUERY );
323 bool bIsTarget = xSI->supportsService( aProp_LinkTarget );
325 // create userdata
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 );
337 if (aXBitmap.is())
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&)
348 nEntries++;
350 uno::Reference< document::XLinkTargetSupplier > xLTS( xTarget, uno::UNO_QUERY );
351 if( xLTS.is() )
352 nEntries += FillTree( xLTS->getLinks(), xEntry.get() );
354 catch(const css::uno::Exception&)
360 return nEntries;
363 // Clear Tree
364 void SvxHlinkDlgMarkWnd::ClearTree()
366 std::unique_ptr<weld::TreeIter> xEntry = mxLbTree->make_iterator();
367 bool bEntry = mxLbTree->get_iter_first(*xEntry);
369 while (bEntry)
371 TargetData* pUserData = reinterpret_cast<TargetData*>(mxLbTree->get_id(*xEntry).toInt64());
372 delete pUserData;
374 bEntry = mxLbTree->iter_next(*xEntry);
377 mxLbTree->clear();
380 // Find Entry for String
381 std::unique_ptr<weld::TreeIter> SvxHlinkDlgMarkWnd::FindEntry (const OUString& aStrName)
383 bool bFound=false;
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)
391 bFound = true;
392 else
393 bEntry = mxLbTree->iter_next(*xEntry);
396 if (!bFound)
397 xEntry.reset();
399 return xEntry;
402 // Select Entry
403 bool SvxHlinkDlgMarkWnd::SelectEntry(const OUString& aStrMark)
405 std::unique_ptr<weld::TreeIter> xEntry = FindEntry(aStrMark);
406 if (!xEntry)
407 return false;
408 mxLbTree->select(*xEntry);
409 mxLbTree->scroll_to_row(*xEntry);
410 return true;
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);
417 return true;
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());
424 if (bEntry)
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());
439 if (bEntry)
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());
449 while (bEntry)
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)) }
461 // write
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: */