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
