Version 6.4.0.0.beta1, tag libreoffice-6.4.0.0.beta1
[LibreOffice.git] / fpicker / source / office / RemoteFilesDialog.cxx
blobb0739b49e95ca0640cf012c55d0629e3f9d3926d
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/.
8 */
10 #include <config_oauth2.h>
12 #include "fpsmartcontent.hxx"
13 #include "QueryFolderName.hxx"
14 #include "RemoteFilesDialog.hxx"
15 #include <fpsofficeResMgr.hxx>
16 #include <fpicker/strings.hrc>
17 #include <strings.hrc>
18 #include <comphelper/docpasswordrequest.hxx>
19 #include <comphelper/stillreadwriteinteraction.hxx>
20 #include <com/sun/star/task/InteractionHandler.hpp>
21 #include <com/sun/star/task/PasswordContainer.hpp>
22 #include <svtools/PlaceEditDialog.hxx>
23 #include <tools/debug.hxx>
24 #include <ucbhelper/commandenvironment.hxx>
25 #include <vcl/errinf.hxx>
26 #include <bitmaps.hlst>
27 #include <officecfg/Office/Common.hxx>
29 RemoteFilesDialog::RemoteFilesDialog( weld::Window* pParent, PickerFlags nBits )
30 : SvtFileDialog_Base( pParent, "fps/ui/remotefilesdialog.ui", "RemoteFilesDialog" )
31 , m_xContext( comphelper::getProcessComponentContext() )
32 , m_xMasterPasswd( PasswordContainer::create( m_xContext ) )
33 , m_bIsInExecute( false )
34 , m_xCancel_btn(m_xBuilder->weld_button("cancel"))
35 , m_xAddService_bar(m_xBuilder->weld_toolbar("add_service_bar"))
36 , m_xAddService_menu(m_xBuilder->weld_menu("service_edit_menu"))
37 , m_xServices_lb(m_xBuilder->weld_combo_box("services_lb"))
38 , m_xPathContainer(m_xBuilder->weld_container("breadcrumb_container"))
39 , m_xNewFolder(m_xBuilder->weld_button("new_folder"))
40 , m_xListView_btn(m_xBuilder->weld_toggle_button("list_view"))
41 , m_xIconView_btn(m_xBuilder->weld_toggle_button("icon_view"))
42 , m_xFilter_lb(m_xBuilder->weld_combo_box("filter_lb"))
43 , m_xName_ed(new AutocompleteEdit(m_xBuilder->weld_entry("filename")))
45 m_xAddService_bar->set_item_menu("add_service_btn", m_xAddService_menu.get());
47 m_eMode = ( nBits & PickerFlags::SaveAs ) ? REMOTEDLG_MODE_SAVE : REMOTEDLG_MODE_OPEN;
48 m_eType = ( nBits & PickerFlags::PathDialog ) ? REMOTEDLG_TYPE_PATHDLG : REMOTEDLG_TYPE_FILEDLG;
49 bool bMultiselection = bool( nBits & PickerFlags::MultiSelection );
50 m_bIsUpdated = false;
51 m_bIsConnected = false;
52 m_bServiceChanged = false;
53 m_nCurrentFilter = -1;
55 m_xName_ed->show();
57 // limit width due to super wide strings that may end up here
58 m_xFilter_lb->set_size_request(m_xFilter_lb->get_approximate_digit_width() * 60, -1);
60 m_xFilter_lb->set_sensitive(false);
61 m_xName_ed->set_sensitive(false);
62 m_xNewFolder->set_sensitive(false);
64 if( m_eMode == REMOTEDLG_MODE_OPEN )
66 m_xOk_btn = m_xBuilder->weld_button("open");
68 m_xNewFolder->hide();
70 else
72 m_xOk_btn = m_xBuilder->weld_button("save");
73 m_xNewFolder->connect_clicked( LINK( this, RemoteFilesDialog, NewFolderHdl ) );
76 m_xListView_btn->set_active(true);
77 m_xIconView_btn->connect_clicked( LINK( this, RemoteFilesDialog, IconViewHdl ) );
78 m_xListView_btn->connect_clicked( LINK( this, RemoteFilesDialog, ListViewHdl ) );
80 m_xOk_btn->show();
81 m_xOk_btn->set_sensitive(false);
83 m_xOk_btn->connect_clicked( LINK( this, RemoteFilesDialog, OkHdl ) );
84 m_xCancel_btn->connect_clicked( LINK( this, RemoteFilesDialog, CancelHdl ) );
86 m_sRootLabel = FpsResId( STR_SVT_ROOTLABEL );
87 m_xPath.reset(new Breadcrumb(m_xPathContainer.get()));
88 m_xPath->connect_clicked( LINK( this, RemoteFilesDialog, SelectBreadcrumbHdl ) );
89 m_xPath->SetMode( SvtBreadcrumbMode::ALL_VISITED );
91 m_xContainer = m_xBuilder->weld_container("container");
92 m_xContainer->set_size_request(m_xContainer->get_approximate_digit_width() * 82, -1);
94 m_xFileView.reset(new SvtFileView(m_xDialog.get(),
95 m_xBuilder->weld_tree_view("fileview"),
96 m_xBuilder->weld_icon_view("iconview"),
97 REMOTEDLG_TYPE_PATHDLG == m_eType,
98 bMultiselection, false));
100 m_xFileView->SetDoubleClickHdl( LINK( this, RemoteFilesDialog, DoubleClickHdl ) );
101 m_xFileView->SetSelectHdl( LINK( this, RemoteFilesDialog, SelectHdl ) );
102 m_xFileView->EnableDelete( true );
104 m_xTreeView.reset(new FolderTree(m_xBuilder->weld_tree_view("foldertree"), m_xDialog.get()));
105 m_xTreeView->connect_changed(LINK(this, RemoteFilesDialog, TreeSelectHdl));
107 m_xContainer->set_sensitive(false);
109 m_sIniKey = "RemoteFilesDialog";
110 InitSize();
112 m_xName_ed->connect_focus_in(LINK(this, RemoteFilesDialog, FileNameGetFocusHdl));
113 m_xName_ed->connect_changed(LINK(this, RemoteFilesDialog, FileNameModifyHdl));
115 m_xAddService_bar->connect_clicked(LINK( this, RemoteFilesDialog, AddServiceHdl));
116 m_xAddService_menu->connect_activate(LINK(this, RemoteFilesDialog, EditServiceMenuHdl));
118 FillServicesListbox();
120 m_xServices_lb->connect_changed( LINK( this, RemoteFilesDialog, SelectServiceHdl ) );
122 m_xFilter_lb->connect_changed( LINK( this, RemoteFilesDialog, SelectFilterHdl ) );
125 RemoteFilesDialog::~RemoteFilesDialog()
127 m_xFileView->SetSelectHdl(Link<SvtFileView*,void>());
129 // save window state
130 if( !m_sIniKey.isEmpty() )
132 SvtViewOptions aDlgOpt( EViewType::Dialog, m_sIniKey );
133 aDlgOpt.SetWindowState(OStringToOUString(m_xDialog->get_window_state(WindowStateMask::All), RTL_TEXTENCODING_UTF8));
135 Size aSize(m_xDialog->get_size());
137 OUString sSize = OUString::number( aSize.Width() ) + "|";
138 sSize = sSize + OUString::number( aSize.Height() ) + "|";
140 OUString sUserData = m_xFileView->GetConfigString();
141 aDlgOpt.SetUserItem( "UserData",
142 makeAny( sSize + sUserData ) );
145 // save services
146 std::shared_ptr< comphelper::ConfigurationChanges > batch( comphelper::ConfigurationChanges::create( m_xContext ) );
148 officecfg::Office::Common::Misc::FilePickerLastService::set( m_sLastServiceUrl, batch );
150 if( m_bIsUpdated )
152 Sequence< OUString > placesUrlsList( m_aServices.size() );
153 Sequence< OUString > placesNamesList( m_aServices.size() );
155 int i = 0;
156 for (auto const& service : m_aServices)
158 placesUrlsList[i] = service->GetUrl();
159 placesNamesList[i] = service->GetName();
160 ++i;
163 officecfg::Office::Common::Misc::FilePickerPlacesUrls::set( placesUrlsList, batch );
164 officecfg::Office::Common::Misc::FilePickerPlacesNames::set( placesNamesList, batch );
167 batch->commit();
170 short RemoteFilesDialog::run()
172 if (m_xServices_lb->get_count() > 0)
174 m_xDialog->show();
175 SelectServiceHdl(*m_xServices_lb);
177 if (!m_bIsConnected)
179 m_xServices_lb->set_active(-1);
180 m_xAddService_bar->set_item_menu("add_service_btn", nullptr);
183 m_bIsInExecute = true;
184 short nRet = SvtFileDialog_Base::run();
185 m_bIsInExecute = false;
186 return nRet;
189 static OUString lcl_GetServiceType( const ServicePtr& pService )
191 INetProtocol aProtocol = pService->GetUrlObject().GetProtocol();
192 switch( aProtocol )
194 case INetProtocol::Ftp:
195 return "FTP";
196 case INetProtocol::Cmis:
198 OUString sHost = pService->GetUrlObject().GetHost( INetURLObject::DecodeMechanism::WithCharset );
200 if( sHost.startsWith( GDRIVE_BASE_URL ) )
201 return "Google Drive";
202 else if( sHost.startsWith( ALFRESCO_CLOUD_BASE_URL ) )
203 return "Alfresco Cloud";
204 else if( sHost.startsWith( ONEDRIVE_BASE_URL ) )
205 return "OneDrive";
207 return "CMIS";
209 case INetProtocol::Smb:
210 return "Windows Share";
211 case INetProtocol::File:
212 return "SSH";
213 case INetProtocol::Http:
214 return "WebDAV";
215 case INetProtocol::Https:
216 return "WebDAV";
217 case INetProtocol::Generic:
218 return "SSH";
219 default:
220 return OUString();
224 void RemoteFilesDialog::InitSize()
226 if( m_sIniKey.isEmpty() )
227 return;
229 // initialize from config
230 SvtViewOptions aDlgOpt( EViewType::Dialog, m_sIniKey );
232 if( aDlgOpt.Exists() )
234 m_xDialog->set_window_state(OUStringToOString(aDlgOpt.GetWindowState(), RTL_TEXTENCODING_UTF8));
236 Any aUserData = aDlgOpt.GetUserItem( "UserData" );
237 OUString sCfgStr;
238 if( aUserData >>= sCfgStr )
240 sal_Int32 nPos1{ sCfgStr.indexOf('|') };
241 if (nPos1<0)
242 return;
243 sal_Int32 nPos2{ sCfgStr.indexOf('|', nPos1+1 ) };
244 if (nPos2<0)
245 return;
246 m_xFileView->SetConfigString( sCfgStr.copy(nPos2+1) );
251 void RemoteFilesDialog::FillServicesListbox()
253 m_xServices_lb->clear();
254 m_aServices.clear();
256 // Load from user settings
257 Sequence< OUString > placesUrlsList( officecfg::Office::Common::Misc::FilePickerPlacesUrls::get( m_xContext ) );
258 Sequence< OUString > placesNamesList( officecfg::Office::Common::Misc::FilePickerPlacesNames::get( m_xContext ) );
260 unsigned int nPos = 0;
261 unsigned int i = 0;
263 m_sLastServiceUrl = officecfg::Office::Common::Misc::FilePickerLastService::get( m_xContext );
265 for( sal_Int32 nPlace = 0; nPlace < placesUrlsList.getLength() && nPlace < placesNamesList.getLength(); ++nPlace )
267 ServicePtr pService( new Place( placesNamesList[nPlace], placesUrlsList[nPlace], true ) );
268 m_aServices.push_back( pService );
270 // Add to the listbox only remote services, not local bookmarks
271 if( !pService->IsLocal() )
273 OUString sPrefix = lcl_GetServiceType( pService );
275 if( !sPrefix.isEmpty() )
276 sPrefix += ": ";
278 if( placesUrlsList[nPlace] == m_sLastServiceUrl )
279 nPos = i;
281 m_xServices_lb->append_text(sPrefix + placesNamesList[nPlace]);
283 i++;
287 if (m_xServices_lb->get_count() > 0)
289 m_xServices_lb->set_active(nPos);
290 m_xAddService_bar->set_item_menu("add_service_btn", m_xAddService_menu.get());
292 else
293 m_xAddService_bar->set_item_menu("add_service_btn", nullptr);
295 EnableControls();
298 int RemoteFilesDialog::GetSelectedServicePos()
300 if( m_aServices.empty() )
301 return -1;
303 int nPos = 0;
304 int i = -1;
306 int nSelected = m_xServices_lb->get_active();
308 int nServices = static_cast<int>(m_aServices.size());
309 while( nPos < nServices )
311 while( (nPos < nServices) && m_aServices[nPos]->IsLocal() )
312 nPos++;
313 i++;
314 if( i == nSelected )
315 break;
316 nPos++;
319 return nPos;
322 void RemoteFilesDialog::AddFilter( const OUString& rFilter, const OUString& rType )
324 OUString sName = rFilter;
326 m_aFilters.emplace_back( rFilter, rType );
327 if (rType.isEmpty())
328 m_xFilter_lb->append_separator("");
329 else
330 m_xFilter_lb->append_text(sName);
332 if (m_xFilter_lb->get_active() == -1)
333 m_xFilter_lb->set_active(0);
336 void RemoteFilesDialog::OpenURL( OUString const & sURL )
338 if( m_xFileView )
340 DisableControls();
342 auto xWait = std::make_unique<weld::WaitObject>(m_xDialog.get());
344 if( !sURL.isEmpty() )
346 OUString sFilter = FILEDIALOG_FILTER_ALL;
348 if( m_nCurrentFilter != -1)
350 sFilter = m_aFilters[m_nCurrentFilter].second;
353 m_xFileView->EndInplaceEditing();
355 DBG_ASSERT( !m_pCurrentAsyncAction.is(), "SvtFileDialog::executeAsync: previous async action not yet finished!" );
357 m_pCurrentAsyncAction = new AsyncPickerAction( this, m_xFileView.get(), AsyncPickerAction::Action::eOpenURL );
359 // -1 timeout - sync
360 m_pCurrentAsyncAction->execute( sURL, sFilter, -1, -1, GetBlackList() );
362 if( m_eMode != REMOTEDLG_MODE_SAVE )
363 m_xName_ed->set_text( "" );
365 m_xFileView->grab_focus();
367 else
369 xWait.reset();
371 // content doesn't exist
372 ErrorHandler::HandleError( ERRCODE_IO_NOTEXISTS );
374 EnableControls();
379 void RemoteFilesDialog::AddFileExtension()
381 if (m_nCurrentFilter != -1)
383 OUString sExt = m_aFilters[m_nCurrentFilter].second;
384 OUString sFileName = m_xName_ed->get_text();
386 sal_Int32 nDotPos = sFileName.lastIndexOf( '.' );
388 if ( nDotPos == -1 )
390 sFileName += sExt.copy( 1 ); // without '*'
391 m_xName_ed->set_text( sFileName );
396 void RemoteFilesDialog::EnableControls()
398 if (m_xServices_lb->get_count() > 0)
400 m_xServices_lb->set_sensitive(true);
402 if (m_xServices_lb->get_active() != -1)
404 m_xAddService_menu->set_sensitive("change_password", false);
408 if( m_xMasterPasswd->isPersistentStoringAllowed() )
410 int nPos = GetSelectedServicePos();
412 if( nPos >= 0 )
414 OUString sUrl( m_aServices[nPos]->GetUrl() );
416 UrlRecord aURLEntries = m_xMasterPasswd->find( sUrl, Reference< XInteractionHandler>() );
418 if( aURLEntries.UserList.hasElements() )
420 m_xAddService_menu->set_sensitive("change_password", true);
425 catch( const Exception& )
429 else
430 m_xServices_lb->set_sensitive(false);
432 if( m_bIsConnected )
434 m_xFilter_lb->set_sensitive(true);
435 m_xName_ed->set_sensitive(true);
436 m_xContainer->set_sensitive(true);
437 m_xNewFolder->set_sensitive(true);
439 if (!m_xName_ed->get_text().isEmpty())
440 m_xOk_btn->set_sensitive(true);
441 else
442 m_xOk_btn->set_sensitive(false);
444 else
446 m_xFilter_lb->set_sensitive(false);
447 m_xName_ed->set_sensitive(false);
448 m_xContainer->set_sensitive(false);
449 m_xNewFolder->set_sensitive(false);
450 m_xOk_btn->set_sensitive(false);
453 m_xPath->EnableFields( true );
454 m_xAddService_bar->set_sensitive(true);
457 void RemoteFilesDialog::DisableControls()
459 m_xServices_lb->set_sensitive(false);
460 m_xFilter_lb->set_sensitive(false);
461 m_xAddService_bar->set_sensitive(false);
462 m_xName_ed->set_sensitive(false);
463 m_xContainer->set_sensitive(false);
464 m_xOk_btn->set_sensitive(false);
465 m_xPath->EnableFields( false );
467 m_xCancel_btn->set_sensitive(true);
470 void RemoteFilesDialog::SavePassword(const OUString& rURL, const OUString& rUser,
471 const OUString& rPassword, bool bPersistent)
473 if( rURL.isEmpty() || rUser.isEmpty() || rPassword.isEmpty() )
474 return;
478 if( !bPersistent ||
479 ( m_xMasterPasswd->isPersistentStoringAllowed()
480 && m_xMasterPasswd->authorizateWithMasterPassword( Reference< XInteractionHandler>() ) )
483 Reference< XInteractionHandler > xInteractionHandler =
484 InteractionHandler::createWithParent( m_xContext, nullptr );
486 Sequence<OUString> aPasswd { rPassword };
488 if( bPersistent )
489 m_xMasterPasswd->addPersistent(
490 rURL, rUser, aPasswd, xInteractionHandler );
491 else
492 m_xMasterPasswd->add( rURL, rUser, aPasswd, xInteractionHandler );
495 catch( const Exception& )
499 IMPL_LINK_NOARG ( RemoteFilesDialog, IconViewHdl, weld::Button&, void )
501 m_xListView_btn->set_active(false);
502 m_xFileView->SetViewMode( eIcon );
505 IMPL_LINK_NOARG ( RemoteFilesDialog, ListViewHdl, weld::Button&, void )
507 m_xIconView_btn->set_active(false);
508 m_xFileView->SetViewMode( eDetailedList );
511 IMPL_LINK_NOARG ( RemoteFilesDialog, AddServiceHdl, const OString&, void )
513 PlaceEditDialog aDlg(m_xDialog.get());
514 aDlg.ShowPasswordControl();
515 short aRetCode = aDlg.run();
517 switch( aRetCode )
519 case RET_OK :
521 ServicePtr newService = aDlg.GetPlace();
522 m_aServices.push_back( newService );
524 OUString sPassword = aDlg.GetPassword();
525 OUString sUser = aDlg.GetUser();
526 if( !sUser.isEmpty() && !sPassword.isEmpty() )
528 bool bPersistent = aDlg.IsRememberChecked();
529 SavePassword( newService->GetUrl(), sUser, sPassword, bPersistent );
532 OUString sPrefix = lcl_GetServiceType( newService );
534 if(!sPrefix.isEmpty())
535 sPrefix += ": ";
537 m_xServices_lb->append_text( sPrefix + newService->GetName() );
538 m_xServices_lb->set_active( m_xServices_lb->get_count() - 1 );
539 m_xAddService_bar->set_item_menu("add_service_btn", m_xAddService_menu.get());
540 SelectServiceHdl( *m_xServices_lb );
542 m_bIsUpdated = true;
544 EnableControls();
545 break;
547 case RET_CANCEL :
548 default :
549 // Do Nothing
550 break;
554 IMPL_LINK_NOARG( RemoteFilesDialog, SelectServiceHdl, weld::ComboBox&, void )
556 int nPos = GetSelectedServicePos();
558 if( nPos >= 0 )
560 OUString sURL = m_aServices[nPos]->GetUrl();
561 m_xAddService_bar->set_item_menu("add_service_btn", m_xAddService_menu.get());
563 m_bServiceChanged = true;
564 OpenURL( sURL );
568 IMPL_LINK ( RemoteFilesDialog, EditServiceMenuHdl, const OString&, rIdent, void )
570 OString sIdent(rIdent);
571 if( sIdent == "edit_service" && m_xServices_lb->get_count() > 0 )
573 int nSelected = m_xServices_lb->get_active();
574 int nPos = GetSelectedServicePos();
576 if( nPos >= 0 )
578 PlaceEditDialog aDlg(m_xDialog.get(), m_aServices[nPos]);
579 short aRetCode = aDlg.run();
581 switch( aRetCode )
583 case RET_OK :
585 ServicePtr pEditedService = aDlg.GetPlace();
587 m_aServices[nPos] = pEditedService;
588 m_xServices_lb->remove( nSelected );
590 OUString sPrefix = lcl_GetServiceType( pEditedService );
592 if(!sPrefix.isEmpty())
593 sPrefix += ": ";
595 m_xServices_lb->insert_text(nSelected, sPrefix + pEditedService->GetName());
596 m_xServices_lb->set_active( nSelected );
598 m_bIsUpdated = true;
599 break;
601 case RET_NO:
602 sIdent = "delete_service";
603 break;
604 case RET_CANCEL :
605 default :
606 // Do Nothing
607 break;
611 if( sIdent == "delete_service" && m_xServices_lb->get_count() > 0 )
613 int nSelected = m_xServices_lb->get_active();
614 int nPos = GetSelectedServicePos();
616 if( nPos >= 0 )
618 OUString sMsg = FpsResId( STR_SVT_DELETESERVICE );
619 sMsg = sMsg.replaceFirst( "$servicename$", m_xServices_lb->get_active_text() );
620 std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_xDialog.get(),
621 VclMessageType::Question, VclButtonsType::YesNo, sMsg));
622 if (xBox->run() == RET_YES)
624 // remove password
627 if( m_xMasterPasswd->isPersistentStoringAllowed() )
629 OUString sUrl( m_aServices[nPos]->GetUrl() );
631 Reference< XInteractionHandler > xInteractionHandler =
632 InteractionHandler::createWithParent( m_xContext, nullptr );
634 UrlRecord aURLEntries = m_xMasterPasswd->find( sUrl, xInteractionHandler );
636 if( aURLEntries.Url == sUrl && aURLEntries.UserList.hasElements() )
638 OUString sUserName = aURLEntries.UserList[0].UserName;
640 m_xMasterPasswd->removePersistent( sUrl, sUserName );
644 catch( const Exception& )
647 m_aServices.erase( m_aServices.begin() + nPos );
648 m_xServices_lb->remove( nSelected );
650 m_xServices_lb->set_active(-1);
651 m_xAddService_bar->set_item_menu("add_service_btn", nullptr);
653 m_bIsUpdated = true;
655 m_bIsConnected = false;
656 EnableControls();
660 else if( sIdent == "change_password" )
664 if( m_xMasterPasswd->isPersistentStoringAllowed() && m_xMasterPasswd->authorizateWithMasterPassword( Reference< XInteractionHandler>() ) )
666 int nPos = GetSelectedServicePos();
668 if( nPos >= 0 )
670 OUString sUrl( m_aServices[nPos]->GetUrl() );
672 Reference< XInteractionHandler > xInteractionHandler =
673 InteractionHandler::createWithParent( m_xContext, nullptr );
675 UrlRecord aURLEntries = m_xMasterPasswd->find( sUrl, xInteractionHandler );
677 if( aURLEntries.Url == sUrl && aURLEntries.UserList.hasElements() )
679 OUString sUserName = aURLEntries.UserList[0].UserName;
681 ::comphelper::SimplePasswordRequest* pPasswordRequest
682 = new ::comphelper::SimplePasswordRequest;
683 Reference< XInteractionRequest > rRequest( pPasswordRequest );
685 xInteractionHandler->handle( rRequest );
687 if ( pPasswordRequest->isPassword() )
689 OUString aNewPass = pPasswordRequest->getPassword();
690 Sequence<OUString> aPasswd { aNewPass };
692 m_xMasterPasswd->addPersistent(
693 sUrl, sUserName, aPasswd, xInteractionHandler );
699 catch( const Exception& )
703 EnableControls();
706 IMPL_LINK_NOARG( RemoteFilesDialog, DoubleClickHdl, SvtFileView*, bool )
708 SvtContentEntry* pData = m_xFileView->FirstSelected();
709 if (pData)
711 if (!pData->mbIsFolder)
712 m_xDialog->response(RET_OK);
713 else
714 OpenURL(pData->maURL);
716 return true;
719 IMPL_LINK_NOARG( RemoteFilesDialog, SelectHdl, SvtFileView*, void )
721 SvtContentEntry* pData = m_xFileView->FirstSelected();
722 if (pData)
724 if( ( pData->mbIsFolder && ( m_eType == REMOTEDLG_TYPE_PATHDLG ) )
725 || ( !pData->mbIsFolder && ( m_eType == REMOTEDLG_TYPE_FILEDLG ) ) )
727 // url must contain user info, because we need this info in recent files entry
728 // (to fill user field in login box by default)
729 INetURLObject aURL( pData->maURL );
730 INetURLObject aCurrentURL( m_sLastServiceUrl );
731 aURL.SetUser( aCurrentURL.GetUser() );
733 m_sPath = aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
735 m_xName_ed->set_text( aURL.GetLastName(INetURLObject::DecodeMechanism::WithCharset) );
737 else
739 if( m_eMode == REMOTEDLG_MODE_OPEN )
741 m_sPath.clear();
742 m_xName_ed->set_text( "" );
746 EnableControls();
750 IMPL_LINK_NOARG(RemoteFilesDialog, FileNameGetFocusHdl, weld::Widget&, void)
752 m_xFileView->SetNoSelection();
755 IMPL_LINK_NOARG(RemoteFilesDialog, FileNameModifyHdl, weld::Entry&, void)
757 m_xFileView->SetNoSelection();
758 if (!m_xOk_btn->get_sensitive())
759 EnableControls();
762 IMPL_LINK_NOARG( RemoteFilesDialog, SelectFilterHdl, weld::ComboBox&, void )
764 int nPos = m_xFilter_lb->get_active();
766 if( nPos != -1 && !m_aFilters[nPos].second.isEmpty() )
768 m_nCurrentFilter = nPos;
770 OUString sCurrentURL = m_xFileView->GetViewURL();
772 if( !sCurrentURL.isEmpty() && m_bIsConnected )
773 OpenURL( sCurrentURL );
777 IMPL_LINK(RemoteFilesDialog, TreeSelectHdl, weld::TreeView&, rBox, void)
779 OpenURL(rBox.get_selected_id());
780 m_xFileView->grab_focus();
783 IMPL_LINK(RemoteFilesDialog, SelectBreadcrumbHdl, Breadcrumb*, pPtr, bool)
785 OpenURL( pPtr->GetHdlURL() );
786 return true;
789 IMPL_LINK_NOARG ( RemoteFilesDialog, NewFolderHdl, weld::Button&, void )
791 m_xFileView->EndInplaceEditing();
793 // will be bound after InteractionHandler is enabled
794 SmartContent aContent;
795 aContent.enableDefaultInteractionHandler();
796 // now it can be bound
797 aContent.bindTo( m_xFileView->GetViewURL() );
798 if( !aContent.canCreateFolder() )
799 return;
801 OUString aTitle;
802 aContent.getTitle( aTitle );
803 QueryFolderNameDialog aDlg(m_xDialog.get(), aTitle, FpsResId(STR_SVT_NEW_FOLDER));
804 bool bHandled = false;
806 while( !bHandled )
808 if (aDlg.run() == RET_OK)
810 OUString aUrl = aContent.createFolder(aDlg.GetName());
811 if( !aUrl.isEmpty() )
813 m_xFileView->CreatedFolder(aUrl, aDlg.GetName());
814 bHandled = true;
817 else
818 bHandled = true;
822 IMPL_LINK_NOARG ( RemoteFilesDialog, OkHdl, weld::Button&, void )
824 OUString sNameNoExt = m_xName_ed->get_text();
825 OUString sPathNoExt;
827 // auto extension
828 if( m_eMode == REMOTEDLG_MODE_SAVE )
829 AddFileExtension();
831 // check if file/path exists
833 OUString sCurrentPath = m_xFileView->GetViewURL();
834 OUString sSelectedItem = m_xFileView->GetCurrentURL();
835 OUString sName = m_xName_ed->get_text();
837 bool bFileDlg = ( m_eType == REMOTEDLG_TYPE_FILEDLG );
838 bool bSelected = ( m_xFileView->GetSelectionCount() > 0 );
840 if( !sCurrentPath.endsWith("/") )
841 sCurrentPath += "/";
843 if( !bSelected )
845 m_sPath = sCurrentPath + INetURLObject::encode( sName, INetURLObject::PART_FPATH, INetURLObject::EncodeMechanism::All );
846 sPathNoExt = sCurrentPath + INetURLObject::encode( sNameNoExt, INetURLObject::PART_FPATH, INetURLObject::EncodeMechanism::All );
848 else
850 if( m_eType == REMOTEDLG_TYPE_PATHDLG )
851 m_sPath = sCurrentPath;
852 else
853 m_sPath = sSelectedItem;
855 // url must contain user info, because we need this info in recent files entry
856 // (to fill user field in login box by default)
857 INetURLObject aURL( m_sPath );
858 INetURLObject aCurrentURL( m_sLastServiceUrl );
859 aURL.SetUser( aCurrentURL.GetUser() );
861 m_sPath = aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
864 bool bExists = false;
866 if( bFileDlg )
867 bExists = ContentIsDocument( m_sPath );
868 else
869 bExists = ContentIsFolder( m_sPath );
871 if( bExists )
873 if( m_eMode == REMOTEDLG_MODE_SAVE )
875 OUString sMsg = FpsResId( STR_SVT_ALREADYEXISTOVERWRITE );
876 sMsg = sMsg.replaceFirst( "$filename$", sName );
877 std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_xDialog.get(),
878 VclMessageType::Question, VclButtonsType::YesNo, sMsg));
879 if (xBox->run() != RET_YES)
880 return;
883 else
885 if( ContentIsFolder( sPathNoExt ) )
887 OpenURL( sPathNoExt );
888 m_xName_ed->set_text( "" );
890 if (!bSelected)
891 m_xName_ed->grab_focus();
893 return;
896 if( m_eMode == REMOTEDLG_MODE_OPEN )
897 return;
900 m_xDialog->response(RET_OK);
903 IMPL_LINK_NOARG ( RemoteFilesDialog, CancelHdl, weld::Button&, void )
905 if( m_pCurrentAsyncAction.is() )
907 m_pCurrentAsyncAction->cancel();
908 onAsyncOperationFinished();
910 else
912 m_xDialog->response(RET_CANCEL);
916 // SvtFileDialog_Base
917 SvtFileView* RemoteFilesDialog::GetView()
919 return m_xFileView.get();
922 void RemoteFilesDialog::SetHasFilename( bool )
926 void RemoteFilesDialog::SetBlackList( const css::uno::Sequence< OUString >& rBlackList )
928 m_aBlackList = rBlackList;
929 m_xTreeView->SetBlackList( rBlackList );
932 const css::uno::Sequence< OUString >& RemoteFilesDialog::GetBlackList() const
934 return m_aBlackList;
937 void RemoteFilesDialog::SetStandardDir( const OUString& rStdDir )
939 m_sStdDir = rStdDir;
942 const OUString& RemoteFilesDialog::GetStandardDir() const
944 return m_sStdDir;
947 void RemoteFilesDialog::SetPath( const OUString& rNewURL )
949 m_sPath = rNewURL;
951 if( m_eMode == REMOTEDLG_MODE_SAVE )
953 INetURLObject aUrl( m_sPath );
954 OUString sFileName = aUrl.GetLastName( INetURLObject::DecodeMechanism::WithCharset );
956 m_xName_ed->set_text( sFileName );
960 OUString RemoteFilesDialog::getCurrentFileText() const
962 OUString sReturn;
963 if( m_xName_ed )
964 sReturn = m_xName_ed->get_text();
965 return sReturn;
968 void RemoteFilesDialog::setCurrentFileText( const OUString& rText, bool bSelectAll )
970 if (m_xName_ed)
972 m_xName_ed->set_text(rText);
973 if( bSelectAll )
974 m_xName_ed->select_region(0, -1);
978 void RemoteFilesDialog::AddFilterGroup(
979 const OUString& rFilter,
980 const css::uno::Sequence< css::beans::StringPair >& rFilters )
982 AddFilter( rFilter, OUString() );
983 const StringPair* pSubFilters = rFilters.getConstArray();
984 const StringPair* pSubFiltersEnd = pSubFilters + rFilters.getLength();
985 for ( ; pSubFilters != pSubFiltersEnd; ++pSubFilters )
986 AddFilter( pSubFilters->First, pSubFilters->Second );
989 OUString RemoteFilesDialog::GetCurFilter() const
991 OUString sFilter;
993 if (m_nCurrentFilter != -1)
995 sFilter = m_aFilters[m_nCurrentFilter].first;
998 return sFilter;
1001 OUString RemoteFilesDialog::getCurFilter( ) const
1003 return GetCurFilter();
1006 void RemoteFilesDialog::SetCurFilter( const OUString& rFilter )
1008 DBG_ASSERT( !m_bIsInExecute, "SvtFileDialog::SetCurFilter: currently executing!" );
1010 // look for corresponding filter
1011 sal_uInt16 nPos = m_aFilters.size();
1013 while ( nPos-- )
1015 if ( m_aFilters[nPos].first == rFilter )
1017 m_nCurrentFilter = nPos;
1018 m_xFilter_lb->set_active( m_nCurrentFilter );
1019 break;
1024 void RemoteFilesDialog::FilterSelect()
1028 void RemoteFilesDialog::SetFileCallback( ::svt::IFilePickerListener * )
1032 void RemoteFilesDialog::onAsyncOperationStarted()
1034 DisableControls();
1037 void RemoteFilesDialog::onAsyncOperationFinished()
1039 m_pCurrentAsyncAction = nullptr;
1040 EnableControls();
1043 void RemoteFilesDialog::UpdateControls( const OUString& rURL )
1045 int nPos = GetSelectedServicePos();
1047 if( nPos >= 0 && m_bServiceChanged && rURL == m_aServices[nPos]->GetUrl() )
1049 OUString sURL = m_aServices[nPos]->GetUrl();
1051 m_xPath->SetRootName( m_sRootLabel );
1052 m_xTreeView->clear();
1054 m_xTreeView->InsertRootEntry(rURL, m_sRootLabel);
1056 m_xName_ed->grab_focus();
1058 m_sLastServiceUrl = sURL;
1060 m_bServiceChanged = false;
1063 m_xPath->SetURL( rURL );
1065 m_xTreeView->connect_changed(Link<weld::TreeView&,void>());
1067 // read cached data for this url and fill the tree
1068 const ::std::vector< SvtContentEntry >& rFolders = m_xFileView->GetContent();
1069 ::std::vector< std::pair< OUString, OUString > > aFolders;
1071 m_xName_ed->ClearEntries();
1073 for(const auto & rFolder : rFolders)
1075 //WebDAV folders path ends in '/', so strip it
1076 OUString aFolderName = rFolder.maURL;
1077 if( rFolder.mbIsFolder && ( ( aFolderName.lastIndexOf( '/' ) + 1 ) == aFolderName.getLength() ) )
1078 aFolderName = aFolderName.copy( 0, aFolderName.getLength() - 1 );
1080 int nTitleStart = aFolderName.lastIndexOf( '/' );
1081 if( nTitleStart != -1 )
1083 OUString sTitle( INetURLObject::decode(
1084 aFolderName.copy( nTitleStart + 1 ),
1085 INetURLObject::DecodeMechanism::WithCharset ) );
1087 if( rFolder.mbIsFolder )
1089 aFolders.emplace_back( sTitle, aFolderName );
1092 // add entries to the autocompletion mechanism
1093 m_xName_ed->AddEntry( sTitle );
1097 m_xTreeView->FillTreeEntry( rURL, aFolders );
1099 m_xTreeView->connect_changed( LINK( this, RemoteFilesDialog, TreeSelectHdl ) );
1101 m_bIsConnected = true;
1102 EnableControls();
1105 void RemoteFilesDialog::EnableAutocompletion( bool )
1107 // This dialog contains Breadcrumb, not Edit
1110 const OUString& RemoteFilesDialog::GetPath()
1112 return m_sPath;
1115 std::vector<OUString> RemoteFilesDialog::GetPathList() const
1117 std::vector<OUString> aList;
1119 m_xFileView->selected_foreach([this, &aList](weld::TreeIter& rCurEntry){
1120 // url must contain user info, because we need this info in recent files entry
1121 // (to fill user field in login box by default)
1122 INetURLObject aURL(m_xFileView->GetURL(rCurEntry));
1123 INetURLObject aCurrentURL( m_sLastServiceUrl );
1124 aURL.SetUser( aCurrentURL.GetUser() );
1126 aList.push_back( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
1128 return false;
1131 if( aList.empty() && !m_sPath.isEmpty() )
1132 aList.push_back( m_sPath );
1134 return aList;
1137 bool RemoteFilesDialog::ContentIsFolder( const OUString& rURL )
1141 Reference< XInteractionHandler > xInteractionHandler(
1142 InteractionHandler::createWithParent( m_xContext, nullptr ), UNO_QUERY_THROW );
1143 Reference< XCommandEnvironment > xEnv = new ::ucbhelper::CommandEnvironment( xInteractionHandler, Reference< XProgressHandler >() );
1144 ::ucbhelper::Content aContent( rURL, xEnv, m_xContext );
1146 return aContent.isFolder();
1148 catch( const Exception& )
1150 // a content doesn't exist
1153 return false;
1156 bool RemoteFilesDialog::ContentIsDocument( const OUString& rURL )
1160 Reference< XInteractionHandler > xInteractionHandler(
1161 InteractionHandler::createWithParent( m_xContext, nullptr ), UNO_QUERY_THROW );
1162 //check if WebDAV or not
1163 if ( !INetURLObject( rURL ).isAnyKnownWebDAVScheme() )
1165 // no webdav, use the interaction handler as is
1166 Reference< XCommandEnvironment > xEnv = new ::ucbhelper::CommandEnvironment( xInteractionHandler, Reference< XProgressHandler >() );
1167 ::ucbhelper::Content aContent( rURL, xEnv, m_xContext );
1169 return aContent.isDocument();
1171 else
1173 // It's a webdav URL, so use the same open sequence as in normal open process.
1174 // Let's use a comphelper::StillReadWriteInteraction to trap errors here without showing the user.
1175 // This sequence will result in an exception if the target URL resource is not present
1176 comphelper::StillReadWriteInteraction* pInteraction = new comphelper::StillReadWriteInteraction(xInteractionHandler,xInteractionHandler);
1177 css::uno::Reference< css::task::XInteractionHandler > xInteraction(static_cast< css::task::XInteractionHandler* >(pInteraction), css::uno::UNO_QUERY);
1179 Reference< XCommandEnvironment > xEnv = new ::ucbhelper::CommandEnvironment( xInteraction, Reference< XProgressHandler >() );
1180 ::ucbhelper::Content aContent( rURL, xEnv, m_xContext );
1182 aContent.openStream();
1183 return aContent.isDocument();
1186 catch( const Exception& )
1188 // a content doesn't exist
1191 return false;
1194 sal_Int32 RemoteFilesDialog::getAvailableWidth()
1196 // This dialog doesn't contain preview
1197 return 0;
1200 sal_Int32 RemoteFilesDialog::getAvailableHeight()
1202 // This dialog doesn't contain preview
1203 return 0;
1206 void RemoteFilesDialog::setImage( const css::uno::Any& )
1208 // This dialog doesn't contain preview
1211 bool RemoteFilesDialog::getShowState()
1213 // This dialog doesn't contain preview
1214 return false;
1217 weld::Widget* RemoteFilesDialog::getControl( sal_Int16, bool) const
1219 return nullptr;
1222 void RemoteFilesDialog::enableControl( sal_Int16, bool )
1226 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */