xref: /trunk/main/sc/source/ui/vba/vbafiledialog.cxx (revision 7a7771fb4d20b857459c676939e2cc2f4dec9635)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 #include "vbafiledialog.hxx"
23 #include "helperdecl.hxx"
24 #include "comphelper/processfactory.hxx"
25 #include <com/sun/star/lang/XServiceInfo.hpp>
26 #include <com/sun/star/ui/dialogs/XFilePicker.hpp>
27 #include <com/sun/star/ui/dialogs/XFilePicker2.hpp>
28 #include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
29 #include <com/sun/star/ui/dialogs/XFilterManager.hpp>
30 #include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
31 #include "tools/urlobj.hxx"
32 #include <sfx2/filedlghelper.hxx>
33 
34 using namespace ::com::sun::star;
35 using namespace ::com::sun::star::uno;
36 
37 
ScVbaFileDialog(const css::uno::Reference<ooo::vba::XHelperInterface> & xParent,const css::uno::Reference<css::uno::XComponentContext> & xContext,const css::uno::Reference<css::frame::XModel> & xModel)38 ScVbaFileDialog::ScVbaFileDialog( const css::uno::Reference< ooo::vba::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext > &xContext, const css::uno::Reference< css::frame::XModel >& xModel )
39 :   ScVbaFileDialog_BASE( xParent, xContext ), m_xModel( xModel )
40 {
41     m_nDialogType = 3;
42     m_bAllowMultiSelect = sal_True;
43     m_pSelectedItems = new VbaFileDialogSelectedItems(xParent, xContext,
44         uno::Reference< container::XIndexAccess >(
45             static_cast< container::XIndexAccess* >( &m_FileDialogSelectedObj ),
46             UNO_QUERY ));
47 }
48 
ScVbaFileDialog(const css::uno::Sequence<css::uno::Any> &,const css::uno::Reference<css::uno::XComponentContext> & xContext)49 ScVbaFileDialog::ScVbaFileDialog( const css::uno::Sequence< css::uno::Any >& /*args*/,
50     const css::uno::Reference< css::uno::XComponentContext >& xContext )
51 :   ScVbaFileDialog_BASE( xContext ), m_xModel(), m_pSelectedItems(NULL)
52 {
53     m_nDialogType = 3;
54     m_bAllowMultiSelect = sal_True;
55 }
56 
~ScVbaFileDialog()57 ScVbaFileDialog::~ScVbaFileDialog()
58 {
59     if (m_pSelectedItems != NULL)
60     {
61         delete m_pSelectedItems;
62     }
63 }
64 
65 rtl::OUString&
getServiceImplName()66 ScVbaFileDialog::getServiceImplName()
67 {
68     static rtl::OUString sImplName( RTL_CONSTASCII_USTRINGPARAM("ScVbaFileDialog") );
69     return sImplName;
70 }
71 
72 css::uno::Sequence<rtl::OUString>
getServiceNames()73 ScVbaFileDialog::getServiceNames()
74 {
75     static Sequence< rtl::OUString > aServiceNames;
76     if ( aServiceNames.getLength() == 0 )
77     {
78         aServiceNames.realloc( 1 );
79         aServiceNames[ 0 ] = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("ooo.vba.excel.FileDialog" ) );
80     }
81     return aServiceNames;
82 }
83 
84 sal_Int32 SAL_CALL
getMsoFileDialogType()85 ScVbaFileDialog::getMsoFileDialogType() throw ( css::uno::RuntimeException )
86 {
87     return m_nDialogType;
88 }
89 
90 void SAL_CALL
setMsoFileDialogType(sal_Int32 nType)91 ScVbaFileDialog::setMsoFileDialogType( sal_Int32 nType ) throw ( css::uno::RuntimeException )
92 {
93     m_nDialogType = nType;
94 }
95 
96 rtl::OUString SAL_CALL
getTitle()97 ScVbaFileDialog::getTitle() throw ( css::uno::RuntimeException )
98 {
99     return m_sTitle;
100 }
101 
102 void SAL_CALL
setTitle(const rtl::OUString & rTitle)103 ScVbaFileDialog::setTitle( const rtl::OUString& rTitle ) throw ( css::uno::RuntimeException )
104 {
105     m_sTitle = rTitle;
106 }
107 
108 sal_Bool SAL_CALL
getAllowMultiSelect()109 ScVbaFileDialog::getAllowMultiSelect() throw ( css::uno::RuntimeException )
110 {
111     return m_bAllowMultiSelect;
112 }
113 
114 void SAL_CALL
setAllowMultiSelect(sal_Bool bAllow)115 ScVbaFileDialog::setAllowMultiSelect( sal_Bool bAllow ) throw ( css::uno::RuntimeException )
116 {
117     m_bAllowMultiSelect = bAllow;
118 }
119 
120 css::uno::Reference< ooo::vba::XFileDialogSelectedItems > SAL_CALL
getSelectedItems()121 ScVbaFileDialog::getSelectedItems() throw ( css::uno::RuntimeException )
122 {
123     return css::uno::Reference< ooo::vba::XFileDialogSelectedItems >( m_pSelectedItems );
124 }
125 
126 sal_Int32 SAL_CALL
Show()127 ScVbaFileDialog::Show() throw ( css::uno::RuntimeException )
128 {
129     // Returns an Integer indicating if user pressed "Open" button(-1) or "Cancel" button(0).
130     sal_Int32 nResult = -1;
131     try
132     {
133         m_sSelectedItems.realloc(0);
134 
135         const ::rtl::OUString sServiceName = ::rtl::OUString::createFromAscii( "com.sun.star.ui.dialogs.FilePicker" );
136 
137         Reference< lang::XMultiServiceFactory > xMSF( comphelper::getProcessServiceFactory(), uno::UNO_QUERY );
138         // Map MsoFileDialogType to appropriate AOO picker template.
139         // msoFileDialogOpen = 1, msoFileDialogSaveAs = 2,
140         // msoFileDialogFilePicker = 3 (default), msoFileDialogFolderPicker = 4
141         // Note: AOO's current FilePicker API does not expose a dedicated folder
142         // picker template; we fall back to FILEOPEN_SIMPLE for that case.
143         sal_Int16 nTemplateDesc = ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE;
144         switch ( m_nDialogType )
145         {
146             case 1: // msoFileDialogOpen
147                 nTemplateDesc = ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE;
148                 break;
149             case 2: // msoFileDialogSaveAs
150                 nTemplateDesc = ui::dialogs::TemplateDescription::FILESAVE_SIMPLE;
151                 break;
152             case 3: // msoFileDialogFilePicker
153                 nTemplateDesc = ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE;
154                 break;
155             case 4: // msoFileDialogFolderPicker - fall back to FILEOPEN_SIMPLE
156             default:
157                 nTemplateDesc = ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE;
158                 break;
159         }
160         Sequence< uno::Any > aDialogType( 1 );
161         aDialogType[0] <<= nTemplateDesc;
162         Reference< ui::dialogs::XFilePicker > xFilePicker( xMSF->createInstanceWithArguments( sServiceName, aDialogType ), UNO_QUERY );
163         Reference< ui::dialogs::XFilePicker2 > xFilePicker2( xFilePicker, UNO_QUERY );
164         Reference< ui::dialogs::XFilterManager > xFilterManager( xFilePicker, UNO_QUERY );
165         if ( xFilePicker.is() )
166         {
167             // Apply the title if one was set (XFilePicker inherits
168             // XExecutableDialog which provides setTitle)
169             if ( m_sTitle.getLength() > 0 )
170             {
171                 uno::Reference< ui::dialogs::XExecutableDialog > xExecDialog( xFilePicker, UNO_QUERY );
172                 if ( xExecDialog.is() )
173                     xExecDialog->setTitle( m_sTitle );
174             }
175             xFilePicker->setMultiSelectionMode( m_bAllowMultiSelect );
176             // Only when there is no any filter in the msoFileDialogFilePicker dialog, then we need to add the All File Filter.
177             if ( xFilterManager.is() && xFilterManager->getCurrentFilter().equalsAscii("") )
178             {
179                 xFilterManager->appendFilter( rtl::OUString::createFromAscii( "All Files" ), rtl::OUString::createFromAscii( "*.*" ) );
180             }
181             if ( xFilePicker->execute() )
182             {
183                 sal_Bool bUseXFilePicker2 = sal_False;
184                 Reference< lang::XServiceInfo > xServiceInfo( xFilePicker, UNO_QUERY );
185                 if (xServiceInfo.is())
186                 {
187                     rtl::OUString sImplName = xServiceInfo->getImplementationName();
188                     if (sImplName.equalsAscii("com.sun.star.comp.fpicker.VistaFileDialog") ||
189                         sImplName.equalsAscii("com.sun.star.ui.dialogs.SalGtkFilePicker"))
190                     {
191                         bUseXFilePicker2 = sal_True;
192                     }
193                 }
194                 if ( bUseXFilePicker2 && xFilePicker2.is() )
195                 {
196                     // On Linux, XFilePicker->getFiles() always return one selected file although we select
197                     // more than one file, also on Vista XFilePicker->getFiles() does not work well too,
198                     // so we call XFilePicker2->getSelectedFiles() to get selected files.
199                     m_sSelectedItems = xFilePicker2->getSelectedFiles();
200                 }
201                 else
202                 {
203                     // If only one file is selected, the first entry of the sequence contains the complete path/filename in
204                     // URL format. If multiple files are selected, the first entry of the sequence contains the path in URL
205                     // format, and the other entries contains the names of the selected files without path information.
206                     Sequence< rtl::OUString > aSelectedFiles = xFilePicker->getFiles();
207                     sal_Int32 iFileCount = aSelectedFiles.getLength();
208                     if ( iFileCount > 1 )
209                     {
210                         m_sSelectedItems.realloc( iFileCount - 1 );
211                         INetURLObject aPath( aSelectedFiles[0] );
212                         aPath.setFinalSlash();
213                         for ( sal_Int32 i = 1; i < iFileCount; i++ )
214                         {
215                             if ( aSelectedFiles[i].indexOf ('/') > 0 || aSelectedFiles[i].indexOf ('\\') > 0 )
216                             {
217                                 m_sSelectedItems[i - 1] = aSelectedFiles[i];
218                             }
219                             else
220                             {
221                                 if ( i == 1 )
222                                     aPath.Append( aSelectedFiles[i] );
223                                 else
224                                     aPath.setName( aSelectedFiles[i] );
225                                 m_sSelectedItems[i - 1] = aPath.GetMainURL(INetURLObject::NO_DECODE);
226                             }
227                         }
228                     }
229                     else if ( iFileCount == 1 )
230                     {
231                         m_sSelectedItems = aSelectedFiles;
232                     }
233                 }
234 
235                 sal_Int32 iFileCount = m_sSelectedItems.getLength();
236                 rtl::OUString aTemp;
237                 for ( sal_Int32 i = 0; i < iFileCount; i++ )
238                 {
239                     INetURLObject aObj( m_sSelectedItems[i] );
240                     if ( aObj.GetProtocol() == INET_PROT_FILE )
241                     {
242                         aTemp = aObj.PathToFileName();
243                         m_sSelectedItems[i] = aTemp.getLength() > 0 ? aTemp : m_sSelectedItems[i];
244                     }
245                 }
246             }
247             else
248             {
249                 nResult = 0;
250             }
251         }
252 
253         m_FileDialogSelectedObj.SetSelectedFile(m_sSelectedItems);
254     }
255     catch( const uno::Exception& )
256     {
257         return 0;
258     }
259 
260     return nResult;
261 }
262