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