/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
void SetFsysExtension_Impl( OUString& rFile, std::u16string_view rExtension )
{ const sal_Int32 nDotPos{ rFile.lastIndexOf('.') }; if (nDotPos>=0)
{ if (!rExtension.empty())
rFile = OUString::Concat(rFile.subView(0, nDotPos)) + rExtension; // replace old extension with new (not empty) one elseif (nDotPos)
rFile = rFile.copy(0, nDotPos-1); // truncate extension (new one is empty) else
rFile.clear(); // Filename was just an extension
} elseif (!rExtension.empty())
rFile += OUString::Concat(".") + rExtension; // no extension was present, append new one if not empty
}
void lcl_autoUpdateFileExtension( SvtFileDialog* _pDialog, const OUString& _rLastFilterExt )
{ // if auto extension is enabled... if ( !_pDialog->isAutoExtensionEnabled() ) return;
// automatically switch to the extension of the (maybe just newly selected) extension
OUString aNewFile = _pDialog->getCurrentFileText( );
OUString aExt = GetFsysExtension_Impl( aNewFile, _rLastFilterExt );
// but only if there already is an extension if ( aExt.isEmpty() ) return;
// check if it is a real file extension, and not only the "post-dot" part in // a directory name bool bRealExtensions = true; if ( -1 != aExt.indexOf( '/' ) )
bRealExtensions = false; elseif ( -1 != aExt.indexOf( '\\' ) )
bRealExtensions = false; else
{ // no easy way to tell, because the part containing the dot already is the last // segment of the complete file name // So we have to check if the file name denotes a folder or a file. // For performance reasons, we do this for file urls only
INetURLObject aURL( aNewFile ); if ( INetProtocol::NotValid == aURL.GetProtocol() )
{
OUString sURL; if ( osl::FileBase::getFileURLFromSystemPath( aNewFile, sURL )
== osl::FileBase::E_None )
aURL = INetURLObject( sURL );
} if ( INetProtocol::File == aURL.GetProtocol() )
{ try
{
bRealExtensions = !_pDialog->ContentIsFolder( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
} catch( const css::uno::Exception& )
{
SAL_INFO( "fpicker.office", "Exception in lcl_autoUpdateFileExtension" );
}
}
}
// now ask the content broker for a provider for this scheme
try
{ // get the provider for the current scheme
Reference< XContentProvider > xProvider(
UniversalContentBroker::create(
comphelper::getProcessComponentContext() )->
queryContentProvider( _rForURL ) );
SAL_WARN_IF( !xProvider.is(), "fpicker.office", "lcl_getHomeDirectory: could not find a (valid) content provider for the current URL!" );
Reference< XPropertySet > xProviderProps( xProvider, UNO_QUERY ); if ( xProviderProps.is() )
{
Reference< XPropertySetInfo > xPropInfo = xProviderProps->getPropertySetInfo(); static constexpr OUString sHomeDirPropertyName( u"HomeDirectory"_ustr ); if ( !xPropInfo.is() || xPropInfo->hasPropertyByName( sHomeDirPropertyName ) )
{
OUString sHomeDirectory;
xProviderProps->getPropertyValue( sHomeDirPropertyName ) >>= sHomeDirectory;
_rHomeDir = sHomeDirectory;
}
}
} catch( const Exception& )
{
TOOLS_WARN_EXCEPTION( "fpicker", "lcl_getHomeDirectory" );
} return !_rHomeDir.isEmpty();
} #endif
// because the "<All Formats> (*.bmp,*...)" entry is too wide, // we need to disable the auto width feature of the filter box int nWidth = m_xImpl->m_xLbFilter->get_approximate_digit_width() * 60;
m_xImpl->m_xSharedListBox->set_size_request(nWidth, -1);
m_xImpl->m_xLbFilter->set_size_request(nWidth, -1);
if (nStyle & PickerFlags::PathDialog)
m_xImpl->m_eDlgType = FILEDLG_TYPE_PATHDLG;
// Create control element, the order defines the tab control.
m_xImpl->m_xEdFileName->connect_changed( LINK( this, SvtFileDialog, EntrySelectHdl_Impl ) );
m_xImpl->m_xEdFileName->connect_entry_activate( LINK( this, SvtFileDialog, OpenUrlHdl_Impl ) );
// in folder picker mode, only auto-complete directories (no files) bool bIsFolderPicker = m_xImpl->m_eDlgType == FILEDLG_TYPE_PATHDLG;
m_xImpl->m_xEdFileName->SetOnlyDirectories( bIsFolderPicker );
// in save mode, don't use the autocompletion as selection in the edit part bool bSaveMode = FILEDLG_MODE_SAVE == m_xImpl->m_eMode;
m_xImpl->m_xEdFileName->SetNoURLSelection( bSaveMode );
if (nStyle & PickerFlags::MultiSelection)
m_xImpl->m_bMultiSelection = true;
// set timer for the filterbox travel
m_xImpl->m_aFilterIdle.SetPriority(TaskPriority::LOWEST);
m_xImpl->m_aFilterIdle.SetInvokeHandler( LINK( this, SvtFileDialog, FilterSelectTimerHdl_Impl ) );
if ( PickerFlags::SaveAs & nStyle )
{ // different help ids if in save-as mode
m_xDialog->set_help_id( HID_FILESAVE_DIALOG );
// formerly, there was only _pLbFileVersion, which was used for 3 different // use cases. For reasons of maintainability, I introduced extra members (_pLbTemplates, _pLbImageTemplates) // for the extra use cases, and separated _pLbFileVersion // I did not find out in which cases the help ID is really needed HID_FILESAVE_TEMPLATE - all // tests I made lead to a dialog where _no_ of the three list boxes was present. if (m_xImpl->m_xSharedListBox)
m_xImpl->m_xSharedListBox->set_help_id( HID_FILESAVE_TEMPLATE );
if ( m_xImpl->m_xCbPassword ) m_xImpl->m_xCbPassword->set_help_id( HID_FILESAVE_SAVEWITHPASSWORD ); if ( m_xImpl->m_xCbAutoExtension ) m_xImpl->m_xCbAutoExtension->set_help_id( HID_FILESAVE_AUTOEXTENSION ); if ( m_xImpl->m_xCbOptions ) m_xImpl->m_xCbOptions->set_help_id( HID_FILESAVE_CUSTOMIZEFILTER ); if ( m_xCbSelection ) m_xCbSelection->set_help_id( HID_FILESAVE_SELECTION );
}
/// read our settings from the configuration
m_aConfiguration = OConfigurationTreeRoot::createWithComponentContext(
::comphelper::getProcessComponentContext(),
u"/org.openoffice.Office.UI/FilePicker"_ustr
);
void SvtFileDialog::createNewUserFilter( const OUString& _rNewFilter )
{ // delete the old user filter and create a new one
m_xImpl->m_xUserFilter.reset( new SvtFileDialogFilter_Impl( _rNewFilter, _rNewFilter ) );
// remember the extension bool bIsAllFiles = _rNewFilter == FILEDIALOG_FILTER_ALL; if ( bIsAllFiles )
EraseDefaultExt(); else
SetDefaultExt( _rNewFilter.copy( 2 ) ); // TODO: this is nonsense. In the whole file there are a lot of places where we assume that a user filter // is always "*.<something>". But changing this would take some more time than I have now...
// now, the default extension is set to the one of the user filter (or empty) if ( m_xImpl->GetCurFilter( ) )
SetDefaultExt( m_xImpl->GetCurFilter( )->GetExtension() ); else
EraseDefaultExt();
}
void SvtFileDialog::OpenHdl_Impl(voidconst * pVoid)
{ if ( m_xImpl->m_bMultiSelection && m_xFileView->GetSelectionCount() > 1 )
{ // special open in case of multiselection
OpenMultiSelection_Impl(); return;
}
OUString aFileName;
OUString aOldPath(m_xFileView->GetViewURL()); if ( m_xImpl->m_bDoubleClick || m_xFileView->has_focus() )
{ // Selection done by doubleclicking in the view, get filename from the view
aFileName = m_xFileView->GetCurrentURL();
}
if ( aFileName.isEmpty() )
{ // if an entry is selected in the view... if ( m_xFileView->GetSelectionCount() )
{ // -> use this one. This will allow us to step down this folder
aFileName = m_xFileView->GetCurrentURL();
}
}
if ( aFileName.isEmpty() )
{ // get the URL from the edit field ( if not empty ) if ( !m_xImpl->m_xEdFileName->get_active_text().isEmpty() )
{
OUString aText = m_xImpl->m_xEdFileName->get_active_text();
// did we reach the root? if ( !INetURLObject( aOldPath ).getSegmentCount() )
{ if ( ( aText.getLength() == 2 && aText == ".." ) ||
( aText.getLength() == 3 && ( aText == "..\\" || aText == "../" ) ) ) // don't go higher than the root return;
}
#ifdefined( UNX ) if ( ( 1 == aText.getLength() ) && ( '~' == aText[0] ) )
{ // go to the home directory if ( lcl_getHomeDirectory( m_xFileView->GetViewURL(), aFileName ) ) // in case we got a home dir, reset the text of the edit
m_xImpl->m_xEdFileName->set_entry_text( OUString() );
} if ( aFileName.isEmpty() ) #endif
{ // get url from autocomplete edit
aFileName = m_xImpl->m_xEdFileName->GetURL();
}
} elseif ( pVoid == m_xImpl->m_xBtnFileOpen.get() ) // OpenHdl was called for the "Open" Button; if edit field is empty, use selected element in the view
aFileName = m_xFileView->GetCurrentURL();
}
sal_Int32 nLen = aFileName.getLength(); if ( !nLen )
{ // if the dialog was opened to select a folder, the last selected folder should be selected if( m_xImpl->m_eDlgType == FILEDLG_TYPE_PATHDLG )
{
aFileName = m_xImpl->m_xEdCurrentPath->get_active_text();
nLen = aFileName.getLength();
} else // no file selected ! return;
}
// mark input as selected
m_xImpl->m_xEdFileName->select_entry_region(0, nLen);
// if a path with wildcards is given, divide the string into path and wildcards
OUString aFilter; if ( !SvtFileDialog::IsolateFilterFromPath_Impl( aFileName, aFilter ) ) return;
// if a filter was retrieved, there were wildcards !
AdjustFilterFlags nNewFilterFlags = adjustFilter( aFilter ); if ( nNewFilterFlags & AdjustFilterFlags::Changed )
{ // cut off all text before wildcard in edit and select wildcard
m_xImpl->m_xEdFileName->set_entry_text( aFilter );
m_xImpl->m_xEdFileName->select_entry_region(0, -1);
}
// check if it is a folder bool bIsFolder = false;
// first thing before doing anything with the content: Reset it. When the user presses "open" (or "save" or "export", // for that matter), s/he wants the complete handling, including all possible error messages, even if s/he // does the same thing for the same content twice, s/he wants both fails to be displayed. // Without the reset, it could be that the content cached all relevant information, and will not display any // error messages for the same content a second time...
m_aContent.bindTo( OUString( ) );
if ( !aFileName.isEmpty() )
{ // Make sure we have own Interaction Handler in place. We do not need // to intercept interactions here, but to record the fact that there // was an interaction.
SmartContent::InteractionHandlerType eInterActionHandlerType
= m_aContent.queryCurrentInteractionHandler(); if ( ( eInterActionHandlerType == SmartContent::IHT_NONE ) ||
( eInterActionHandlerType == SmartContent::IHT_DEFAULT ) )
m_aContent.enableOwnInteractionHandler(
OFilePickerInteractionHandler::E_NOINTERCEPTION );
bIsFolder = m_aContent.isFolder( aFileName );
// access denied to the given resource - and interaction was already // used => break following operations
OFilePickerInteractionHandler* pHandler
= m_aContent.getOwnInteractionHandler();
OSL_ENSURE( pHandler, "Got no Interaction Handler!!!" );
if ( pHandler->wasAccessDenied() ) return;
if ( m_aContent.isInvalid() &&
( m_xImpl->m_eMode == FILEDLG_MODE_OPEN ) )
{ if ( !pHandler->wasUsed() )
ErrorHandler::HandleError( ERRCODE_IO_NOTEXISTS );
if ( !bIsFolder // no existent folder
&& m_xImpl->m_xCbAutoExtension // auto extension is enabled in general
&& m_xImpl->m_xCbAutoExtension->get_active()// auto extension is really to be used
&& !GetDefaultExt().isEmpty() // there is a default extension
&& GetDefaultExt() != "*"// the default extension is not "all"
&& !( FILEDLG_MODE_SAVE == m_xImpl->m_eMode // we're saving a file
&& m_xFileView->GetSelectionCount() // there is a selected file in the file view -> it will later on
) // (in SvtFileDialog::GetPathList) be taken as file to save to
&& FILEDLG_MODE_OPEN != m_xImpl->m_eMode // #i83408# don't append extension on open
)
{ // check extension and append the default extension if necessary
appendDefaultExtension(aFileName,
GetDefaultExt(),
m_xImpl->GetCurFilter()->GetType());
}
IMPL_LINK_NOARG( SvtFileDialog, FilterSelectHdl_Impl, weld::ComboBox&, void )
{
OUString sSelectedFilterDisplayName;
SvtFileDialogFilter_Impl* pSelectedFilter = m_xImpl->GetSelectedFilterEntry( sSelectedFilterDisplayName ); if ( !pSelectedFilter )
{ // there is no current selection. This happens if for instance the user selects a group separator using // the keyboard, and then presses enter: When the selection happens, we immediately deselect the entry, // so in this situation there is no current selection.
restoreCurrentFilter( m_xImpl );
} else
{ if ( ( pSelectedFilter != m_xImpl->GetCurFilter() )
|| m_xImpl->m_xUserFilter
)
{ // Store the old filter for the auto extension handling
OUString sLastFilterExt = m_xImpl->GetCurFilter()->GetExtension();
m_xImpl->m_xUserFilter.reset();
// if applicable remove filter of the user
m_xImpl->SetCurFilter( pSelectedFilter, sSelectedFilterDisplayName );
// if applicable show extension
SetDefaultExt( pSelectedFilter->GetExtension() );
sal_Int32 nSepPos = GetDefaultExt().indexOf( FILEDIALOG_DEF_EXTSEP );
if ( nSepPos != -1 )
EraseDefaultExt( nSepPos );
// update the extension of the current file if necessary
lcl_autoUpdateFileExtension( this, sLastFilterExt );
// if the user is traveling fast through the filterbox // do not filter instantly // FilterSelectHdl_Impl should be started again at idle
m_xImpl->m_aFilterIdle.Start();
}
}
}
IMPL_LINK_NOARG(SvtFileDialog, FilterSelectTimerHdl_Impl, Timer*, void)
{ // filter the view again
ExecuteFilter();
}
break;
} case RET_CANCEL : default : // Do Nothing break;
}
}
IMPL_LINK_NOARG ( SvtFileDialog, AddPlacePressed_Hdl, weld::Button&, void )
{ // Maybe open the PlacesDialog would have been a better idea // there is an ux choice to make we did not make...
INetURLObject aURLObj( m_xFileView->GetViewURL() );
PlacePtr newPlace =
std::make_shared<Place>( aURLObj.GetLastName(INetURLObject::DecodeMechanism::WithCharset),
m_xFileView->GetViewURL(), true);
m_xImpl->m_xPlaces->AppendPlace(newPlace);
}
if ( aObj.getSegmentCount() )
{
osl::FileBase::getSystemPathFromFileURL(rURL, sText); if ( !sText.isEmpty() )
{ // no Fsys path for server file system ( only UCB has mountpoints! ) if ( INetProtocol::File != aObj.GetProtocol() )
sText = rURL.copy( INetURLObject::GetScheme( aObj.GetProtocol() ).getLength() );
}
if ( sText.isEmpty() && aObj.getSegmentCount() )
sText = rURL;
}
// path mode ? if ( FILEDLG_TYPE_PATHDLG == m_xImpl->m_eDlgType ) // -> set new path in the edit field
m_xImpl->m_xEdFileName->set_entry_text( sText );
// in the "current path" field, truncate the trailing slash if ( aObj.hasFinalSlash() )
{
aObj.removeFinalSlash();
OUString sURL( aObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ) ); if (osl::FileBase::getSystemPathFromFileURL(sURL, sText) != osl::FileBase::E_None)
sText = sURL;
}
if ( sText.isEmpty() && !rURL.isEmpty() ) // happens, for instance, for URLs which the INetURLObject does not know to belong to a hierarchical scheme
sText = rURL;
m_xImpl->m_xEdCurrentPath->set_entry_text(sText);
}
m_aPath = rURL;
m_xImpl->m_xBtnUp->FillURLMenu();
if (m_pFileNotifier)
m_pFileNotifier->notify( DIRECTORY_CHANGED, 0 );
}
IMPL_LINK( SvtFileDialog, OpenDoneHdl_Impl, SvtFileView*, pView, void )
{ const OUString& sCurrentFolder( pView->GetViewURL() ); // check if we can create new folders
EnableControl( m_xImpl->m_xBtnNewFolder.get(), ContentCanMakeFolder( sCurrentFolder ) );
// check if we can travel one level up bool bCanTravelUp = ContentHasParentFolder( pView->GetViewURL() ); if ( bCanTravelUp )
{ // additional check: the parent folder should not be prohibited
INetURLObject aCurrentFolder( sCurrentFolder );
SAL_WARN_IF( INetProtocol::NotValid == aCurrentFolder.GetProtocol(), "fpicker.office", "SvtFileDialog::OpenDoneHdl_Impl: invalid current URL!" );
short SvtFileDialog::run()
{ if ( !PrepareExecute() ) return 0;
// start the dialog
m_bIsInExecute = true; short nResult = GenericDialogController::run();
m_bIsInExecute = false;
SAL_WARN_IF( m_pCurrentAsyncAction.is(), "fpicker.office", "SvtFilePicker::run: still running an async action!" ); // the dialog should not be cancellable while an async action is running - first, the action // needs to be cancelled
// remember last directory if ( RET_OK == nResult )
{
INetURLObject aURL( m_aPath ); if ( aURL.GetProtocol() == INetProtocol::File )
{ // remember the selected directory only for file URLs not for virtual folders
sal_Int32 nLevel = aURL.getSegmentCount(); bool bDir = m_aContent.isFolder( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ) ); if ( nLevel > 1 && ( FILEDLG_TYPE_FILEDLG == m_xImpl->m_eDlgType || !bDir ) )
aURL.removeSegment();
}
}
return nResult;
}
void SvtFileDialog::onAsyncOperationStarted()
{
EnableUI( false ); // the cancel button must be always enabled
m_xImpl->m_xBtnCancel->set_sensitive(true);
m_xImpl->m_xBtnCancel->grab_focus();
}
void SvtFileDialog::onAsyncOperationFinished()
{
EnableUI( true );
m_pCurrentAsyncAction = nullptr; if ( !m_bInExecuteAsync )
m_xImpl->m_xEdFileName->grab_focus(); // (if m_bInExecuteAsync is true, then the operation was finished within the minimum wait time, // and to the user, the operation appears to be synchronous)
}
void SvtFileDialog::displayIOException( const OUString& _rURL, IOErrorCode _eCode )
{ try
{ // create make a human-readable string from the URL
OUString sDisplayPath; if (osl::FileBase::getSystemPathFromFileURL(_rURL, sDisplayPath)
== osl::FileBase::E_None)
{
sDisplayPath = _rURL;
}
// build an own exception which tells "access denied"
InteractiveAugmentedIOException aException;
aException.Arguments =
{ css::uno::Any(sDisplayPath),
css::uno::Any(PropertyValue(
u"Uri"_ustr,
-1, aException.Arguments[ 0 ], PropertyState_DIRECT_VALUE
)) }; // (formerly, it was sufficient to put the URL first parameter. Nowadays, // the services expects the URL in a PropertyValue named "Uri" ...)
aException.Code = _eCode;
aException.Classification = InteractionClassification_ERROR;
// let and interaction handler handle this exception
rtl::Reference<::comphelper::OInteractionRequest> pRequest = new ::comphelper::OInteractionRequest( Any( aException ) );
pRequest->addContinuation( new ::comphelper::OInteractionAbort( ) );
if (bEnable)
{ auto aPos = m_aDisabledControls.find( pControl ); if ( m_aDisabledControls.end() != aPos )
m_aDisabledControls.erase( aPos );
} else
m_aDisabledControls.insert( pControl );
}
bool SvtFileDialog::PrepareExecute()
{ if (comphelper::LibreOfficeKit::isActive()) returnfalse;
if ( ( m_xImpl->m_nStyle & PickerFlags::SaveAs ) && m_bHasFilename ) // when doing a save-as, we do not want the handler to handle "this file does not exist" messages // - finally we're going to save that file, aren't we?
m_aContent.enableOwnInteractionHandler(::svt::OFilePickerInteractionHandler::E_DOESNOTEXIST); else
m_aContent.enableDefaultInteractionHandler();
// possibly just a filename without a path
OUString aFileNameOnly; if( !m_aPath.isEmpty() && (m_xImpl->m_eMode == FILEDLG_MODE_SAVE)
&& (m_aPath.indexOf(':') == -1)
&& (m_aPath.indexOf('\\') == -1)
&& (m_aPath.indexOf('/') == -1))
{
aFileNameOnly = m_aPath;
m_aPath.clear();
} // no starting path specified? if ( m_aPath.isEmpty() )
{ // then use the standard directory
m_aPath = lcl_ensureFinalSlash( SvtPathOptions().GetWorkPath() ); // attach given filename to path if ( !aFileNameOnly.isEmpty() )
m_aPath += aFileNameOnly;
}
m_aPath = implGetInitialURL( m_aPath, SvtPathOptions().GetWorkPath() );
if ( m_xImpl->m_nStyle & PickerFlags::SaveAs && !m_bHasFilename ) // when doing a save-as, we do not want the handler to handle "this file does not exist" messages // - finally we're going to save that file, aren't we?
m_aContent.enableOwnInteractionHandler(::svt::OFilePickerInteractionHandler::E_DOESNOTEXIST);
// if applicable show filter
m_xImpl->InitFilterList();
// set up initial filter
sal_uInt16 nFilterCount = GetFilterCount();
OUString aAll = FpsResId( STR_FILTERNAME_ALL ); bool bHasAll = m_xImpl->HasFilterListEntry( aAll ); if ( m_xImpl->GetCurFilter() || nFilterCount == 1 || ( nFilterCount == 2 && bHasAll ) )
{ // if applicable set the only filter or the only filter that // does not refer to all files, as the current one if ( !m_xImpl->GetCurFilter() )
{
sal_uInt16 nPos = 0; if ( 2 == nFilterCount && bHasAll )
{
nPos = nFilterCount; while (nPos)
{
--nPos; if ( aAll != GetFilterName( nPos ) ) break;
}
}
SvtFileDialogFilter_Impl* pNewCurFilter = m_xImpl->m_aFilter[ nPos ].get();
assert( pNewCurFilter && "SvtFileDialog::run: invalid filter pos!" );
m_xImpl->SetCurFilter( pNewCurFilter, pNewCurFilter->GetName() );
}
INetURLObject aObj = std::move(aFolderURL); if ( aObj.GetProtocol() == INetProtocol::File )
{ // set folder as current directory
aObj.setFinalSlash();
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.