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 <unotools/viewoptions.hxx>
22 #include <vcl/graph.hxx>
23 
24 // UNO-Stuff
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>
34 
36 
37 #include <strings.hrc>
38 #include <hlmarkwn.hxx>
39 #include <hltpbase.hxx>
40 #include <hlmarkwn_def.hxx>
41 
42 using namespace ::com::sun::star;
43 
44 // Userdata-struct for tree-entries
45 struct TargetData
46 {
47  OUString aUStrLinkname;
48  bool bIsTarget;
49 
50  TargetData (const OUString& aUStrLName, bool bTarget)
51  : bIsTarget(bTarget)
52  {
53  if (bIsTarget)
54  aUStrLinkname = aUStrLName;
55  }
56 };
57 
58 //*** Window-Class ***
59 // Constructor / Destructor
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"))
68 {
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 ) );
74 }
75 
77 {
78  ClearTree();
79 }
80 
82 {
83  if (mnError == LERR_NOENTRIES)
84  {
85  OUString aStrMessage = CuiResId( RID_SVXSTR_HYPDLG_ERR_LERR_NOENTRIES );
86  mxError->set_label(aStrMessage);
87  mxError->show();
88  mxLbTree->hide();
89  }
90  else if (mnError == LERR_DOCNOTOPEN)
91  {
92  OUString aStrMessage = CuiResId( RID_SVXSTR_HYPDLG_ERR_LERR_DOCNOTOPEN );
93  mxError->set_label(aStrMessage);
94  mxError->show();
95  mxLbTree->hide();
96  }
97  else
98  {
99  mxLbTree->show();
100  mxError->hide();
101  }
102 }
103 
104 // Set an errorstatus
105 sal_uInt16 SvxHlinkDlgMarkWnd::SetError( sal_uInt16 nError)
106 {
107  sal_uInt16 nOldError = mnError;
108  mnError = nError;
109 
110  if( mnError != LERR_NOERROR )
111  ClearTree();
112 
113  ErrorChanged();
114 
115  return nOldError;
116 }
117 
118 // Move window
119 void SvxHlinkDlgMarkWnd::MoveTo(const Point& rNewPos)
120 {
121  m_xDialog->window_move(rNewPos.X(), rNewPos.Y());
122 }
123 
124 namespace
125 {
126  void SelectPath(weld::TreeIter* pEntry, weld::TreeView& rLbTree,
127  std::deque<OUString> &rLastSelectedPath)
128  {
129  OUString sTitle(rLastSelectedPath.front());
130  rLastSelectedPath.pop_front();
131  if (sTitle.isEmpty())
132  return;
133  while (pEntry)
134  {
135  if (sTitle == rLbTree.get_text(*pEntry))
136  {
137  rLbTree.select(*pEntry);
138  rLbTree.scroll_to_row(*pEntry);
139  if (!rLastSelectedPath.empty())
140  {
141  rLbTree.expand_row(*pEntry);
142  if (!rLbTree.iter_children(*pEntry))
143  pEntry = nullptr;
144  SelectPath(pEntry, rLbTree, rLastSelectedPath);
145  }
146  break;
147  }
148  if (!rLbTree.iter_next_sibling(*pEntry))
149  pEntry = nullptr;
150  }
151  }
152 }
153 
154 #define TG_SETTING_MANAGER "TargetInDocument"
155 #define TG_SETTING_LASTMARK "LastSelectedMark"
156 #define TG_SETTING_LASTPATH "LastSelectedPath"
157 
159 {
160  bool bSelectedEntry = false;
161 
162  OUString sLastSelectedMark;
163  std::deque<OUString> aLastSelectedPath;
164  SvtViewOptions aViewSettings( EViewType::Dialog, TG_SETTING_MANAGER );
165  if (aViewSettings.Exists())
166  {
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);
174  }
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())
182  {
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);
188  }
189 }
190 
191 // Interface to refresh tree
192 void SvxHlinkDlgMarkWnd::RefreshTree (const OUString& aStrURL)
193 {
194  OUString aUStrURL;
195 
196  weld::WaitObject aWait(m_xDialog.get());
197 
198  ClearTree();
199 
200  sal_Int32 nPos = aStrURL.indexOf('#');
201 
202  if (nPos != 0)
203  aUStrURL = aStrURL;
204 
205  if (!RefreshFromDoc(aUStrURL))
206  ErrorChanged();
207 
208  bool bSelectedEntry = false;
209 
210  if ( nPos != -1 )
211  {
212  OUString aStrMark = aStrURL.copy(nPos+1);
213  bSelectedEntry = SelectEntry(aStrMark);
214  }
215 
216  if (!bSelectedEntry)
218 }
219 
220 // get links from document
221 bool SvxHlinkDlgMarkWnd::RefreshFromDoc(const OUString& aURL)
222 {
224 
225  uno::Reference< frame::XDesktop2 > xDesktop = frame::Desktop::create( ::comphelper::getProcessComponentContext() );
226  uno::Reference< lang::XComponent > xComp;
227 
228  if( !aURL.isEmpty() )
229  {
230  // load from url
231  if( xDesktop.is() )
232  {
233  try
234  {
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 );
239  }
240  catch( const io::IOException& )
241  {
242 
243  }
244  catch( const lang::IllegalArgumentException& )
245  {
246 
247  }
248  }
249  }
250  else
251  {
252  // the component with user focus ( current document )
253  xComp = xDesktop->getCurrentComponent();
254  }
255 
256  if( xComp.is() )
257  {
258  uno::Reference< document::XLinkTargetSupplier > xLTS( xComp, uno::UNO_QUERY );
259 
260  if( xLTS.is() )
261  {
262  if( FillTree( xLTS->getLinks() ) == 0 )
264  }
265  else
267 
268  if ( !aURL.isEmpty() )
269  xComp->dispose();
270  }
271  else
272  {
273  if( !aURL.isEmpty() )
275  }
276  return (mnError==0);
277 }
278 
279 // Fill Tree-Control
280 int SvxHlinkDlgMarkWnd::FillTree( const uno::Reference< container::XNameAccess >& xLinks, weld::TreeIter* pParentEntry )
281 {
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();
286 
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++ )
291  {
292  uno::Any aAny;
293  OUString aLink( *pNames++ );
294 
295  bool bError = false;
296  try
297  {
298  aAny = xLinks->getByName( aLink );
299  }
300  catch(const uno::Exception&)
301  {
302  // if the name of the target was invalid (like empty headings)
303  // no object can be provided
304  bError = true;
305  }
306  if(bError)
307  continue;
308 
309  uno::Reference< beans::XPropertySet > xTarget;
310 
311  if( aAny >>= xTarget )
312  {
313  try
314  {
315  // get name to display
316  aAny = xTarget->getPropertyValue( aProp_LinkDisplayName );
317  OUString aDisplayName;
318  aAny >>= aDisplayName;
319  OUString aStrDisplayname ( aDisplayName );
320 
321  // is it a target ?
322  uno::Reference< lang::XServiceInfo > xSI( xTarget, uno::UNO_QUERY );
323  bool bIsTarget = xSI->supportsService( aProp_LinkTarget );
324 
325  // create userdata
326  TargetData *pData = new TargetData ( aLink, bIsTarget );
327  OUString sId(OUString::number(reinterpret_cast<sal_Int64>(pData)));
328 
329  std::unique_ptr<weld::TreeIter> xEntry(mxLbTree->make_iterator());
330  mxLbTree->insert(pParentEntry, -1, &aStrDisplayname, &sId, nullptr, nullptr, nullptr, false, xEntry.get());
331 
332  try
333  {
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())
338  {
339  Graphic aBmp(Graphic(VCLUnoHelper::GetBitmap(aXBitmap)));
340  // insert Displayname into treelist with bitmaps
341  mxLbTree->set_image(*xEntry, aBmp.GetXGraphic(), -1);
342  }
343  }
344  catch(const css::uno::Exception&)
345  {
346  }
347 
348  nEntries++;
349 
350  uno::Reference< document::XLinkTargetSupplier > xLTS( xTarget, uno::UNO_QUERY );
351  if( xLTS.is() )
352  nEntries += FillTree( xLTS->getLinks(), xEntry.get() );
353  }
354  catch(const css::uno::Exception&)
355  {
356  }
357  }
358  }
359 
360  return nEntries;
361 }
362 
363 // Clear Tree
365 {
366  std::unique_ptr<weld::TreeIter> xEntry = mxLbTree->make_iterator();
367  bool bEntry = mxLbTree->get_iter_first(*xEntry);
368 
369  while (bEntry)
370  {
371  TargetData* pUserData = reinterpret_cast<TargetData*>(mxLbTree->get_id(*xEntry).toInt64());
372  delete pUserData;
373 
374  bEntry = mxLbTree->iter_next(*xEntry);
375  }
376 
377  mxLbTree->clear();
378 }
379 
380 // Find Entry for String
381 std::unique_ptr<weld::TreeIter> SvxHlinkDlgMarkWnd::FindEntry (const OUString& aStrName)
382 {
383  bool bFound=false;
384  std::unique_ptr<weld::TreeIter> xEntry = mxLbTree->make_iterator();
385  bool bEntry = mxLbTree->get_iter_first(*xEntry);
386 
387  while (bEntry && !bFound)
388  {
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);
394  }
395 
396  if (!bFound)
397  xEntry.reset();
398 
399  return xEntry;
400 }
401 
402 // Select Entry
403 bool SvxHlinkDlgMarkWnd::SelectEntry(const OUString& aStrMark)
404 {
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;
411 }
412 
413 // Click on Apply-Button / Double-click on item in tree
414 IMPL_LINK_NOARG(SvxHlinkDlgMarkWnd, DoubleClickApplyHdl_Impl, weld::TreeView&, void)
415 {
416  ClickApplyHdl_Impl(*mxBtApply);
417 }
418 
419 IMPL_LINK_NOARG(SvxHlinkDlgMarkWnd, ClickApplyHdl_Impl, weld::Button&, void)
420 {
421  std::unique_ptr<weld::TreeIter> xEntry(mxLbTree->make_iterator());
422  bool bEntry = mxLbTree->get_cursor(xEntry.get());
423  if (bEntry)
424  {
425  TargetData* pData = reinterpret_cast<TargetData*>(mxLbTree->get_id(*xEntry).toInt64());
426  if (pData->bIsTarget)
427  {
428  mpParent->SetMarkStr(pData->aUStrLinkname);
429  }
430  }
431 }
432 
433 // Click on Close-Button
434 IMPL_LINK_NOARG(SvxHlinkDlgMarkWnd, ClickCloseHdl_Impl, weld::Button&, void)
435 {
436  std::unique_ptr<weld::TreeIter> xEntry(mxLbTree->make_iterator());
437  bool bEntry = mxLbTree->get_cursor(xEntry.get());
438  if (bEntry)
439  {
440  TargetData* pUserData = reinterpret_cast<TargetData*>(mxLbTree->get_id(*xEntry).toInt64());
441  OUString sLastSelectedMark = pUserData->aUStrLinkname;
442 
443  std::deque<OUString> aLastSelectedPath;
444  //If the bottommost entry is expanded but nothing
445  //underneath it is selected leave a dummy entry
446  if (mxLbTree->get_row_expanded(*xEntry))
447  aLastSelectedPath.push_front(OUString());
448  while (bEntry)
449  {
450  aLastSelectedPath.push_front(mxLbTree->get_text(*xEntry));
451  bEntry = mxLbTree->iter_parent(*xEntry);
452  }
453 
454  uno::Sequence< beans::NamedValue > aSettings
455  {
456  { TG_SETTING_LASTMARK, css::uno::Any(sLastSelectedMark) },
457  { TG_SETTING_LASTPATH, css::uno::Any(comphelper::containerToSequence(aLastSelectedPath)) }
458  };
459 
460  // write
461  SvtViewOptions aViewSettings( EViewType::Dialog, TG_SETTING_MANAGER );
462  aViewSettings.SetUserData( aSettings );
463  }
464 
465  m_xDialog->response(RET_CANCEL);
466 }
467 
468 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
std::shared_ptr< weld::Dialog > m_xDialog
std::unique_ptr< weld::Button > mxBtApply
Definition: hlmarkwn.hxx:40
OUString aUStrLinkname
Definition: hlmarkwn.cxx:47
virtual void scroll_to_row(int pos)=0
sal_uIntPtr sal_uLong
virtual ~SvxHlinkDlgMarkWnd() override
Definition: hlmarkwn.cxx:76
#define LERR_NOENTRIES
void MoveTo(const Point &rNewPos)
Definition: hlmarkwn.cxx:119
RET_CANCEL
css::uno::Reference< css::graphic::XGraphic > GetXGraphic() const
void RefreshTree(const OUString &aStrURL)
Definition: hlmarkwn.cxx:192
#define TG_SETTING_MANAGER
Definition: hlmarkwn.cxx:154
#define LERR_DOCNOTOPEN
static BitmapEx GetBitmap(const css::uno::Reference< css::awt::XBitmap > &rxBitmap)
void RestoreLastSelection()
Definition: hlmarkwn.cxx:158
#define LERR_NOERROR
sal_uInt16 SetError(sal_uInt16 nError)
Definition: hlmarkwn.cxx:105
std::unique_ptr< weld::TreeIter > FindEntry(const OUString &aStrName)
Definition: hlmarkwn.cxx:381
int i
bool RefreshFromDoc(const OUString &aURL)
Definition: hlmarkwn.cxx:221
void SetUserData(const css::uno::Sequence< css::beans::NamedValue > &lData)
bool bIsTarget
Definition: hlmarkwn.cxx:48
virtual OUString get_text(int row, int col=-1) const =0
virtual void expand_row(const TreeIter &rIter)=0
TargetData(const OUString &aUStrLName, bool bTarget)
Definition: hlmarkwn.cxx:50
long X() const
OUString CuiResId(const char *pKey)
Definition: cuiresmgr.cxx:23
virtual bool iter_children(TreeIter &rIter) const =0
#define TG_SETTING_LASTPATH
Definition: hlmarkwn.cxx:156
std::unique_ptr< weld::Label > mxError
Definition: hlmarkwn.hxx:43
virtual void select(int pos)=0
IMPL_LINK_NOARG(SvxHlinkDlgMarkWnd, DoubleClickApplyHdl_Impl, weld::TreeView &, void)
Definition: hlmarkwn.cxx:414
int FillTree(const css::uno::Reference< css::container::XNameAccess > &xLinks, weld::TreeIter *pParentEntry=nullptr)
Definition: hlmarkwn.cxx:280
sal_uInt16 mnError
Definition: hlmarkwn.hxx:38
css::uno::Sequence< DstElementType > containerToSequence(const SrcType &i_Container)
#define TG_SETTING_LASTMARK
Definition: hlmarkwn.cxx:155
bool Exists() const
Reference< XComponentContext > getProcessComponentContext()
css::uno::Any GetUserItem(const OUString &sName) const
SvxHlinkDlgMarkWnd(weld::Window *pParentDialog, SvxHyperlinkTabPageBase *pParentPage)
Definition: hlmarkwn.cxx:60
bool SelectEntry(const OUString &aStrMark)
Definition: hlmarkwn.cxx:403
std::unique_ptr< weld::Button > mxBtClose
Definition: hlmarkwn.hxx:41
virtual bool iter_next_sibling(TreeIter &rIter) const =0
sal_Int32 nPos
Tabpage : Basisclass.
Definition: hltpbase.hxx:47
std::unique_ptr< weld::TreeView > mxLbTree
Definition: hlmarkwn.hxx:42
long Y() const
OUString sId