1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <sal/config.h>
22 #include <sal/log.hxx>
23 #include "fileview.hxx"
25 #include <svtools/PlaceEditDialog.hxx>
26 #include "OfficeControlAccess.hxx"
27 #include "PlacesListBox.hxx"
28 #include <fpicker/fpsofficeResMgr.hxx>
29 #include <tools/debug.hxx>
30 #include <comphelper/diagnose_ex.hxx>
31 #include <tools/stream.hxx>
32 #include <tools/urlobj.hxx>
33 #include <vcl/errinf.hxx>
34 #include <vcl/graph.hxx>
35 #include <vcl/svapp.hxx>
36 #include <vcl/timer.hxx>
37 #include <unotools/ucbhelper.hxx>
38 #include <unotools/pathoptions.hxx>
39 #include <unotools/viewoptions.hxx>
40 #include <svtools/sfxecode.hxx>
42 #include <fpicker/strings.hrc>
43 #include <svtools/helpids.h>
44 #include <strings.hrc>
45 #include "asyncfilepicker.hxx"
46 #include "iodlgimp.hxx"
47 #include <svtools/inettbc.hxx>
48 #include "QueryFolderName.hxx"
49 #include <rtl/ustring.hxx>
50 #include <com/sun/star/ucb/UniversalContentBroker.hpp>
51 #include <com/sun/star/ucb/CommandAbortedException.hpp>
52 #include <com/sun/star/ucb/ContentCreationException.hpp>
53 #include <com/sun/star/ui/dialogs/CommonFilePickerElementIds.hpp>
54 #include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp>
55 #include <com/sun/star/beans/PropertyValue.hpp>
56 #include <com/sun/star/sdbc/XResultSet.hpp>
57 #include <com/sun/star/uno/Exception.hpp>
58 #include <com/sun/star/uno/Reference.hxx>
59 #include <com/sun/star/beans/XPropertySet.hpp>
61 #include <comphelper/interaction.hxx>
62 #include <comphelper/lok.hxx>
63 #include <comphelper/processfactory.hxx>
64 #include <comphelper/string.hxx>
66 #include <osl/file.hxx>
67 #include <vcl/dibtools.hxx>
69 #include <com/sun/star/task/InteractionHandler.hpp>
70 #include <com/sun/star/ucb/InteractiveAugmentedIOException.hpp>
71 #include "fpinteraction.hxx"
72 #include <osl/process.h>
73 #include <o3tl/string_view.hxx>
75 #include <officecfg/Office/Common.hxx>
79 #include <string_view>
81 using namespace ::com::sun::star::beans
;
82 using namespace ::com::sun::star::ui::dialogs
;
83 using namespace ::com::sun::star::uno
;
84 using namespace ::com::sun::star::lang
;
85 using namespace ::com::sun::star::ucb
;
86 using namespace ::com::sun::star::container
;
87 using namespace ::com::sun::star::task
;
88 using namespace ::com::sun::star::sdbc
;
89 using namespace ::utl
;
90 using namespace ::svt
;
92 using namespace ExtendedFilePickerElementIds
;
93 using namespace CommonFilePickerElementIds
;
94 using namespace InternalFilePickerElementIds
;
96 // functions -------------------------------------------------------------
100 OUString
getMostCurrentFilter( std::unique_ptr
<SvtExpFileDlg_Impl
> const & pImpl
)
102 assert( pImpl
&& "invalid impl pointer" );
103 const SvtFileDialogFilter_Impl
* pFilter
= pImpl
->m_xUserFilter
.get();
106 pFilter
= pImpl
->GetCurFilter();
111 return pFilter
->GetType();
114 void restoreCurrentFilter( std::unique_ptr
<SvtExpFileDlg_Impl
> const & pImpl
)
116 SAL_WARN_IF( !pImpl
->GetCurFilter(), "fpicker.office", "restoreCurrentFilter: no current filter!" );
117 SAL_WARN_IF( pImpl
->GetCurFilterDisplayName().isEmpty(), "fpicker.office", "restoreCurrentFilter: no current filter (no display name)!" );
119 pImpl
->SelectFilterListEntry( pImpl
->GetCurFilterDisplayName() );
122 OUString sSelectedDisplayName
;
123 DBG_ASSERT( ( pImpl
->GetSelectedFilterEntry( sSelectedDisplayName
) == pImpl
->GetCurFilter() )
124 && ( sSelectedDisplayName
== pImpl
->GetCurFilterDisplayName() ),
125 "restoreCurrentFilter: inconsistence!" );
130 OUString
GetFsysExtension_Impl( std::u16string_view rFile
, const OUString
& rLastFilterExt
)
132 size_t nDotPos
= rFile
.rfind( '.' );
133 if ( nDotPos
!= std::u16string_view::npos
)
135 if ( !rLastFilterExt
.isEmpty() )
137 if ( o3tl::equalsIgnoreAsciiCase(rFile
.substr( nDotPos
+ 1 ), rLastFilterExt
) )
138 return rLastFilterExt
;
141 return OUString(rFile
.substr( nDotPos
));
147 void SetFsysExtension_Impl( OUString
& rFile
, std::u16string_view rExtension
)
149 const sal_Int32 nDotPos
{ rFile
.lastIndexOf('.') };
152 if (!rExtension
.empty())
153 rFile
= OUString::Concat(rFile
.subView(0, nDotPos
)) + rExtension
; // replace old extension with new (not empty) one
155 rFile
= rFile
.copy(0, nDotPos
-1); // truncate extension (new one is empty)
157 rFile
.clear(); // Filename was just an extension
159 else if (!rExtension
.empty())
160 rFile
+= OUString::Concat(".") + rExtension
;
161 // no extension was present, append new one if not empty
164 void lcl_autoUpdateFileExtension( SvtFileDialog
* _pDialog
, const OUString
& _rLastFilterExt
)
166 // if auto extension is enabled...
167 if ( !_pDialog
->isAutoExtensionEnabled() )
170 // automatically switch to the extension of the (maybe just newly selected) extension
171 OUString aNewFile
= _pDialog
->getCurrentFileText( );
172 OUString aExt
= GetFsysExtension_Impl( aNewFile
, _rLastFilterExt
);
174 // but only if there already is an extension
175 if ( aExt
.isEmpty() )
178 // check if it is a real file extension, and not only the "post-dot" part in
180 bool bRealExtensions
= true;
181 if ( -1 != aExt
.indexOf( '/' ) )
182 bRealExtensions
= false;
183 else if ( -1 != aExt
.indexOf( '\\' ) )
184 bRealExtensions
= false;
187 // no easy way to tell, because the part containing the dot already is the last
188 // segment of the complete file name
189 // So we have to check if the file name denotes a folder or a file.
190 // For performance reasons, we do this for file urls only
191 INetURLObject
aURL( aNewFile
);
192 if ( INetProtocol::NotValid
== aURL
.GetProtocol() )
195 if ( osl::FileBase::getFileURLFromSystemPath( aNewFile
, sURL
)
196 == osl::FileBase::E_None
)
197 aURL
= INetURLObject( sURL
);
199 if ( INetProtocol::File
== aURL
.GetProtocol() )
203 bRealExtensions
= !_pDialog
->ContentIsFolder( aURL
.GetMainURL( INetURLObject::DecodeMechanism::NONE
) );
205 catch( const css::uno::Exception
& )
207 SAL_INFO( "fpicker.office", "Exception in lcl_autoUpdateFileExtension" );
212 if ( bRealExtensions
)
214 SetFsysExtension_Impl( aNewFile
, _pDialog
->GetDefaultExt() );
215 _pDialog
->setCurrentFileText( aNewFile
);
220 bool lcl_getHomeDirectory( const OUString
& _rForURL
, OUString
& /* [out] */ _rHomeDir
)
224 // now ask the content broker for a provider for this scheme
228 // get the provider for the current scheme
229 Reference
< XContentProvider
> xProvider(
230 UniversalContentBroker::create(
231 comphelper::getProcessComponentContext() )->
232 queryContentProvider( _rForURL
) );
234 SAL_WARN_IF( !xProvider
.is(), "fpicker.office", "lcl_getHomeDirectory: could not find a (valid) content provider for the current URL!" );
235 Reference
< XPropertySet
> xProviderProps( xProvider
, UNO_QUERY
);
236 if ( xProviderProps
.is() )
238 Reference
< XPropertySetInfo
> xPropInfo
= xProviderProps
->getPropertySetInfo();
239 static constexpr OUString
sHomeDirPropertyName( u
"HomeDirectory"_ustr
);
240 if ( !xPropInfo
.is() || xPropInfo
->hasPropertyByName( sHomeDirPropertyName
) )
242 OUString sHomeDirectory
;
243 xProviderProps
->getPropertyValue( sHomeDirPropertyName
) >>= sHomeDirectory
;
244 _rHomeDir
= sHomeDirectory
;
248 catch( const Exception
& )
250 TOOLS_WARN_EXCEPTION( "fpicker", "lcl_getHomeDirectory" );
252 return !_rHomeDir
.isEmpty();
256 OUString
lcl_ensureFinalSlash( std::u16string_view _rDir
)
258 INetURLObject
aWorkPathObj( _rDir
, INetProtocol::File
);
259 aWorkPathObj
.setFinalSlash();
260 return aWorkPathObj
.GetMainURL( INetURLObject::DecodeMechanism::NONE
);
264 /** retrieves the value of an environment variable
265 @return <TRUE/> if and only if the retrieved string value is not empty
267 bool getEnvironmentValue( const char* _pAsciiEnvName
, OUString
& _rValue
)
270 OUString sEnvName
= OUString::createFromAscii( _pAsciiEnvName
);
271 osl_getEnvironment( sEnvName
.pData
, &_rValue
.pData
);
272 return !_rValue
.isEmpty();
277 SvtFileDialog::SvtFileDialog(weld::Window
* pParent
, PickerFlags nStyle
)
278 : SvtFileDialog_Base(pParent
, "fps/ui/explorerfiledialog.ui", "ExplorerFileDialog")
279 , m_xCbReadOnly(m_xBuilder
->weld_check_button("readonly"))
280 , m_xCbLinkBox(m_xBuilder
->weld_check_button("link"))
281 , m_xCbPreviewBox(m_xBuilder
->weld_check_button("cb_preview"))
282 , m_xCbSelection(m_xBuilder
->weld_check_button("selection"))
283 , m_xPbPlay(m_xBuilder
->weld_button("play"))
284 , m_xPreviewFrame(m_xBuilder
->weld_widget("previewframe"))
285 , m_xPrevBmp(m_xBuilder
->weld_image("preview"))
286 , m_pFileNotifier(nullptr)
287 , m_xImpl(new SvtExpFileDlg_Impl
)
288 , m_nPickerFlags(nStyle
)
289 , m_bIsInExecute(false)
290 , m_bInExecuteAsync(false)
291 , m_bHasFilename(false)
293 m_xImpl
->m_xCbOptions
= m_xBuilder
->weld_check_button("options");
294 m_xImpl
->m_xFtFileName
= m_xBuilder
->weld_label("file_name_label");
295 m_xImpl
->m_xEdFileName
.reset(new SvtURLBox(m_xBuilder
->weld_combo_box("file_name")));
296 m_xImpl
->m_xFtFileType
= m_xBuilder
->weld_label("file_type_label");
297 m_xImpl
->m_xLbFilter
= m_xBuilder
->weld_combo_box("file_type");
298 m_xImpl
->m_xEdCurrentPath
.reset(new SvtURLBox(m_xBuilder
->weld_combo_box("current_path")));
299 m_xImpl
->m_xBtnFileOpen
= m_xBuilder
->weld_button("open");
300 m_xImpl
->m_xBtnCancel
= m_xBuilder
->weld_button("cancel");
301 m_xImpl
->m_xBtnHelp
= m_xBuilder
->weld_button("help");
302 m_xImpl
->m_xBtnConnectToServer
= m_xBuilder
->weld_button("connect_to_server");
303 m_xImpl
->m_xBtnNewFolder
= m_xBuilder
->weld_button("new_folder");
304 m_xImpl
->m_xCbPassword
= m_xBuilder
->weld_check_button("password");
305 m_xImpl
->m_xCbGPGEncrypt
= m_xBuilder
->weld_check_button("gpgencrypt");
306 m_xImpl
->m_xCbAutoExtension
= m_xBuilder
->weld_check_button("extension");
307 m_xImpl
->m_xSharedLabel
= m_xBuilder
->weld_label("shared_label");
308 m_xImpl
->m_xSharedListBox
= m_xBuilder
->weld_combo_box("shared");
310 // because the "<All Formats> (*.bmp,*...)" entry is too wide,
311 // we need to disable the auto width feature of the filter box
312 int nWidth
= m_xImpl
->m_xLbFilter
->get_approximate_digit_width() * 60;
313 m_xImpl
->m_xSharedListBox
->set_size_request(nWidth
, -1);
314 m_xImpl
->m_xLbFilter
->set_size_request(nWidth
, -1);
316 m_xImpl
->m_xBtnUp
.reset(new SvtUpButton_Impl(m_xBuilder
->weld_toolbar("up_bar"),
317 m_xBuilder
->weld_menu("up_menu"),
319 m_xImpl
->m_xBtnUp
->set_help_id(HID_FILEOPEN_LEVELUP
);
320 m_xImpl
->m_xBtnUp
->show();
322 m_xImpl
->m_nStyle
= nStyle
;
323 m_xImpl
->m_eMode
= ( nStyle
& PickerFlags::SaveAs
) ? FILEDLG_MODE_SAVE
: FILEDLG_MODE_OPEN
;
324 m_xImpl
->m_eDlgType
= FILEDLG_TYPE_FILEDLG
;
326 if (nStyle
& PickerFlags::PathDialog
)
327 m_xImpl
->m_eDlgType
= FILEDLG_TYPE_PATHDLG
;
329 // Set the directory for the "back to the default dir" button
330 INetURLObject
aStdDirObj( SvtPathOptions().GetWorkPath() );
331 SetStandardDir( aStdDirObj
.GetMainURL( INetURLObject::DecodeMechanism::NONE
) );
333 // Create control element, the order defines the tab control.
334 m_xImpl
->m_xEdFileName
->connect_changed( LINK( this, SvtFileDialog
, EntrySelectHdl_Impl
) );
335 m_xImpl
->m_xEdFileName
->connect_entry_activate( LINK( this, SvtFileDialog
, OpenUrlHdl_Impl
) );
337 // in folder picker mode, only auto-complete directories (no files)
338 bool bIsFolderPicker
= m_xImpl
->m_eDlgType
== FILEDLG_TYPE_PATHDLG
;
339 m_xImpl
->m_xEdFileName
->SetOnlyDirectories( bIsFolderPicker
);
341 // in save mode, don't use the autocompletion as selection in the edit part
342 bool bSaveMode
= FILEDLG_MODE_SAVE
== m_xImpl
->m_eMode
;
343 m_xImpl
->m_xEdFileName
->SetNoURLSelection( bSaveMode
);
345 if (nStyle
& PickerFlags::MultiSelection
)
346 m_xImpl
->m_bMultiSelection
= true;
348 m_xContainer
= m_xBuilder
->weld_container("container");
349 m_xContainer
->set_size_request(m_xContainer
->get_approximate_digit_width() * 95, -1);
351 m_xFileView
.reset(new SvtFileView(m_xDialog
.get(),
352 m_xBuilder
->weld_tree_view("fileview"),
353 m_xBuilder
->weld_icon_view("iconview"),
354 FILEDLG_TYPE_PATHDLG
== m_xImpl
->m_eDlgType
,
355 m_xImpl
->m_bMultiSelection
));
356 m_xFileView
->set_help_id( HID_FILEDLG_STANDARD
);
358 if ( nStyle
& PickerFlags::ReadOnly
)
360 m_xCbReadOnly
->set_help_id( HID_FILEOPEN_READONLY
);
361 m_xCbReadOnly
->set_label( FpsResId( STR_SVT_FILEPICKER_READONLY
) );
362 m_xCbReadOnly
->connect_toggled( LINK( this, SvtFileDialog
, ClickHdl_Impl
) );
363 m_xCbReadOnly
->show();
366 if ( nStyle
& PickerFlags::Password
)
368 m_xImpl
->m_xCbPassword
->set_label( FpsResId( STR_SVT_FILEPICKER_PASSWORD
) );
369 m_xImpl
->m_xCbPassword
->connect_toggled( LINK( this, SvtFileDialog
, ClickHdl_Impl
) );
370 m_xImpl
->m_xCbPassword
->show();
371 m_xImpl
->m_xCbGPGEncrypt
->connect_toggled( LINK( this, SvtFileDialog
, ClickHdl_Impl
) );
372 m_xImpl
->m_xCbGPGEncrypt
->show();
375 // set the ini file for extracting the size
376 m_xImpl
->m_aIniKey
= "FileDialog";
380 // adjust the labels to the mode
381 TranslateId pResId
= STR_EXPLORERFILE_OPEN
;
382 TranslateId pButtonResId
;
384 if ( nStyle
& PickerFlags::SaveAs
)
386 pResId
= STR_EXPLORERFILE_SAVE
;
387 pButtonResId
= STR_EXPLORERFILE_BUTTONSAVE
;
390 if ( nStyle
& PickerFlags::PathDialog
)
392 m_xImpl
->m_xFtFileName
->set_label( FpsResId( STR_PATHNAME
) );
393 pResId
= STR_PATHSELECT
;
394 pButtonResId
= STR_BUTTONSELECT
;
397 m_xDialog
->set_title(FpsResId(pResId
));
400 m_xImpl
->m_xBtnFileOpen
->set_label( FpsResId( pButtonResId
) );
402 if ( FILEDLG_TYPE_FILEDLG
!= m_xImpl
->m_eDlgType
)
404 m_xImpl
->m_xFtFileType
->hide();
405 m_xImpl
->GetFilterListControl()->hide();
408 // Setting preferences of the control elements.
409 m_xImpl
->m_xBtnNewFolder
->connect_clicked( LINK( this, SvtFileDialog
, NewFolderHdl_Impl
) );
410 m_xImpl
->m_xBtnFileOpen
->connect_clicked( LINK( this, SvtFileDialog
, OpenClickHdl_Impl
) );
411 m_xImpl
->m_xBtnCancel
->connect_clicked( LINK( this, SvtFileDialog
, CancelHdl_Impl
) );
412 m_xImpl
->SetFilterListSelectHdl( LINK( this, SvtFileDialog
, FilterSelectHdl_Impl
) );
413 m_xImpl
->m_xEdFileName
->connect_focus_in( LINK( this, SvtFileDialog
, FileNameGetFocusHdl_Impl
) );
414 m_xImpl
->m_xEdFileName
->connect_changed( LINK( this, SvtFileDialog
, FileNameModifiedHdl_Impl
) );
415 m_xImpl
->m_xEdCurrentPath
->connect_entry_activate( LINK( this, SvtFileDialog
, URLBoxModifiedHdl_Impl
) );
416 m_xImpl
->m_xBtnConnectToServer
->connect_clicked( LINK ( this, SvtFileDialog
, ConnectToServerPressed_Hdl
) );
418 m_xFileView
->SetSelectHdl( LINK( this, SvtFileDialog
, SelectHdl_Impl
) );
419 m_xFileView
->SetDoubleClickHdl( LINK( this, SvtFileDialog
, DblClickHdl_Impl
) );
420 m_xFileView
->SetOpenDoneHdl( LINK( this, SvtFileDialog
, OpenDoneHdl_Impl
) );
422 // set timer for the filterbox travel
423 m_xImpl
->m_aFilterIdle
.SetPriority(TaskPriority::LOWEST
);
424 m_xImpl
->m_aFilterIdle
.SetInvokeHandler( LINK( this, SvtFileDialog
, FilterSelectTimerHdl_Impl
) );
426 if ( PickerFlags::SaveAs
& nStyle
)
428 // different help ids if in save-as mode
429 m_xDialog
->set_help_id( HID_FILESAVE_DIALOG
);
431 m_xImpl
->m_xEdFileName
->set_help_id( HID_FILESAVE_FILEURL
);
432 m_xImpl
->m_xBtnFileOpen
->set_help_id( HID_FILESAVE_DOSAVE
);
433 m_xImpl
->m_xBtnNewFolder
->set_help_id( HID_FILESAVE_CREATEDIRECTORY
);
434 m_xImpl
->m_xBtnUp
->set_help_id( HID_FILESAVE_LEVELUP
);
435 m_xImpl
->GetFilterListControl()->set_help_id( HID_FILESAVE_FILETYPE
);
436 m_xFileView
->set_help_id( HID_FILESAVE_FILEVIEW
);
438 // formerly, there was only _pLbFileVersion, which was used for 3 different
439 // use cases. For reasons of maintainability, I introduced extra members (_pLbTemplates, _pLbImageTemplates)
440 // for the extra use cases, and separated _pLbFileVersion
441 // I did not find out in which cases the help ID is really needed HID_FILESAVE_TEMPLATE - all
442 // tests I made lead to a dialog where _no_ of the three list boxes was present.
443 if (m_xImpl
->m_xSharedListBox
)
444 m_xImpl
->m_xSharedListBox
->set_help_id( HID_FILESAVE_TEMPLATE
);
446 if ( m_xImpl
->m_xCbPassword
) m_xImpl
->m_xCbPassword
->set_help_id( HID_FILESAVE_SAVEWITHPASSWORD
);
447 if ( m_xImpl
->m_xCbAutoExtension
) m_xImpl
->m_xCbAutoExtension
->set_help_id( HID_FILESAVE_AUTOEXTENSION
);
448 if ( m_xImpl
->m_xCbOptions
) m_xImpl
->m_xCbOptions
->set_help_id( HID_FILESAVE_CUSTOMIZEFILTER
);
449 if ( m_xCbSelection
) m_xCbSelection
->set_help_id( HID_FILESAVE_SELECTION
);
452 /// read our settings from the configuration
453 m_aConfiguration
= OConfigurationTreeRoot::createWithComponentContext(
454 ::comphelper::getProcessComponentContext(),
455 "/org.openoffice.Office.UI/FilePicker"
458 m_xDialog
->connect_size_allocate(LINK(this, SvtFileDialog
, SizeAllocHdl
));
459 SizeAllocHdl(Size());
461 m_xImpl
->m_xEdFileName
->grab_focus();
464 SvtFileDialog::~SvtFileDialog()
466 if (!m_xImpl
->m_aIniKey
.isEmpty())
469 SvtViewOptions
aDlgOpt( EViewType::Dialog
, m_xImpl
->m_aIniKey
);
470 aDlgOpt
.SetWindowState(m_xDialog
->get_window_state(vcl::WindowDataMask::All
));
471 OUString sUserData
= m_xFileView
->GetConfigString();
472 aDlgOpt
.SetUserItem( "UserData",
476 m_xFileView
->SetSelectHdl(Link
<SvtFileView
*,void>());
478 // Save bookmarked places
479 if (!m_xImpl
->m_xPlaces
->IsUpdated())
482 const std::vector
<PlacePtr
> aPlaces
= m_xImpl
->m_xPlaces
->GetPlaces();
483 Sequence
< OUString
> placesUrlsList(m_xImpl
->m_xPlaces
->GetNbEditablePlaces());
484 auto placesUrlsListRange
= asNonConstRange(placesUrlsList
);
485 Sequence
< OUString
> placesNamesList(m_xImpl
->m_xPlaces
->GetNbEditablePlaces());
486 auto placesNamesListRange
= asNonConstRange(placesNamesList
);
488 for (auto const& place
: aPlaces
)
490 if(place
->IsEditable()) {
491 placesUrlsListRange
[i
] = place
->GetUrl();
492 placesNamesListRange
[i
] = place
->GetName();
497 std::shared_ptr
<comphelper::ConfigurationChanges
> batch(comphelper::ConfigurationChanges::create());
498 officecfg::Office::Common::Misc::FilePickerPlacesUrls::set(placesUrlsList
, batch
);
499 officecfg::Office::Common::Misc::FilePickerPlacesNames::set(placesNamesList
, batch
);
503 IMPL_LINK_NOARG(SvtFileDialog
, NewFolderHdl_Impl
, weld::Button
&, void)
505 m_xFileView
->EndInplaceEditing();
507 SmartContent
aContent( m_xFileView
->GetViewURL( ) );
509 aContent
.getTitle( aTitle
);
510 QueryFolderNameDialog
aDlg(m_xDialog
.get(), aTitle
, FpsResId(STR_SVT_NEW_FOLDER
));
511 bool bHandled
= false;
515 if (aDlg
.run() == RET_OK
)
517 OUString aUrl
= aContent
.createFolder(aDlg
.GetName());
518 if ( !aUrl
.isEmpty( ) )
520 m_xFileView
->CreatedFolder(aUrl
, aDlg
.GetName());
529 void SvtFileDialog::createNewUserFilter( const OUString
& _rNewFilter
)
531 // delete the old user filter and create a new one
532 m_xImpl
->m_xUserFilter
.reset( new SvtFileDialogFilter_Impl( _rNewFilter
, _rNewFilter
) );
534 // remember the extension
535 bool bIsAllFiles
= _rNewFilter
== FILEDIALOG_FILTER_ALL
;
539 SetDefaultExt( _rNewFilter
.copy( 2 ) );
540 // TODO: this is nonsense. In the whole file there are a lot of places where we assume that a user filter
541 // is always "*.<something>". But changing this would take some more time than I have now...
543 // now, the default extension is set to the one of the user filter (or empty)
544 if ( m_xImpl
->GetCurFilter( ) )
545 SetDefaultExt( m_xImpl
->GetCurFilter( )->GetExtension() );
551 AdjustFilterFlags
SvtFileDialog::adjustFilter( const OUString
& rFilter
)
553 AdjustFilterFlags nReturn
= AdjustFilterFlags::NONE
;
555 const bool bNonEmpty
= !rFilter
.isEmpty();
558 nReturn
|= AdjustFilterFlags::NonEmpty
;
560 bool bFilterChanged
= true;
562 // search for a corresponding filter
563 SvtFileDialogFilter_Impl
* pFilter
= FindFilter_Impl( rFilter
, false, bFilterChanged
);
565 // look for multi-ext filters if necessary
567 pFilter
= FindFilter_Impl( rFilter
, true, bFilterChanged
);
569 if ( bFilterChanged
)
570 nReturn
|= AdjustFilterFlags::Changed
;
574 nReturn
|= AdjustFilterFlags::UserFilter
;
575 // no filter found : use it as user defined filter
576 createNewUserFilter( rFilter
);
583 IMPL_LINK_NOARG(SvtFileDialog
, CancelHdl_Impl
, weld::Button
&, void)
585 if ( m_pCurrentAsyncAction
.is() )
587 m_pCurrentAsyncAction
->cancel();
588 onAsyncOperationFinished();
592 m_xDialog
->response(RET_CANCEL
);
596 IMPL_LINK( SvtFileDialog
, OpenClickHdl_Impl
, weld::Button
&, rVoid
, void )
598 OpenHdl_Impl(&rVoid
);
601 IMPL_LINK( SvtFileDialog
, OpenUrlHdl_Impl
, weld::ComboBox
&, rVoid
, bool )
603 OpenHdl_Impl(&rVoid
);
607 void SvtFileDialog::OpenHdl_Impl(void const * pVoid
)
609 if ( m_xImpl
->m_bMultiSelection
&& m_xFileView
->GetSelectionCount() > 1 )
611 // special open in case of multiselection
612 OpenMultiSelection_Impl();
617 OUString
aOldPath(m_xFileView
->GetViewURL());
618 if ( m_xImpl
->m_bDoubleClick
|| m_xFileView
->has_focus() )
620 // Selection done by doubleclicking in the view, get filename from the view
621 aFileName
= m_xFileView
->GetCurrentURL();
624 if ( aFileName
.isEmpty() )
626 // if an entry is selected in the view...
627 if ( m_xFileView
->GetSelectionCount() )
628 { // -> use this one. This will allow us to step down this folder
629 aFileName
= m_xFileView
->GetCurrentURL();
633 if ( aFileName
.isEmpty() )
635 // get the URL from the edit field ( if not empty )
636 if ( !m_xImpl
->m_xEdFileName
->get_active_text().isEmpty() )
638 OUString aText
= m_xImpl
->m_xEdFileName
->get_active_text();
640 // did we reach the root?
641 if ( !INetURLObject( aOldPath
).getSegmentCount() )
643 if ( ( aText
.getLength() == 2 && aText
== ".." ) ||
644 ( aText
.getLength() == 3 && ( aText
== "..\\" || aText
== "../" ) ) )
645 // don't go higher than the root
650 if ( ( 1 == aText
.getLength() ) && ( '~' == aText
[0] ) )
652 // go to the home directory
653 if ( lcl_getHomeDirectory( m_xFileView
->GetViewURL(), aFileName
) )
654 // in case we got a home dir, reset the text of the edit
655 m_xImpl
->m_xEdFileName
->set_entry_text( OUString() );
657 if ( aFileName
.isEmpty() )
660 // get url from autocomplete edit
661 aFileName
= m_xImpl
->m_xEdFileName
->GetURL();
664 else if ( pVoid
== m_xImpl
->m_xBtnFileOpen
.get() )
665 // OpenHdl was called for the "Open" Button; if edit field is empty, use selected element in the view
666 aFileName
= m_xFileView
->GetCurrentURL();
670 if ( aFileName
.isEmpty() && pVoid
== m_xImpl
->m_xEdFileName
.get() && m_xImpl
->m_xUserFilter
)
672 m_xImpl
->m_xUserFilter
.reset();
676 sal_Int32 nLen
= aFileName
.getLength();
679 // if the dialog was opened to select a folder, the last selected folder should be selected
680 if( m_xImpl
->m_eDlgType
== FILEDLG_TYPE_PATHDLG
)
682 aFileName
= m_xImpl
->m_xEdCurrentPath
->get_active_text();
683 nLen
= aFileName
.getLength();
686 // no file selected !
690 // mark input as selected
691 m_xImpl
->m_xEdFileName
->select_entry_region(0, nLen
);
693 // if a path with wildcards is given, divide the string into path and wildcards
695 if ( !SvtFileDialog::IsolateFilterFromPath_Impl( aFileName
, aFilter
) )
698 // if a filter was retrieved, there were wildcards !
699 AdjustFilterFlags nNewFilterFlags
= adjustFilter( aFilter
);
700 if ( nNewFilterFlags
& AdjustFilterFlags::Changed
)
702 // cut off all text before wildcard in edit and select wildcard
703 m_xImpl
->m_xEdFileName
->set_entry_text( aFilter
);
704 m_xImpl
->m_xEdFileName
->select_entry_region(0, -1);
708 INetURLObject
aFileObject( aFileName
);
709 if ( ( aFileObject
.GetProtocol() == INetProtocol::NotValid
) && !aFileName
.isEmpty() )
711 OUString sCompleted
= SvtURLBox::ParseSmart( aFileName
, m_xFileView
->GetViewURL() );
712 if ( !sCompleted
.isEmpty() )
713 aFileName
= sCompleted
;
717 // check if it is a folder
718 bool bIsFolder
= false;
720 // first thing before doing anything with the content: Reset it. When the user presses "open" (or "save" or "export",
721 // for that matter), s/he wants the complete handling, including all possible error messages, even if s/he
722 // does the same thing for the same content twice, s/he wants both fails to be displayed.
723 // Without the reset, it could be that the content cached all relevant information, and will not display any
724 // error messages for the same content a second time...
725 m_aContent
.bindTo( OUString( ) );
727 if ( !aFileName
.isEmpty() )
729 // Make sure we have own Interaction Handler in place. We do not need
730 // to intercept interactions here, but to record the fact that there
731 // was an interaction.
732 SmartContent::InteractionHandlerType eInterActionHandlerType
733 = m_aContent
.queryCurrentInteractionHandler();
734 if ( ( eInterActionHandlerType
== SmartContent::IHT_NONE
) ||
735 ( eInterActionHandlerType
== SmartContent::IHT_DEFAULT
) )
736 m_aContent
.enableOwnInteractionHandler(
737 OFilePickerInteractionHandler::E_NOINTERCEPTION
);
739 bIsFolder
= m_aContent
.isFolder( aFileName
);
741 // access denied to the given resource - and interaction was already
742 // used => break following operations
743 OFilePickerInteractionHandler
* pHandler
744 = m_aContent
.getOwnInteractionHandler();
746 OSL_ENSURE( pHandler
, "Got no Interaction Handler!!!" );
748 if ( pHandler
->wasAccessDenied() )
751 if ( m_aContent
.isInvalid() &&
752 ( m_xImpl
->m_eMode
== FILEDLG_MODE_OPEN
) )
754 if ( !pHandler
->wasUsed() )
755 ErrorHandler::HandleError( ERRCODE_IO_NOTEXISTS
);
760 // restore previous Interaction Handler
761 if ( eInterActionHandlerType
== SmartContent::IHT_NONE
)
762 m_aContent
.disableInteractionHandler();
763 else if ( eInterActionHandlerType
== SmartContent::IHT_DEFAULT
)
764 m_aContent
.enableDefaultInteractionHandler();
767 if ( !bIsFolder
// no existent folder
768 && m_xImpl
->m_xCbAutoExtension
// auto extension is enabled in general
769 && m_xImpl
->m_xCbAutoExtension
->get_active()// auto extension is really to be used
770 && !GetDefaultExt().isEmpty() // there is a default extension
771 && GetDefaultExt() != "*" // the default extension is not "all"
772 && !( FILEDLG_MODE_SAVE
== m_xImpl
->m_eMode
// we're saving a file
773 && m_xFileView
->GetSelectionCount() // there is a selected file in the file view -> it will later on
774 ) // (in SvtFileDialog::GetPathList) be taken as file to save to
776 && FILEDLG_MODE_OPEN
!= m_xImpl
->m_eMode
// #i83408# don't append extension on open
779 // check extension and append the default extension if necessary
780 appendDefaultExtension(aFileName
,
782 m_xImpl
->GetCurFilter()->GetType());
785 bool bOpenFolder
= ( FILEDLG_TYPE_PATHDLG
== m_xImpl
->m_eDlgType
) &&
786 !m_xImpl
->m_bDoubleClick
&& pVoid
!= m_xImpl
->m_xEdFileName
.get();
795 if ( aFileName
!= m_xFileView
->GetViewURL() )
797 OpenURL_Impl( aFileName
);
801 if ( nNewFilterFlags
& AdjustFilterFlags::Changed
)
808 else if ( !( nNewFilterFlags
& AdjustFilterFlags::NonEmpty
) )
810 // if applicable save URL
815 // if applicable filter again
816 if ( nNewFilterFlags
& AdjustFilterFlags::Changed
)
821 INetURLObject
aFileObj( aFileName
);
822 if ( aFileObj
.HasError() )
824 ErrorHandler::HandleError( ERRCODE_IO_GENERAL
);
828 switch (m_xImpl
->m_eMode
)
830 case FILEDLG_MODE_SAVE
:
832 if ( ::utl::UCBContentHelper::Exists( aFileObj
.GetMainURL( INetURLObject::DecodeMechanism::NONE
) ) )
834 OUString aMsg
= FpsResId(STR_SVT_ALREADYEXISTOVERWRITE
);
835 aMsg
= aMsg
.replaceFirst(
837 aFileObj
.getName(INetURLObject::LAST_SEGMENT
, true, INetURLObject::DecodeMechanism::WithCharset
)
839 std::unique_ptr
<weld::MessageDialog
> xBox(Application::CreateMessageDialog(m_xDialog
.get(),
840 VclMessageType::Question
, VclButtonsType::YesNo
, aMsg
));
841 if (xBox
->run() != RET_YES
)
847 if (osl::FileBase::getSystemPathFromFileURL(aFileName
, aCurPath
) == osl::FileBase::E_None
)
849 // if content does not exist: at least its path must exist
850 INetURLObject aPathObj
= aFileObj
;
851 aPathObj
.removeSegment();
852 bool bFolder
= m_aContent
.isFolder( aPathObj
.GetMainURL( INetURLObject::DecodeMechanism::NONE
) );
855 ErrorHandler::HandleError( ERRCODE_IO_NOTEXISTSPATH
);
863 case FILEDLG_MODE_OPEN
:
865 // do an existence check herein, again
867 if ( INetProtocol::File
== aFileObj
.GetProtocol( ) )
869 bool bExists
= m_aContent
.is( aFileObj
.GetMainURL( INetURLObject::DecodeMechanism::NONE
) );
873 OUString
sError(FpsResId(RID_FILEOPEN_NOTEXISTENTFILE
));
875 OUString
sInvalidFile( aFileObj
.GetMainURL( INetURLObject::DecodeMechanism::ToIUri
) );
876 if ( INetProtocol::File
== aFileObj
.GetProtocol() )
877 { // if it's a file URL, transform the URL into system notation
878 OUString
sURL( sInvalidFile
);
880 osl_getSystemPathFromFileURL( sURL
.pData
, &sSystem
.pData
);
881 sInvalidFile
= sSystem
;
883 sError
= sError
.replaceFirst( "$name$", sInvalidFile
);
885 std::unique_ptr
<weld::MessageDialog
> xBox(Application::CreateMessageDialog(m_xDialog
.get(),
886 VclMessageType::Warning
, VclButtonsType::Ok
, sError
));
895 OSL_FAIL("SvtFileDialog, OpenHdl_Impl: invalid mode!");
898 m_xDialog
->response(RET_OK
);
901 void SvtFileDialog::EnableAutocompletion(bool bEnable
)
903 m_xImpl
->m_xEdFileName
->EnableAutocomplete(bEnable
);
906 IMPL_LINK_NOARG( SvtFileDialog
, FilterSelectHdl_Impl
, weld::ComboBox
&, void )
908 OUString sSelectedFilterDisplayName
;
909 SvtFileDialogFilter_Impl
* pSelectedFilter
= m_xImpl
->GetSelectedFilterEntry( sSelectedFilterDisplayName
);
910 if ( !pSelectedFilter
)
911 { // there is no current selection. This happens if for instance the user selects a group separator using
912 // the keyboard, and then presses enter: When the selection happens, we immediately deselect the entry,
913 // so in this situation there is no current selection.
914 restoreCurrentFilter( m_xImpl
);
918 if ( ( pSelectedFilter
!= m_xImpl
->GetCurFilter() )
919 || m_xImpl
->m_xUserFilter
922 // Store the old filter for the auto extension handling
923 OUString sLastFilterExt
= m_xImpl
->GetCurFilter()->GetExtension();
924 m_xImpl
->m_xUserFilter
.reset();
926 // if applicable remove filter of the user
927 m_xImpl
->SetCurFilter( pSelectedFilter
, sSelectedFilterDisplayName
);
929 // if applicable show extension
930 SetDefaultExt( pSelectedFilter
->GetExtension() );
931 sal_Int32 nSepPos
= GetDefaultExt().indexOf( FILEDIALOG_DEF_EXTSEP
);
934 EraseDefaultExt( nSepPos
);
936 // update the extension of the current file if necessary
937 lcl_autoUpdateFileExtension( this, sLastFilterExt
);
939 // if the user is traveling fast through the filterbox
940 // do not filter instantly
941 // FilterSelectHdl_Impl should be started again at idle
942 m_xImpl
->m_aFilterIdle
.Start();
947 IMPL_LINK_NOARG(SvtFileDialog
, FilterSelectTimerHdl_Impl
, Timer
*, void)
949 // filter the view again
953 IMPL_LINK_NOARG( SvtFileDialog
, FileNameGetFocusHdl_Impl
, weld::Widget
&, void )
955 m_xFileView
->SetNoSelection();
958 IMPL_LINK( SvtFileDialog
, FileNameModifiedHdl_Impl
, weld::ComboBox
&, rComboBox
, void )
960 FileNameGetFocusHdl_Impl(rComboBox
);
963 IMPL_LINK_NOARG(SvtFileDialog
, URLBoxModifiedHdl_Impl
, weld::ComboBox
&, bool)
965 OUString aPath
= m_xImpl
->m_xEdCurrentPath
->GetURL();
970 IMPL_LINK_NOARG( SvtFileDialog
, ConnectToServerPressed_Hdl
, weld::Button
&, void )
972 m_xFileView
->EndInplaceEditing();
974 PlaceEditDialog
aDlg(m_xDialog
.get());
975 short aRetCode
= aDlg
.run();
980 PlacePtr newPlace
= aDlg
.GetPlace();
981 m_xImpl
->m_xPlaces
->AppendPlace(newPlace
);
992 IMPL_LINK_NOARG ( SvtFileDialog
, AddPlacePressed_Hdl
, weld::Button
&, void )
994 // Maybe open the PlacesDialog would have been a better idea
995 // there is an ux choice to make we did not make...
996 INetURLObject
aURLObj( m_xFileView
->GetViewURL() );
998 std::make_shared
<Place
>( aURLObj
.GetLastName(INetURLObject::DecodeMechanism::WithCharset
),
999 m_xFileView
->GetViewURL(), true);
1000 m_xImpl
->m_xPlaces
->AppendPlace(newPlace
);
1003 IMPL_LINK_NOARG ( SvtFileDialog
, RemovePlacePressed_Hdl
, weld::Button
&, void )
1005 m_xImpl
->m_xPlaces
->RemoveSelectedPlace();
1008 SvtFileDialogFilter_Impl
* SvtFileDialog::FindFilter_Impl
1010 const OUString
& rFilter
,
1011 bool bMultiExt
,/* TRUE - regard filter with several extensions
1014 bool& rFilterChanged
1019 This method looks for the specified extension in the included filters.
1023 SvtFileDialogFilter_Impl
* pFoundFilter
= nullptr;
1024 SvtFileDialogFilterList_Impl
& rList
= m_xImpl
->m_aFilter
;
1025 sal_uInt16 nFilter
= rList
.size();
1029 SvtFileDialogFilter_Impl
* pFilter
= rList
[ nFilter
].get();
1030 const OUString
& rType
= pFilter
->GetType();
1035 while ( !pFoundFilter
&& nIdx
!= -1 )
1037 const OUString aSingleType
= rType
.getToken( 0, FILEDIALOG_DEF_EXTSEP
, nIdx
);
1039 if ( aSingleType
== rFilter
)
1041 if ( aSingleType
.equalsIgnoreAsciiCase( rFilter
) )
1043 pFoundFilter
= pFilter
;
1047 else if ( rType
== rFilter
)
1049 else if ( rType
.equalsIgnoreAsciiCase( rFilter
) )
1051 pFoundFilter
= pFilter
;
1056 rFilterChanged
= m_xImpl
->m_xUserFilter
|| ( m_xImpl
->GetCurFilter() != pFilter
);
1058 createNewUserFilter( rFilter
);
1063 return pFoundFilter
;
1067 void SvtFileDialog::ExecuteFilter()
1069 executeAsync( AsyncPickerAction::eExecuteFilter
, OUString(), getMostCurrentFilter(m_xImpl
) );
1074 OpenHandler for MultiSelection
1076 void SvtFileDialog::OpenMultiSelection_Impl()
1078 SvtContentEntry
* pEntry
= m_xFileView
->FirstSelected();
1081 m_aPath
= pEntry
->maURL
;
1083 m_xDialog
->response(RET_OK
);
1086 void SvtFileDialog::UpdateControls( const OUString
& rURL
)
1088 m_xImpl
->m_xEdFileName
->SetBaseURL( rURL
);
1090 INetURLObject
aObj( rURL
);
1094 SAL_WARN_IF( INetProtocol::NotValid
== aObj
.GetProtocol(), "fpicker.office", "SvtFileDialog::UpdateControls: Invalid URL!" );
1096 if ( aObj
.getSegmentCount() )
1098 osl::FileBase::getSystemPathFromFileURL(rURL
, sText
);
1099 if ( !sText
.isEmpty() )
1101 // no Fsys path for server file system ( only UCB has mountpoints! )
1102 if ( INetProtocol::File
!= aObj
.GetProtocol() )
1103 sText
= rURL
.copy( INetURLObject::GetScheme( aObj
.GetProtocol() ).getLength() );
1106 if ( sText
.isEmpty() && aObj
.getSegmentCount() )
1111 if ( FILEDLG_TYPE_PATHDLG
== m_xImpl
->m_eDlgType
)
1112 // -> set new path in the edit field
1113 m_xImpl
->m_xEdFileName
->set_entry_text( sText
);
1115 // in the "current path" field, truncate the trailing slash
1116 if ( aObj
.hasFinalSlash() )
1118 aObj
.removeFinalSlash();
1119 OUString
sURL( aObj
.GetMainURL( INetURLObject::DecodeMechanism::NONE
) );
1120 if (osl::FileBase::getSystemPathFromFileURL(sURL
, sText
) != osl::FileBase::E_None
)
1124 if ( sText
.isEmpty() && !rURL
.isEmpty() )
1125 // happens, for instance, for URLs which the INetURLObject does not know to belong to a hierarchical scheme
1127 m_xImpl
->m_xEdCurrentPath
->set_entry_text(sText
);
1132 m_xImpl
->m_xBtnUp
->FillURLMenu();
1134 if (m_pFileNotifier
)
1135 m_pFileNotifier
->notify( DIRECTORY_CHANGED
, 0 );
1138 IMPL_LINK( SvtFileDialog
, SelectHdl_Impl
, SvtFileView
*, pBox
, void )
1140 SvtContentEntry
* pUserData
= pBox
->FirstSelected();
1143 INetURLObject
aObj( pUserData
->maURL
);
1144 if ( FILEDLG_TYPE_PATHDLG
== m_xImpl
->m_eDlgType
)
1146 if ( aObj
.GetProtocol() == INetProtocol::File
)
1148 if ( !pUserData
->mbIsFolder
)
1149 aObj
.removeSegment();
1150 OUString aName
= aObj
.getFSysPath( static_cast<FSysStyle
>(FSysStyle::Detect
& ~FSysStyle::Vos
) );
1151 m_xImpl
->m_xEdFileName
->set_entry_text( aName
);
1152 m_xImpl
->m_xEdFileName
->select_entry_region(0, -1);
1153 m_aPath
= pUserData
->maURL
;
1155 else if ( !pUserData
->mbIsFolder
)
1157 m_xImpl
->m_xEdFileName
->set_entry_text( pUserData
->maURL
);
1158 m_xImpl
->m_xEdFileName
->select_entry_region(0, -1);
1159 m_aPath
= pUserData
->maURL
;
1162 m_xImpl
->m_xEdFileName
->set_entry_text( OUString() );
1166 if ( !pUserData
->mbIsFolder
)
1168 OUString aName
= pBox
->get_selected_text();
1169 m_xImpl
->m_xEdFileName
->set_entry_text( aName
);
1170 m_xImpl
->m_xEdFileName
->select_entry_region(0, -1);
1171 m_aPath
= pUserData
->maURL
;
1176 if ( m_xImpl
->m_bMultiSelection
&& m_xFileView
->GetSelectionCount() > 1 )
1178 // clear the file edit for multiselection
1179 m_xImpl
->m_xEdFileName
->set_entry_text( OUString() );
1185 IMPL_LINK_NOARG(SvtFileDialog
, DblClickHdl_Impl
, SvtFileView
*, bool)
1187 m_xImpl
->m_bDoubleClick
= true;
1188 OpenHdl_Impl( nullptr );
1189 m_xImpl
->m_bDoubleClick
= false;
1193 IMPL_LINK_NOARG(SvtFileDialog
, EntrySelectHdl_Impl
, weld::ComboBox
&, void)
1198 IMPL_LINK( SvtFileDialog
, OpenDoneHdl_Impl
, SvtFileView
*, pView
, void )
1200 const OUString
& sCurrentFolder( pView
->GetViewURL() );
1201 // check if we can create new folders
1202 EnableControl( m_xImpl
->m_xBtnNewFolder
.get(), ContentCanMakeFolder( sCurrentFolder
) );
1204 // check if we can travel one level up
1205 bool bCanTravelUp
= ContentHasParentFolder( pView
->GetViewURL() );
1208 // additional check: the parent folder should not be prohibited
1209 INetURLObject
aCurrentFolder( sCurrentFolder
);
1210 SAL_WARN_IF( INetProtocol::NotValid
== aCurrentFolder
.GetProtocol(),
1211 "fpicker.office", "SvtFileDialog::OpenDoneHdl_Impl: invalid current URL!" );
1213 aCurrentFolder
.removeSegment();
1215 EnableControl( m_xImpl
->m_xBtnUp
->getWidget(), bCanTravelUp
);
1218 IMPL_LINK_NOARG(SvtFileDialog
, AutoExtensionHdl_Impl
, weld::Toggleable
&, void)
1220 if (m_pFileNotifier
)
1221 m_pFileNotifier
->notify(CTRL_STATE_CHANGED
, CHECKBOX_AUTOEXTENSION
);
1223 // update the extension of the current file if necessary
1224 lcl_autoUpdateFileExtension( this, m_xImpl
->GetCurFilter()->GetExtension() );
1227 IMPL_LINK( SvtFileDialog
, ClickHdl_Impl
, weld::Toggleable
&, rCheckBox
, void )
1229 if (!m_pFileNotifier
)
1234 if ( &rCheckBox
== m_xImpl
->m_xCbOptions
.get() )
1235 nId
= CHECKBOX_FILTEROPTIONS
;
1236 else if ( &rCheckBox
== m_xCbSelection
.get() )
1237 nId
= CHECKBOX_SELECTION
;
1238 else if ( &rCheckBox
== m_xCbReadOnly
.get() )
1239 nId
= CHECKBOX_READONLY
;
1240 else if ( &rCheckBox
== m_xImpl
->m_xCbPassword
.get() )
1241 nId
= CHECKBOX_PASSWORD
;
1242 else if ( &rCheckBox
== m_xImpl
->m_xCbGPGEncrypt
.get() )
1243 nId
= CHECKBOX_GPGENCRYPTION
;
1244 else if ( &rCheckBox
== m_xCbLinkBox
.get() )
1245 nId
= CHECKBOX_LINK
;
1246 else if ( &rCheckBox
== m_xCbPreviewBox
.get() )
1247 nId
= CHECKBOX_PREVIEW
;
1250 m_pFileNotifier
->notify( CTRL_STATE_CHANGED
, nId
);
1253 IMPL_LINK_NOARG(SvtFileDialog
, PlayButtonHdl_Impl
, weld::Button
&, void)
1255 if (m_pFileNotifier
)
1256 m_pFileNotifier
->notify(CTRL_STATE_CHANGED
, PUSHBUTTON_PLAY
);
1262 bool implIsInvalid( const OUString
& rURL
)
1264 SmartContent
aContent( rURL
);
1265 aContent
.enableOwnInteractionHandler( ::svt::OFilePickerInteractionHandler::E_DOESNOTEXIST
);
1266 aContent
.isFolder(); // do this _before_ asking isInvalid! Otherwise result might be wrong.
1267 return aContent
.isInvalid();
1273 OUString
SvtFileDialog::implGetInitialURL( const OUString
& _rPath
, std::u16string_view _rFallback
)
1275 // a URL parser for the fallback
1276 INetURLObject aURLParser
;
1279 bool bWasAbsolute
= false;
1280 aURLParser
= aURLParser
.smartRel2Abs( _rPath
, bWasAbsolute
);
1282 // is it a valid folder?
1283 m_aContent
.bindTo( aURLParser
.GetMainURL( INetURLObject::DecodeMechanism::NONE
) );
1284 bool bIsFolder
= m_aContent
.isFolder( ); // do this _before_ asking isInvalid!
1285 bool bIsInvalid
= m_aContent
.isInvalid();
1287 if ( bIsInvalid
&& m_bHasFilename
&& !aURLParser
.hasFinalSlash() )
1288 { // check if the parent folder exists
1289 INetURLObject
aParent( aURLParser
);
1290 aParent
.removeSegment( );
1291 aParent
.setFinalSlash( );
1292 bIsInvalid
= implIsInvalid( aParent
.GetMainURL( INetURLObject::DecodeMechanism::NONE
) );
1297 INetURLObject
aFallback( _rFallback
);
1298 bIsInvalid
= implIsInvalid( aFallback
.GetMainURL( INetURLObject::DecodeMechanism::NONE
) );
1301 aURLParser
= aFallback
;
1306 INetURLObject
aParent( aURLParser
);
1307 while ( bIsInvalid
&& aParent
.removeSegment() )
1309 aParent
.setFinalSlash( );
1310 bIsInvalid
= implIsInvalid( aParent
.GetMainURL( INetURLObject::DecodeMechanism::NONE
) );
1314 aURLParser
= aParent
;
1317 if ( !bIsInvalid
&& bIsFolder
)
1319 aURLParser
.setFinalSlash();
1321 return aURLParser
.GetMainURL( INetURLObject::DecodeMechanism::NONE
);
1325 short SvtFileDialog::run()
1327 if ( !PrepareExecute() )
1331 m_bIsInExecute
= true;
1332 short nResult
= GenericDialogController::run();
1333 m_bIsInExecute
= false;
1335 SAL_WARN_IF( m_pCurrentAsyncAction
.is(), "fpicker.office", "SvtFilePicker::run: still running an async action!" );
1336 // the dialog should not be cancellable while an async action is running - first, the action
1337 // needs to be cancelled
1339 // remember last directory
1340 if ( RET_OK
== nResult
)
1342 INetURLObject
aURL( m_aPath
);
1343 if ( aURL
.GetProtocol() == INetProtocol::File
)
1345 // remember the selected directory only for file URLs not for virtual folders
1346 sal_Int32 nLevel
= aURL
.getSegmentCount();
1347 bool bDir
= m_aContent
.isFolder( aURL
.GetMainURL( INetURLObject::DecodeMechanism::NONE
) );
1348 if ( nLevel
> 1 && ( FILEDLG_TYPE_FILEDLG
== m_xImpl
->m_eDlgType
|| !bDir
) )
1349 aURL
.removeSegment();
1356 void SvtFileDialog::onAsyncOperationStarted()
1359 // the cancel button must be always enabled
1360 m_xImpl
->m_xBtnCancel
->set_sensitive(true);
1361 m_xImpl
->m_xBtnCancel
->grab_focus();
1364 void SvtFileDialog::onAsyncOperationFinished()
1367 m_pCurrentAsyncAction
= nullptr;
1368 if ( !m_bInExecuteAsync
)
1369 m_xImpl
->m_xEdFileName
->grab_focus();
1370 // (if m_bInExecuteAsync is true, then the operation was finished within the minimum wait time,
1371 // and to the user, the operation appears to be synchronous)
1374 void SvtFileDialog::RemovablePlaceSelected(bool enable
)
1376 m_xImpl
->m_xPlaces
->SetDelEnabled( enable
);
1379 void SvtFileDialog::displayIOException( const OUString
& _rURL
, IOErrorCode _eCode
)
1383 // create make a human-readable string from the URL
1384 OUString sDisplayPath
;
1385 if (osl::FileBase::getSystemPathFromFileURL(_rURL
, sDisplayPath
)
1386 == osl::FileBase::E_None
)
1388 sDisplayPath
= _rURL
;
1391 // build an own exception which tells "access denied"
1392 InteractiveAugmentedIOException aException
;
1393 aException
.Arguments
=
1394 { css::uno::Any(sDisplayPath
),
1395 css::uno::Any(PropertyValue(
1397 -1, aException
.Arguments
[ 0 ], PropertyState_DIRECT_VALUE
1399 // (formerly, it was sufficient to put the URL first parameter. Nowadays,
1400 // the services expects the URL in a PropertyValue named "Uri" ...)
1401 aException
.Code
= _eCode
;
1402 aException
.Classification
= InteractionClassification_ERROR
;
1404 // let and interaction handler handle this exception
1405 rtl::Reference
<::comphelper::OInteractionRequest
> pRequest
=
1406 new ::comphelper::OInteractionRequest( Any( aException
) );
1407 pRequest
->addContinuation( new ::comphelper::OInteractionAbort( ) );
1409 Reference
< XInteractionHandler2
> xHandler(
1410 InteractionHandler::createWithParent( ::comphelper::getProcessComponentContext(), nullptr ) );
1411 xHandler
->handle( pRequest
);
1413 catch( const Exception
& )
1415 TOOLS_WARN_EXCEPTION( "fpicker", "iodlg::displayIOException" );
1419 void SvtFileDialog::EnableUI(bool bEnable
)
1421 m_xDialog
->set_sensitive(bEnable
);
1425 for (auto& rxControl
: m_aDisabledControls
)
1427 rxControl
->set_sensitive(false);
1432 void SvtFileDialog::EnableControl(weld::Widget
* pControl
, bool bEnable
)
1436 SAL_WARN( "fpicker.office", "SvtFileDialog::EnableControl: invalid control!" );
1440 pControl
->set_sensitive(bEnable
);
1444 auto aPos
= m_aDisabledControls
.find( pControl
);
1445 if ( m_aDisabledControls
.end() != aPos
)
1446 m_aDisabledControls
.erase( aPos
);
1449 m_aDisabledControls
.insert( pControl
);
1452 bool SvtFileDialog::PrepareExecute()
1454 if (comphelper::LibreOfficeKit::isActive())
1458 if ( getEnvironmentValue( "WorkDirMustContainRemovableMedia", aEnvValue
) && aEnvValue
== "1" )
1462 INetURLObject
aStdDir( GetStandardDir() );
1463 ::ucbhelper::Content
aCnt( aStdDir
.GetMainURL(
1464 INetURLObject::DecodeMechanism::NONE
),
1465 Reference
< XCommandEnvironment
>(),
1466 comphelper::getProcessComponentContext() );
1467 Sequence
< OUString
> aProps
{ "IsVolume", "IsRemoveable" };
1469 Reference
< XResultSet
> xResultSet
1470 = aCnt
.createCursor( aProps
, ::ucbhelper::INCLUDE_FOLDERS_ONLY
);
1471 if ( xResultSet
.is() && !xResultSet
->next() )
1473 std::unique_ptr
<weld::MessageDialog
> xBox(Application::CreateMessageDialog(m_xDialog
.get(),
1474 VclMessageType::Warning
, VclButtonsType::Ok
,
1475 FpsResId(STR_SVT_NOREMOVABLEDEVICE
)));
1480 catch ( ContentCreationException
const & )
1483 catch ( CommandAbortedException
const & )
1488 if ( ( m_xImpl
->m_nStyle
& PickerFlags::SaveAs
) && m_bHasFilename
)
1489 // when doing a save-as, we do not want the handler to handle "this file does not exist" messages
1490 // - finally we're going to save that file, aren't we?
1491 m_aContent
.enableOwnInteractionHandler(::svt::OFilePickerInteractionHandler::E_DOESNOTEXIST
);
1493 m_aContent
.enableDefaultInteractionHandler();
1495 // possibly just a filename without a path
1496 OUString aFileNameOnly
;
1497 if( !m_aPath
.isEmpty() && (m_xImpl
->m_eMode
== FILEDLG_MODE_SAVE
)
1498 && (m_aPath
.indexOf(':') == -1)
1499 && (m_aPath
.indexOf('\\') == -1)
1500 && (m_aPath
.indexOf('/') == -1))
1502 aFileNameOnly
= m_aPath
;
1506 // no starting path specified?
1507 if ( m_aPath
.isEmpty() )
1509 // then use the standard directory
1510 m_aPath
= lcl_ensureFinalSlash( m_xImpl
->GetStandardDir() );
1512 // attach given filename to path
1513 if ( !aFileNameOnly
.isEmpty() )
1514 m_aPath
+= aFileNameOnly
;
1518 m_aPath
= implGetInitialURL( m_aPath
, GetStandardDir() );
1520 if ( m_xImpl
->m_nStyle
& PickerFlags::SaveAs
&& !m_bHasFilename
)
1521 // when doing a save-as, we do not want the handler to handle "this file does not exist" messages
1522 // - finally we're going to save that file, aren't we?
1523 m_aContent
.enableOwnInteractionHandler(::svt::OFilePickerInteractionHandler::E_DOESNOTEXIST
);
1525 // if applicable show filter
1526 m_xImpl
->InitFilterList();
1528 // set up initial filter
1529 sal_uInt16 nFilterCount
= GetFilterCount();
1530 OUString aAll
= FpsResId( STR_FILTERNAME_ALL
);
1531 bool bHasAll
= m_xImpl
->HasFilterListEntry( aAll
);
1532 if ( m_xImpl
->GetCurFilter() || nFilterCount
== 1 || ( nFilterCount
== 2 && bHasAll
) )
1534 // if applicable set the only filter or the only filter that
1535 // does not refer to all files, as the current one
1536 if ( !m_xImpl
->GetCurFilter() )
1538 sal_uInt16 nPos
= 0;
1539 if ( 2 == nFilterCount
&& bHasAll
)
1541 nPos
= nFilterCount
;
1544 if ( aAll
!= GetFilterName( nPos
) )
1548 SvtFileDialogFilter_Impl
* pNewCurFilter
= m_xImpl
->m_aFilter
[ nPos
].get();
1549 assert( pNewCurFilter
&& "SvtFileDialog::run: invalid filter pos!" );
1550 m_xImpl
->SetCurFilter( pNewCurFilter
, pNewCurFilter
->GetName() );
1554 m_xImpl
->SelectFilterListEntry( m_xImpl
->GetCurFilter()->GetName() );
1555 SetDefaultExt( m_xImpl
->GetCurFilter()->GetExtension() );
1556 sal_Int32 nSepPos
= GetDefaultExt().indexOf( FILEDIALOG_DEF_EXTSEP
);
1557 if ( nSepPos
!= -1 )
1558 EraseDefaultExt( nSepPos
);
1562 // if applicable set respectively create filter for all files
1565 SvtFileDialogFilter_Impl
* pAllFilter
= implAddFilter( aAll
, FILEDIALOG_FILTER_ALL
);
1566 m_xImpl
->InsertFilterListEntry( pAllFilter
);
1567 m_xImpl
->SetCurFilter( pAllFilter
, aAll
);
1569 m_xImpl
->SelectFilterListEntry( aAll
);
1572 // if applicable isolate filter
1575 if ( !IsolateFilterFromPath_Impl( m_aPath
, aFilter
) )
1578 AdjustFilterFlags nNewFilterFlags
= adjustFilter( aFilter
);
1579 if ( nNewFilterFlags
& ( AdjustFilterFlags::NonEmpty
| AdjustFilterFlags::UserFilter
) )
1581 m_xImpl
->m_xEdFileName
->set_entry_text( aFilter
);
1584 // create and show instance for set path
1585 INetURLObject
aFolderURL( m_aPath
);
1586 OUString
aFileName( aFolderURL
.getName( INetURLObject::LAST_SEGMENT
, false ) );
1587 sal_Int32 nFileNameLen
= aFileName
.getLength();
1588 bool bFileToSelect
= nFileNameLen
!= 0;
1589 if ( bFileToSelect
&& aFileName
[ nFileNameLen
- 1 ] != '/' )
1591 OUString aDecodedName
= aFolderURL
.getName( INetURLObject::LAST_SEGMENT
, true, INetURLObject::DecodeMechanism::WithCharset
);
1592 m_xImpl
->m_xEdFileName
->set_entry_text( aDecodedName
);
1593 aFolderURL
.removeSegment();
1596 INetURLObject aObj
= aFolderURL
;
1597 if ( aObj
.GetProtocol() == INetProtocol::File
)
1599 // set folder as current directory
1600 aObj
.setFinalSlash();
1603 UpdateControls( aObj
.GetMainURL( INetURLObject::DecodeMechanism::NONE
) );
1605 // Somebody might want to enable some controls according to the current filter
1608 OpenURL_Impl( aObj
.GetMainURL( INetURLObject::DecodeMechanism::NONE
) );
1610 // if applicable read and set size from ini
1616 void SvtFileDialog::executeAsync( ::svt::AsyncPickerAction::Action eAction
,
1617 const OUString
& rURL
, const OUString
& rFilter
)
1619 SAL_WARN_IF( m_pCurrentAsyncAction
.is(), "fpicker.office", "SvtFileDialog::executeAsync: previous async action not yet finished!" );
1621 m_pCurrentAsyncAction
= new AsyncPickerAction( this, m_xFileView
.get(), eAction
);
1623 bool bReallyAsync
= true;
1624 m_aConfiguration
.getNodeValue( OUString( "FillAsynchronously" ) ) >>= bReallyAsync
;
1626 sal_Int32 nMinTimeout
= 0;
1627 m_aConfiguration
.getNodeValue( OUString( "Timeout/Min" ) ) >>= nMinTimeout
;
1628 sal_Int32 nMaxTimeout
= 0;
1629 m_aConfiguration
.getNodeValue( OUString( "Timeout/Max" ) ) >>= nMaxTimeout
;
1631 m_bInExecuteAsync
= true;
1632 m_pCurrentAsyncAction
->execute(rURL
, rFilter
, bReallyAsync
? nMinTimeout
: -1, nMaxTimeout
, GetDenyList());
1633 m_bInExecuteAsync
= false;
1637 void SvtFileDialog::FileSelect()
1639 if (m_pFileNotifier
)
1640 m_pFileNotifier
->notify( FILE_SELECTION_CHANGED
, 0 );
1644 void SvtFileDialog::FilterSelect()
1646 if (m_pFileNotifier
)
1647 m_pFileNotifier
->notify( CTRL_STATE_CHANGED
,
1654 This method sets the path for the default button.
1656 void SvtFileDialog::SetStandardDir( const OUString
& rStdDir
)
1658 INetURLObject
aObj( rStdDir
);
1659 SAL_WARN_IF( aObj
.GetProtocol() == INetProtocol::NotValid
, "fpicker.office", "Invalid protocol!" );
1660 aObj
.setFinalSlash();
1661 m_xImpl
->SetStandardDir( aObj
.GetMainURL( INetURLObject::DecodeMechanism::NONE
) );
1664 void SvtFileDialog::SetDenyList( const css::uno::Sequence
< OUString
>& rDenyList
)
1666 m_xImpl
->SetDenyList( rDenyList
);
1670 const css::uno::Sequence
< OUString
>& SvtFileDialog::GetDenyList() const
1672 return m_xImpl
->GetDenyList();
1678 This method returns the standard path.
1680 const OUString
& SvtFileDialog::GetStandardDir() const
1682 return m_xImpl
->GetStandardDir();
1686 void SvtFileDialog::PrevLevel_Impl()
1688 m_xFileView
->EndInplaceEditing();
1691 executeAsync( AsyncPickerAction::ePrevLevel
, sDummy
, sDummy
);
1694 void SvtFileDialog::OpenURL_Impl( const OUString
& _rURL
)
1696 m_xFileView
->EndInplaceEditing();
1698 executeAsync( AsyncPickerAction::eOpenURL
, _rURL
, getMostCurrentFilter( m_xImpl
) );
1701 SvtFileDialogFilter_Impl
* SvtFileDialog::implAddFilter( const OUString
& rFilter
, const OUString
& _rType
)
1703 SvtFileDialogFilter_Impl
* pNewFilter
= new SvtFileDialogFilter_Impl( rFilter
, _rType
);
1704 m_xImpl
->m_aFilter
.push_front( std::unique_ptr
<SvtFileDialogFilter_Impl
>( pNewFilter
) );
1706 if ( !m_xImpl
->GetCurFilter() )
1707 m_xImpl
->SetCurFilter( pNewFilter
, rFilter
);
1712 void SvtFileDialog::AddFilter( const OUString
& rFilter
, const OUString
& _rType
)
1714 SAL_WARN_IF( m_bIsInExecute
, "fpicker.office", "SvtFileDialog::AddFilter: currently executing!" );
1715 implAddFilter ( rFilter
, _rType
);
1719 void SvtFileDialog::AddFilterGroup( const OUString
& rFilter
, const Sequence
< StringPair
>& rFilters
)
1721 SAL_WARN_IF( m_bIsInExecute
, "fpicker.office", "SvtFileDialog::AddFilter: currently executing!" );
1723 implAddFilter( rFilter
, OUString() );
1724 const StringPair
* pSubFilters
= rFilters
.getConstArray();
1725 const StringPair
* pSubFiltersEnd
= pSubFilters
+ rFilters
.getLength();
1726 for ( ; pSubFilters
!= pSubFiltersEnd
; ++pSubFilters
)
1727 implAddFilter( pSubFilters
->First
, pSubFilters
->Second
);
1731 void SvtFileDialog::SetCurFilter( const OUString
& rFilter
)
1733 SAL_WARN_IF( m_bIsInExecute
, "fpicker.office", "SvtFileDialog::SetCurFilter: currently executing!" );
1735 // look for corresponding filter
1736 sal_uInt16 nPos
= m_xImpl
->m_aFilter
.size();
1740 SvtFileDialogFilter_Impl
* pFilter
= m_xImpl
->m_aFilter
[ nPos
].get();
1741 if ( pFilter
->GetName() == rFilter
)
1743 m_xImpl
->SetCurFilter( pFilter
, rFilter
);
1749 OUString
SvtFileDialog::GetCurFilter() const
1753 const SvtFileDialogFilter_Impl
* pCurrentFilter
= m_xImpl
->GetCurFilter();
1754 if ( pCurrentFilter
)
1755 aFilter
= pCurrentFilter
->GetName();
1760 OUString
SvtFileDialog::getCurFilter( ) const
1762 return GetCurFilter();
1765 sal_uInt16
SvtFileDialog::GetFilterCount() const
1767 return m_xImpl
->m_aFilter
.size();
1770 const OUString
& SvtFileDialog::GetFilterName( sal_uInt16 nPos
) const
1772 assert( nPos
< GetFilterCount() && "invalid index" );
1773 return m_xImpl
->m_aFilter
[ nPos
]->GetName();
1776 void SvtFileDialog::InitSize()
1778 if (m_xImpl
->m_aIniKey
.isEmpty())
1781 // initialize from config
1782 SvtViewOptions
aDlgOpt( EViewType::Dialog
, m_xImpl
->m_aIniKey
);
1784 if ( aDlgOpt
.Exists() )
1786 m_xDialog
->set_window_state(aDlgOpt
.GetWindowState());
1788 Any aUserData
= aDlgOpt
.GetUserItem( "UserData");
1790 if ( aUserData
>>= sCfgStr
)
1791 m_xFileView
->SetConfigString( sCfgStr
);
1795 std::vector
<OUString
> SvtFileDialog::GetPathList() const
1797 std::vector
<OUString
> aList
;
1799 m_xFileView
->selected_foreach([this, &aList
](weld::TreeIter
& rCurEntry
){
1800 aList
.push_back(m_xFileView
->GetURL(rCurEntry
));
1806 if ( !m_xImpl
->m_xEdFileName
->get_active_text().isEmpty() && m_bIsInExecute
)
1807 aList
.push_back(m_xImpl
->m_xEdFileName
->GetURL());
1809 aList
.push_back(m_aPath
);
1815 bool SvtFileDialog::IsolateFilterFromPath_Impl( OUString
& rPath
, OUString
& rFilter
)
1817 OUString aReversePath
= comphelper::string::reverseString(rPath
);
1818 sal_Int32 nQuestionMarkPos
= rPath
.indexOf( '?' );
1819 sal_Int32 nWildCardPos
= rPath
.indexOf( FILEDIALOG_DEF_WILDCARD
);
1821 if ( nQuestionMarkPos
!= -1 )
1823 // use question mark as wildcard only for files
1824 INetProtocol eProt
= INetURLObject::CompareProtocolScheme( rPath
);
1826 if ( INetProtocol::NotValid
!= eProt
&& INetProtocol::File
!= eProt
)
1827 nQuestionMarkPos
= -1;
1829 nWildCardPos
= std::min( nWildCardPos
, nQuestionMarkPos
);
1834 if ( nWildCardPos
== -1 )
1837 sal_Int32 nPathTokenPos
= aReversePath
.indexOf( '/' );
1839 if ( nPathTokenPos
== -1 )
1849 nPathTokenPos
= aReversePath
.indexOf( aDelim
);
1851 if ( nPathTokenPos
== -1 )
1853 nPathTokenPos
= aReversePath
.indexOf( ':' );
1859 if ( nPathTokenPos
!= -1 )
1861 if ( nPathTokenPos
< (rPath
.getLength() - nWildCardPos
- 1) )
1863 ErrorHandler::HandleError( ERRCODE_SFX_INVALIDSYNTAX
);
1868 rFilter
= aReversePath
.copy( 0, nPathTokenPos
);
1869 rFilter
= comphelper::string::reverseString(rFilter
);
1872 rPath
= aReversePath
.copy( nPathTokenPos
);
1873 rPath
= comphelper::string::reverseString(rPath
);
1884 IMPL_LINK_NOARG(SvtFileDialog
, SizeAllocHdl
, const Size
&, void)
1886 if (m_pFileNotifier
)
1887 m_pFileNotifier
->notify(DIALOG_SIZE_CHANGED
, 0);
1890 weld::Widget
* SvtFileDialog::getControl( sal_Int16 nControlId
, bool bLabelControl
) const
1892 weld::Widget
* pReturn
= nullptr;
1894 switch ( nControlId
)
1896 case CONTROL_FILEVIEW
:
1897 pReturn
= bLabelControl
? nullptr : m_xFileView
->identifier();
1901 pReturn
= bLabelControl
1902 ? static_cast<weld::Widget
*>(m_xImpl
->m_xFtFileName
.get())
1903 : static_cast<weld::Widget
*>(m_xImpl
->m_xEdFileName
->getWidget());
1906 case EDIT_FILEURL_LABEL
:
1907 pReturn
= m_xImpl
->m_xFtFileName
.get();
1910 case CHECKBOX_AUTOEXTENSION
:
1911 pReturn
= m_xImpl
->m_xCbAutoExtension
.get();
1914 case CHECKBOX_PASSWORD
:
1915 pReturn
= m_xImpl
->m_xCbPassword
.get();
1918 case CHECKBOX_GPGENCRYPTION
:
1919 pReturn
= m_xImpl
->m_xCbGPGEncrypt
.get();
1922 case CHECKBOX_FILTEROPTIONS
:
1923 pReturn
= m_xImpl
->m_xCbOptions
.get();
1926 case CHECKBOX_READONLY
:
1927 pReturn
= m_xCbReadOnly
.get();
1931 pReturn
= m_xCbLinkBox
.get();
1934 case CHECKBOX_PREVIEW
:
1935 pReturn
= m_xCbPreviewBox
.get();
1938 case CHECKBOX_SELECTION
:
1939 pReturn
= m_xCbSelection
.get();
1942 case LISTBOX_FILTER
:
1943 pReturn
= bLabelControl
? m_xImpl
->m_xFtFileType
.get() : m_xImpl
->GetFilterListControl();
1946 case LISTBOX_FILTER_LABEL
:
1947 pReturn
= m_xImpl
->m_xFtFileType
.get();
1950 case FIXEDTEXT_CURRENTFOLDER
:
1951 pReturn
= m_xImpl
->m_xEdCurrentPath
->getWidget();
1954 case LISTBOX_VERSION
:
1955 pReturn
= bLabelControl
1956 ? static_cast<weld::Widget
*>(m_xImpl
->m_xSharedLabel
.get())
1957 : static_cast<weld::Widget
*>(m_xImpl
->m_xSharedListBox
.get());
1960 case LISTBOX_TEMPLATE
:
1961 pReturn
= bLabelControl
1962 ? static_cast<weld::Widget
*>(m_xImpl
->m_xSharedLabel
.get())
1963 : static_cast<weld::Widget
*>(m_xImpl
->m_xSharedListBox
.get());
1966 case LISTBOX_IMAGE_TEMPLATE
:
1967 pReturn
= bLabelControl
1968 ? static_cast<weld::Widget
*>(m_xImpl
->m_xSharedLabel
.get())
1969 : static_cast<weld::Widget
*>(m_xImpl
->m_xSharedListBox
.get());
1972 case LISTBOX_IMAGE_ANCHOR
:
1973 pReturn
= bLabelControl
1974 ? static_cast<weld::Widget
*>(m_xImpl
->m_xSharedLabel
.get())
1975 : static_cast<weld::Widget
*>(m_xImpl
->m_xSharedListBox
.get());
1978 case LISTBOX_VERSION_LABEL
:
1979 pReturn
= m_xImpl
->m_xSharedLabel
.get();
1982 case LISTBOX_TEMPLATE_LABEL
:
1983 pReturn
= m_xImpl
->m_xSharedLabel
.get();
1986 case LISTBOX_IMAGE_TEMPLATE_LABEL
:
1987 pReturn
= m_xImpl
->m_xSharedLabel
.get();
1990 case LISTBOX_IMAGE_ANCHOR_LABEL
:
1991 pReturn
= m_xImpl
->m_xSharedLabel
.get();
1995 pReturn
= m_xImpl
->m_xBtnFileOpen
.get();
1998 case PUSHBUTTON_CANCEL
:
1999 pReturn
= m_xImpl
->m_xBtnCancel
.get();
2002 case PUSHBUTTON_PLAY
:
2003 pReturn
= m_xPbPlay
.get();
2006 case PUSHBUTTON_HELP
:
2007 pReturn
= m_xImpl
->m_xBtnHelp
.get();
2010 case TOOLBOXBUTTON_LEVEL_UP
:
2011 pReturn
= m_xImpl
->m_xBtnUp
->getWidget();
2014 case TOOLBOXBUTTON_NEW_FOLDER
:
2015 pReturn
= m_xImpl
->m_xBtnNewFolder
.get();
2018 case LISTBOX_FILTER_SELECTOR
:
2019 // only exists on SalGtkFilePicker
2023 SAL_WARN( "fpicker.office", "SvtFileDialog::getControl: invalid id!" );
2028 void SvtFileDialog::enableControl(sal_Int16 nControlId
, bool bEnable
)
2030 weld::Widget
* pControl
= getControl(nControlId
);
2032 EnableControl(pControl
, bEnable
);
2033 weld::Widget
* pLabel
= getControl(nControlId
, true);
2035 EnableControl(pLabel
, bEnable
);
2038 void SvtFileDialog::AddControls_Impl( )
2040 // create the "insert as link" checkbox, if needed
2041 if ( m_nPickerFlags
& PickerFlags::InsertAsLink
)
2043 m_xCbLinkBox
->set_label( FpsResId( STR_SVT_FILEPICKER_INSERT_AS_LINK
) );
2044 m_xCbLinkBox
->set_help_id( HID_FILEDLG_LINK_CB
);
2045 m_xCbLinkBox
->connect_toggled( LINK( this, SvtFileDialog
, ClickHdl_Impl
) );
2046 m_xCbLinkBox
->show();
2049 // create the "show preview" checkbox ( and the preview window, too ), if needed
2050 if ( m_nPickerFlags
& PickerFlags::ShowPreview
)
2052 m_xImpl
->m_aIniKey
= "ImportGraphicDialog";
2055 m_xCbPreviewBox
->set_label( FpsResId( STR_SVT_FILEPICKER_SHOW_PREVIEW
) );
2056 m_xCbPreviewBox
->set_help_id( HID_FILEDLG_PREVIEW_CB
);
2057 m_xCbPreviewBox
->connect_toggled( LINK( this, SvtFileDialog
, ClickHdl_Impl
) );
2058 m_xCbPreviewBox
->show();
2060 // generate preview window just here
2061 m_aPreviewSize
= Size(200, 300);
2062 m_xPrevBmp
->set_size_request(m_aPreviewSize
.Width(), m_aPreviewSize
.Height());
2063 m_xPrevBmp
->connect_size_allocate(LINK(this, SvtFileDialog
, PreviewSizeAllocHdl
));
2064 m_xPreviewFrame
->show();
2065 m_xPrevBmp
->set_accessible_name(FpsResId(STR_PREVIEW
));
2068 if ( m_nPickerFlags
& PickerFlags::AutoExtension
)
2070 m_xImpl
->m_xCbAutoExtension
->set_label( FpsResId( STR_SVT_FILEPICKER_AUTO_EXTENSION
) );
2071 m_xImpl
->m_xCbAutoExtension
->set_active(true);
2072 m_xImpl
->m_xCbAutoExtension
->connect_toggled( LINK( this, SvtFileDialog
, AutoExtensionHdl_Impl
) );
2073 m_xImpl
->m_xCbAutoExtension
->show();
2076 if ( m_nPickerFlags
& PickerFlags::FilterOptions
)
2078 m_xImpl
->m_xCbOptions
->set_label( FpsResId( STR_SVT_FILEPICKER_FILTER_OPTIONS
) );
2079 m_xImpl
->m_xCbOptions
->connect_toggled( LINK( this, SvtFileDialog
, ClickHdl_Impl
) );
2080 m_xImpl
->m_xCbOptions
->show();
2083 if ( m_nPickerFlags
& PickerFlags::Selection
)
2085 m_xCbSelection
->set_label( FpsResId( STR_SVT_FILEPICKER_SELECTION
) );
2086 m_xCbSelection
->connect_toggled( LINK( this, SvtFileDialog
, ClickHdl_Impl
) );
2087 m_xCbSelection
->show();
2090 if ( m_nPickerFlags
& PickerFlags::PlayButton
)
2092 m_xPbPlay
->set_label( FpsResId( STR_SVT_FILEPICKER_PLAY
) );
2093 m_xPbPlay
->set_help_id( HID_FILESAVE_DOPLAY
);
2094 m_xPbPlay
->connect_clicked( LINK( this, SvtFileDialog
, PlayButtonHdl_Impl
) );
2098 if ( m_nPickerFlags
& PickerFlags::ShowVersions
)
2100 m_xImpl
->m_xSharedLabel
->set_label( FpsResId( STR_SVT_FILEPICKER_VERSION
) );
2101 m_xImpl
->m_xSharedLabel
->show();
2103 m_xImpl
->m_xSharedListBox
->set_help_id( HID_FILEOPEN_VERSION
);
2104 m_xImpl
->m_xSharedListBox
->show();
2106 else if ( m_nPickerFlags
& PickerFlags::Templates
)
2108 m_xImpl
->m_xSharedLabel
->set_label( FpsResId( STR_SVT_FILEPICKER_TEMPLATES
) );
2109 m_xImpl
->m_xSharedLabel
->show();
2111 m_xImpl
->m_xSharedListBox
->set_help_id( HID_FILEOPEN_VERSION
);
2112 m_xImpl
->m_xSharedListBox
->show();
2113 // This is strange. During the re-factoring during 96930, I discovered that this help id
2114 // is set in the "Templates mode". This was hidden in the previous implementation.
2115 // Shouldn't this be a more meaningful help id.
2117 else if ( m_nPickerFlags
& PickerFlags::ImageTemplate
)
2119 m_xImpl
->m_xSharedLabel
->set_label( FpsResId( STR_SVT_FILEPICKER_IMAGE_TEMPLATE
) );
2120 m_xImpl
->m_xSharedLabel
->show();
2122 m_xImpl
->m_xSharedListBox
->set_help_id( HID_FILEOPEN_IMAGE_TEMPLATE
);
2123 m_xImpl
->m_xSharedListBox
->show();
2125 else if ( m_nPickerFlags
& PickerFlags::ImageAnchor
)
2127 m_xImpl
->m_xSharedLabel
->set_label( FpsResId( STR_SVT_FILEPICKER_IMAGE_ANCHOR
) );
2128 m_xImpl
->m_xSharedLabel
->show();
2130 m_xImpl
->m_xSharedListBox
->set_help_id( HID_FILEOPEN_IMAGE_ANCHOR
);
2131 m_xImpl
->m_xSharedListBox
->show();
2134 m_xImpl
->m_xPlaces
.reset(new PlacesListBox(m_xBuilder
->weld_tree_view("places"),
2135 m_xBuilder
->weld_button("add"),
2136 m_xBuilder
->weld_button("del"),
2138 m_xImpl
->m_xPlaces
->set_help_id("SVT_HID_FILESAVE_PLACES_LISTBOX");
2139 m_xImpl
->m_xPlaces
->SetAddHdl( LINK ( this, SvtFileDialog
, AddPlacePressed_Hdl
) );
2140 m_xImpl
->m_xPlaces
->SetDelHdl( LINK ( this, SvtFileDialog
, RemovePlacePressed_Hdl
) );
2142 initDefaultPlaces();
2145 IMPL_LINK(SvtFileDialog
, PreviewSizeAllocHdl
, const Size
&, rSize
, void)
2147 m_aPreviewSize
= rSize
;
2150 sal_Int32
SvtFileDialog::getAvailableWidth()
2153 return m_aPreviewSize
.Width();
2158 sal_Int32
SvtFileDialog::getAvailableHeight()
2161 return m_aPreviewSize
.Height();
2166 void SvtFileDialog::setImage(const Any
& rImage
)
2168 if (!m_xPrevBmp
|| !m_xPreviewFrame
->get_visible())
2171 Sequence
< sal_Int8
> aBmpSequence
;
2173 if ( rImage
>>= aBmpSequence
)
2176 SvMemoryStream
aData( aBmpSequence
.getArray(),
2177 aBmpSequence
.getLength(),
2179 ReadDIBBitmapEx(aBmp
, aData
);
2181 m_xPrevBmp
->set_image(Graphic(aBmp
).GetXGraphic());
2185 m_xPrevBmp
->set_image(nullptr);
2189 OUString
SvtFileDialog::getCurrentFileText( ) const
2192 if (m_xImpl
&& m_xImpl
->m_xEdFileName
)
2193 sReturn
= m_xImpl
->m_xEdFileName
->get_active_text();
2197 void SvtFileDialog::setCurrentFileText( const OUString
& _rText
, bool m_bSelectAll
)
2199 if (m_xImpl
&& m_xImpl
->m_xEdFileName
)
2201 m_xImpl
->m_xEdFileName
->set_entry_text( _rText
);
2203 m_xImpl
->m_xEdFileName
->select_entry_region(0, -1);
2207 bool SvtFileDialog::isAutoExtensionEnabled() const
2209 return m_xImpl
->m_xCbAutoExtension
&& m_xImpl
->m_xCbAutoExtension
->get_active();
2212 bool SvtFileDialog::getShowState()
2214 if (m_xPreviewFrame
)
2215 return m_xPreviewFrame
->get_visible();
2220 bool SvtFileDialog::ContentHasParentFolder( const OUString
& rURL
)
2222 m_aContent
.bindTo( rURL
);
2224 if ( m_aContent
.isInvalid() )
2227 return m_aContent
.hasParentFolder( ) && m_aContent
.isValid();
2230 bool SvtFileDialog::ContentCanMakeFolder( const OUString
& rURL
)
2232 m_aContent
.bindTo( rURL
);
2234 if ( m_aContent
.isInvalid() )
2237 return m_aContent
.canCreateFolder( ) && m_aContent
.isValid();
2240 bool SvtFileDialog::ContentGetTitle( const OUString
& rURL
, OUString
& rTitle
)
2242 m_aContent
.bindTo( rURL
);
2244 if ( m_aContent
.isInvalid() )
2248 m_aContent
.getTitle( sTitle
);
2251 return m_aContent
.isValid();
2254 void SvtFileDialog::appendDefaultExtension(OUString
& rFileName
,
2255 std::u16string_view rFilterDefaultExtension
,
2256 const OUString
& rFilterExtensions
)
2258 const OUString
aType(rFilterExtensions
.toAsciiLowerCase());
2260 if ( aType
== FILEDIALOG_FILTER_ALL
)
2263 const OUString
aTemp(rFileName
.toAsciiLowerCase());
2268 if (nPos
+1<aType
.getLength() && aType
[nPos
]=='*') // take care of a leading *
2270 const std::u16string_view
aExt(o3tl::getToken(aType
, 0, FILEDIALOG_DEF_EXTSEP
, nPos
));
2273 if (o3tl::ends_with(aTemp
, aExt
))
2278 rFileName
+= OUString::Concat(".") + rFilterDefaultExtension
;
2281 void SvtFileDialog::initDefaultPlaces( )
2283 PlacePtr pRootPlace
= std::make_shared
<Place
>( FpsResId(STR_DEFAULT_DIRECTORY
), GetStandardDir() );
2284 m_xImpl
->m_xPlaces
->AppendPlace( pRootPlace
);
2286 // Load from user settings
2287 Sequence
< OUString
> placesUrlsList(officecfg::Office::Common::Misc::FilePickerPlacesUrls::get());
2288 Sequence
< OUString
> placesNamesList(officecfg::Office::Common::Misc::FilePickerPlacesNames::get());
2290 for(sal_Int32 nPlace
= 0; nPlace
< placesUrlsList
.getLength() && nPlace
< placesNamesList
.getLength(); ++nPlace
)
2292 PlacePtr pPlace
= std::make_shared
<Place
>(placesNamesList
[nPlace
], placesUrlsList
[nPlace
], true);
2293 m_xImpl
->m_xPlaces
->AppendPlace(pPlace
);
2296 // Reset the placesList "updated" state
2297 m_xImpl
->m_xPlaces
->IsUpdated();
2300 QueryFolderNameDialog::QueryFolderNameDialog(weld::Window
* _pParent
,
2301 const OUString
& rTitle
, const OUString
& rDefaultText
)
2302 : GenericDialogController(_pParent
, "fps/ui/foldernamedialog.ui", "FolderNameDialog")
2303 , m_xNameEdit(m_xBuilder
->weld_entry("entry"))
2304 , m_xOKBtn(m_xBuilder
->weld_button("ok"))
2306 m_xDialog
->set_title(rTitle
);
2307 m_xNameEdit
->set_text(rDefaultText
);
2308 m_xNameEdit
->select_region(0, -1);
2309 m_xOKBtn
->connect_clicked(LINK(this, QueryFolderNameDialog
, OKHdl
));
2310 m_xNameEdit
->connect_changed(LINK(this, QueryFolderNameDialog
, NameHdl
));
2313 QueryFolderNameDialog::~QueryFolderNameDialog()
2317 IMPL_LINK_NOARG(QueryFolderNameDialog
, OKHdl
, weld::Button
&, void)
2320 m_xNameEdit
->set_text(comphelper::string::strip(m_xNameEdit
->get_text(), ' '));
2321 m_xDialog
->response(RET_OK
);
2324 IMPL_LINK_NOARG(QueryFolderNameDialog
, NameHdl
, weld::Entry
&, void)
2327 OUString aName
= comphelper::string::strip(m_xNameEdit
->get_text(), ' ');
2328 m_xOKBtn
->set_sensitive(!aName
.isEmpty());
2331 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */