xref: /core/cui/source/dialogs/hldocntp.cxx (revision 61346723)
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 <hldocntp.hxx>
21 #include <osl/file.hxx>
22 #include <sfx2/filedlghelper.hxx>
23 #include <sfx2/viewfrm.hxx>
24 #include <sfx2/docfilt.hxx>
25 #include <svl/stritem.hxx>
26 #include <com/sun/star/awt/XTopWindow.hpp>
27 #include <com/sun/star/uno/Reference.h>
28 #include <com/sun/star/uno/Exception.hpp>
29 #include <utility>
30 #include <vcl/svapp.hxx>
31 #include <vcl/weld.hxx>
32 #include <tools/urlobj.hxx>
33 #include <unotools/pathoptions.hxx>
34 #include <unotools/dynamicmenuoptions.hxx>
35 #include <unotools/ucbstreamhelper.hxx>
36 #include <unotools/ucbhelper.hxx>
37 
38 #include <comphelper/processfactory.hxx>
39 #include <com/sun/star/ui/dialogs/XFolderPicker2.hpp>
40 #include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp>
41 
42 #include <cuihyperdlg.hxx>
43 #include <dialmgr.hxx>
44 #include <strings.hrc>
45 
46 using namespace ::com::sun::star::lang;
47 using namespace ::com::sun::star::ui::dialogs;
48 using namespace ::com::sun::star::uno;
49 
50 using namespace ::com::sun::star;
51 
52 /*************************************************************************
53 |*
54 |* Data-struct for documenttypes in listbox
55 |*
56 |************************************************************************/
57 
58 namespace {
59 
60 struct DocumentTypeData
61 {
62     OUString aStrURL;
63     OUString aStrExt;
64     DocumentTypeData (OUString aURL, OUString aExt) : aStrURL(std::move(aURL)), aStrExt(std::move(aExt))
65     {}
66 };
67 
68 }
69 
70 bool SvxHyperlinkNewDocTp::ImplGetURLObject( const OUString& rPath, std::u16string_view rBase, INetURLObject& aURLObject ) const
71 {
72     bool bIsValidURL = !rPath.isEmpty();
73     if ( bIsValidURL )
74     {
75         aURLObject.SetURL( rPath );
76         if ( aURLObject.GetProtocol() == INetProtocol::NotValid )      // test if the source is already a valid url
77         {                                                           // if not we have to create a url from a physical file name
78             bool wasAbs;
79             INetURLObject base(rBase);
80             base.setFinalSlash();
81             aURLObject = base.smartRel2Abs(
82                 rPath, wasAbs, true, INetURLObject::EncodeMechanism::All,
83                 RTL_TEXTENCODING_UTF8, true);
84         }
85         bIsValidURL = aURLObject.GetProtocol() != INetProtocol::NotValid;
86         if ( bIsValidURL )
87         {
88             OUString aBase( aURLObject.getName( INetURLObject::LAST_SEGMENT, false ) );
89             if ( aBase.isEmpty() || ( aBase[0] == '.' ) )
90                 bIsValidURL = false;
91         }
92         if ( bIsValidURL )
93         {
94             sal_Int32 nPos = m_xLbDocTypes->get_selected_index();
95             if (nPos != -1)
96                 aURLObject.SetExtension(weld::fromId<DocumentTypeData*>(m_xLbDocTypes->get_id(nPos))->aStrExt);
97         }
98 
99     }
100     return bIsValidURL;
101 }
102 
103 /*************************************************************************
104 |*
105 |* Constructor / Destructor
106 |*
107 |************************************************************************/
108 
109 SvxHyperlinkNewDocTp::SvxHyperlinkNewDocTp(weld::Container* pParent, SvxHpLinkDlg* pDlg, const SfxItemSet* pItemSet)
110     : SvxHyperlinkTabPageBase(pParent, pDlg, "cui/ui/hyperlinknewdocpage.ui", "HyperlinkNewDocPage", pItemSet)
111     , m_xRbtEditNow(xBuilder->weld_radio_button("editnow"))
112     , m_xRbtEditLater(xBuilder->weld_radio_button("editlater"))
113     , m_xCbbPath(new SvxHyperURLBox(xBuilder->weld_combo_box("path")))
114     , m_xBtCreate(xBuilder->weld_button("create"))
115     , m_xLbDocTypes(xBuilder->weld_tree_view("types"))
116 {
117     m_xCbbPath->SetSmartProtocol(INetProtocol::File);
118     m_xLbDocTypes->set_size_request(-1, m_xLbDocTypes->get_height_rows(5));
119 
120     InitStdControls();
121 
122     SetExchangeSupport ();
123 
124     m_xCbbPath->show();
125     m_xCbbPath->SetBaseURL(SvtPathOptions().GetWorkPath());
126 
127     // set defaults
128     m_xRbtEditNow->set_active(true);
129 
130     m_xBtCreate->connect_clicked(LINK(this, SvxHyperlinkNewDocTp, ClickNewHdl_Impl));
131 
132     FillDocumentList ();
133 }
134 
135 SvxHyperlinkNewDocTp::~SvxHyperlinkNewDocTp ()
136 {
137     if (m_xLbDocTypes)
138     {
139         for (sal_Int32 n = 0, nEntryCount = m_xLbDocTypes->n_children(); n < nEntryCount; ++n)
140             delete weld::fromId<DocumentTypeData*>(m_xLbDocTypes->get_id(n));
141         m_xLbDocTypes = nullptr;
142     }
143 }
144 
145 /*************************************************************************
146 |*
147 |* Fill the all dialog-controls except controls in groupbox "more..."
148 |*
149 |************************************************************************/
150 
151 
152 void SvxHyperlinkNewDocTp::FillDlgFields(const OUString& /*rStrURL*/)
153 {
154 }
155 
156 void SvxHyperlinkNewDocTp::FillDocumentList()
157 {
158     weld::WaitObject aWaitObj(mpDialog->getDialog());
159 
160     std::vector<SvtDynMenuEntry> aDynamicMenuEntries( SvtDynamicMenuOptions::GetMenu( EDynamicMenuType::NewMenu ) );
161 
162     for ( const SvtDynMenuEntry & rDynamicMenuEntry : aDynamicMenuEntries )
163     {
164         OUString aDocumentUrl = rDynamicMenuEntry.sURL;
165         OUString aTitle = rDynamicMenuEntry.sTitle;
166 
167         //#i96822# business cards, labels and database should not be inserted here
168         if( aDocumentUrl == "private:factory/swriter?slot=21051" ||
169             aDocumentUrl == "private:factory/swriter?slot=21052" ||
170             aDocumentUrl == "private:factory/sdatabase?Interactive" )
171             continue;
172 
173         // Insert into listbox
174         if ( !aDocumentUrl.isEmpty() )
175         {
176             if ( aDocumentUrl == "private:factory/simpress?slot=6686" )              // SJ: #106216# do not start
177                 aDocumentUrl = "private:factory/simpress"; // the AutoPilot for impress
178 
179             // insert private-url and default-extension as user-data
180             std::shared_ptr<const SfxFilter> pFilter = SfxFilter::GetDefaultFilterFromFactory( aDocumentUrl );
181             if ( pFilter )
182             {
183                 // insert doc-name and image
184                 OUString aTitleName = aTitle.replaceFirst( "~", "" );
185 
186                 OUString aStrDefExt(pFilter->GetDefaultExtension());
187                 DocumentTypeData *pTypeData = new DocumentTypeData(aDocumentUrl, aStrDefExt.copy(2));
188                 OUString sId(weld::toId(pTypeData));
189                 m_xLbDocTypes->append(sId, aTitleName);
190             }
191         }
192     }
193     m_xLbDocTypes->select(0);
194 }
195 
196 /*************************************************************************
197 |*
198 |* retrieve and prepare data from dialog-fields
199 |*
200 |************************************************************************/
201 
202 void SvxHyperlinkNewDocTp::GetCurentItemData ( OUString& rStrURL, OUString& aStrName,
203                                                OUString& aStrIntName, OUString& aStrFrame,
204                                                SvxLinkInsertMode& eMode )
205 {
206     // get data from dialog-controls
207     rStrURL = m_xCbbPath->get_active_text();
208     INetURLObject aURL;
209     if ( ImplGetURLObject( rStrURL, m_xCbbPath->GetBaseURL(), aURL ) )
210     {
211         rStrURL = aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
212     }
213 
214     GetDataFromCommonFields( aStrName, aStrIntName, aStrFrame, eMode );
215 }
216 
217 /*************************************************************************
218 |*
219 |* static method to create Tabpage
220 |*
221 |************************************************************************/
222 
223 std::unique_ptr<IconChoicePage> SvxHyperlinkNewDocTp::Create(weld::Container* pWindow, SvxHpLinkDlg* pDlg, const SfxItemSet* pItemSet)
224 {
225     return std::make_unique<SvxHyperlinkNewDocTp>(pWindow, pDlg, pItemSet);
226 }
227 
228 /*************************************************************************
229 |*
230 |* Set initial focus
231 |*
232 |************************************************************************/
233 void SvxHyperlinkNewDocTp::SetInitFocus()
234 {
235     m_xCbbPath->grab_focus();
236 }
237 
238 namespace
239 {
240     struct ExecuteInfo
241     {
242         bool bRbtEditLater;
243         bool bRbtEditNow;
244         INetURLObject aURL;
245         OUString aStrDocName;
246         // current document
247         css::uno::Reference<css::frame::XFrame> xFrame;
248         SfxDispatcher* pDispatcher;
249     };
250 }
251 
252 IMPL_STATIC_LINK(SvxHyperlinkNewDocTp, DispatchDocument, void*, p, void)
253 {
254     std::unique_ptr<ExecuteInfo> xExecuteInfo(static_cast<ExecuteInfo*>(p));
255     if (!xExecuteInfo->xFrame.is())
256         return;
257     try
258     {
259         //if it throws dispatcher is invalid
260         css::uno::Reference<css::awt::XTopWindow>(xExecuteInfo->xFrame->getContainerWindow(), css::uno::UNO_QUERY_THROW);
261 
262         SfxViewFrame *pViewFrame = nullptr;
263 
264         // create items
265         SfxStringItem aName( SID_FILE_NAME, xExecuteInfo->aStrDocName );
266         SfxStringItem aReferer( SID_REFERER, "private:user" );
267         SfxStringItem aFrame( SID_TARGETNAME, "_blank");
268 
269         OUString aStrFlags('S');
270         if (xExecuteInfo->bRbtEditLater)
271         {
272             aStrFlags += "H";
273         }
274         SfxStringItem aFlags (SID_OPTIONS, aStrFlags);
275 
276         // open url
277         const SfxPoolItem* pReturn = xExecuteInfo->pDispatcher->ExecuteList(
278                 SID_OPENDOC, SfxCallMode::SYNCHRON,
279                 { &aName, &aFlags, &aFrame, &aReferer });
280 
281         // save new doc
282         const SfxViewFrameItem *pItem = dynamic_cast<const SfxViewFrameItem*>( pReturn  );  // SJ: pReturn is NULL if the Hyperlink
283         if ( pItem )                                                            // creation is cancelled #106216#
284         {
285             pViewFrame = pItem->GetFrame();
286             if (pViewFrame)
287             {
288                 SfxStringItem aNewName( SID_FILE_NAME, xExecuteInfo->aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
289                 SfxUnoFrameItem aDocFrame( SID_FILLFRAME, pViewFrame->GetFrame().GetFrameInterface() );
290                 fprintf(stderr, "is there a frame int %p\n", pViewFrame->GetFrame().GetFrameInterface().get() );
291                 pViewFrame->GetDispatcher()->ExecuteList(
292                     SID_SAVEASDOC, SfxCallMode::SYNCHRON,
293                     { &aNewName }, { &aDocFrame });
294             }
295         }
296 
297         if (xExecuteInfo->bRbtEditNow)
298         {
299             css::uno::Reference<css::awt::XTopWindow> xWindow(xExecuteInfo->xFrame->getContainerWindow(), css::uno::UNO_QUERY);
300             if (xWindow.is()) //will be false if the frame was exited while the document was loading (e.g. we waited for warning dialogs)
301                 xWindow->toFront();
302         }
303 
304         if (pViewFrame && xExecuteInfo->bRbtEditLater)
305         {
306             SfxObjectShell* pObjShell = pViewFrame->GetObjectShell();
307             pObjShell->DoClose();
308         }
309     }
310     catch (...)
311     {
312     }
313 }
314 
315 /*************************************************************************
316 |*
317 |* Any action to do after apply-button is pressed
318 |*
319 \************************************************************************/
320 void SvxHyperlinkNewDocTp::DoApply()
321 {
322     weld::WaitObject aWait(mpDialog->getDialog());
323 
324     // get data from dialog-controls
325     OUString aStrNewName = m_xCbbPath->get_active_text();
326 
327     if ( aStrNewName.isEmpty() )
328         aStrNewName = maStrInitURL;
329 
330     // create a real URL-String
331     INetURLObject aURL;
332     if ( !ImplGetURLObject( aStrNewName, m_xCbbPath->GetBaseURL(), aURL ) )
333         return;
334 
335     // create Document
336     aStrNewName = aURL.GetURLPath( INetURLObject::DecodeMechanism::NONE );
337     bool bCreate = true;
338     try
339     {
340         // check if file exists, warn before we overwrite it
341         std::unique_ptr<SvStream> pIStm = ::utl::UcbStreamHelper::CreateStream( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), StreamMode::READ );
342 
343         bool bOk = pIStm && ( pIStm->GetError() == ERRCODE_NONE);
344 
345         pIStm.reset();
346 
347         if( bOk )
348         {
349             std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(mpDialog->getDialog(),
350                                                        VclMessageType::Warning, VclButtonsType::YesNo,
351                                                        CuiResId(RID_CUISTR_HYPERDLG_QUERYOVERWRITE)));
352             bCreate = xWarn->run() == RET_YES;
353         }
354     }
355     catch (const uno::Exception&)
356     {
357     }
358 
359     if (!bCreate || aStrNewName.isEmpty())
360         return;
361 
362     ExecuteInfo* pExecuteInfo = new ExecuteInfo;
363 
364     pExecuteInfo->bRbtEditLater = m_xRbtEditLater->get_active();
365     pExecuteInfo->bRbtEditNow = m_xRbtEditNow->get_active();
366     // get private-url
367     sal_Int32 nPos = m_xLbDocTypes->get_selected_index();
368     if (nPos == -1)
369         nPos = 0;
370     pExecuteInfo->aURL = aURL;
371     pExecuteInfo->aStrDocName = weld::fromId<DocumentTypeData*>(m_xLbDocTypes->get_id(nPos))->aStrURL;
372 
373     // current document
374     pExecuteInfo->xFrame = GetDispatcher()->GetFrame()->GetFrame().GetFrameInterface();
375     pExecuteInfo->pDispatcher = GetDispatcher();
376 
377     Application::PostUserEvent(LINK(nullptr, SvxHyperlinkNewDocTp, DispatchDocument), pExecuteInfo);
378 }
379 
380 /*************************************************************************
381 |*
382 |* Click on imagebutton : new
383 |*
384 |************************************************************************/
385 IMPL_LINK_NOARG(SvxHyperlinkNewDocTp, ClickNewHdl_Impl, weld::Button&, void)
386 {
387     DisableClose( true );
388     uno::Reference < XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
389     uno::Reference < XFolderPicker2 >  xFolderPicker = sfx2::createFolderPicker(xContext, mpDialog->getDialog());
390 
391     OUString            aStrURL;
392     OUString            aTempStrURL( m_xCbbPath->get_active_text() );
393     osl::FileBase::getFileURLFromSystemPath( aTempStrURL, aStrURL );
394 
395     OUString            aStrPath = aStrURL;
396     bool            bZeroPath = aStrPath.isEmpty();
397     bool            bHandleFileName = bZeroPath;    // when path has length of 0, then the rest should always be handled
398                                                         //  as file name, otherwise we do not yet know
399 
400     if( bZeroPath )
401         aStrPath = SvtPathOptions().GetWorkPath();
402     else if( !::utl::UCBContentHelper::IsFolder( aStrURL ) )
403         bHandleFileName = true;
404 
405     xFolderPicker->setDisplayDirectory( aStrPath );
406     sal_Int16 nResult = xFolderPicker->execute();
407     DisableClose( false );
408     if( ExecutableDialogResults::OK != nResult )
409         return;
410 
411     char const  sSlash[] = "/";
412 
413     INetURLObject   aURL( aStrURL, INetProtocol::File );
414     OUString        aStrName;
415     if( bHandleFileName )
416         aStrName = bZeroPath? aTempStrURL : aURL.getName();
417 
418     m_xCbbPath->SetBaseURL( xFolderPicker->getDirectory() );
419     OUString          aStrTmp( xFolderPicker->getDirectory() );
420 
421     if( aStrTmp[ aStrTmp.getLength() - 1 ] != sSlash[0] )
422         aStrTmp += sSlash;
423 
424     // append old file name
425     if( bHandleFileName )
426         aStrTmp += aStrName;
427 
428     INetURLObject   aNewURL( aStrTmp );
429 
430     if (!aStrName.isEmpty() && !aNewURL.getExtension().isEmpty() &&
431        m_xLbDocTypes->get_selected_index() != -1)
432     {
433         // get private-url
434         const sal_Int32 nPos = m_xLbDocTypes->get_selected_index();
435         aNewURL.setExtension(weld::fromId<DocumentTypeData*>(m_xLbDocTypes->get_id(nPos))->aStrExt);
436     }
437 
438     if( aNewURL.GetProtocol() == INetProtocol::File )
439     {
440         osl::FileBase::getSystemPathFromFileURL(aNewURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), aStrTmp);
441     }
442     else
443     {
444         aStrTmp = aNewURL.GetMainURL( INetURLObject::DecodeMechanism::Unambiguous );
445     }
446 
447     m_xCbbPath->set_entry_text( aStrTmp );
448 }
449 
450 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
451