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 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_svx.hxx"
26 
27 #include "svx/databaselocationinput.hxx"
28 #include "svx/dialmgr.hxx"
29 
30 #include "svx/fmresids.hrc"
31 
32 /** === begin UNO includes === **/
33 #include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
34 /** === end UNO includes === **/
35 
36 #include <comphelper/componentcontext.hxx>
37 #include <comphelper/namedvaluecollection.hxx>
38 #include <rtl/ustrbuf.hxx>
39 #include <sfx2/filedlghelper.hxx>
40 #include <svtools/urlcontrol.hxx>
41 #include <svl/filenotation.hxx>
42 #include <tools/diagnose_ex.h>
43 #include <unotools/confignode.hxx>
44 #include <unotools/ucbhelper.hxx>
45 #include <vcl/button.hxx>
46 #include <vcl/msgbox.hxx>
47 
48 //........................................................................
49 namespace svx
50 {
51 //........................................................................
52 
53 	/** === begin UNO using === **/
54     using ::com::sun::star::uno::Sequence;
55     using ::com::sun::star::uno::Reference;
56     using ::com::sun::star::container::XNameAccess;
57     using ::com::sun::star::uno::UNO_QUERY_THROW;
58     using ::com::sun::star::uno::Exception;
59 	/** === end UNO using === **/
60     namespace TemplateDescription = ::com::sun::star::ui::dialogs::TemplateDescription;
61 
62 	//====================================================================
63 	//= DatabaseLocationInputController_Impl
64 	//====================================================================
65     class DatabaseLocationInputController_Impl
66     {
67     public:
68         DatabaseLocationInputController_Impl(
69             const ::comphelper::ComponentContext&   _rContext,
70             ::svt::OFileURLControl&                 _rLocationInput,
71             PushButton&                             _rBrowseButton
72         );
73         ~DatabaseLocationInputController_Impl();
74 
75         bool    prepareCommit();
76         void    setURL( const String& _rURL );
77         String  getURL() const;
78 
79     private:
80         void    impl_initFilterProperties_nothrow();
81         void    impl_onBrowseButtonClicked();
82         void    impl_onLocationModified();
83         String  impl_getCurrentURL() const;
84 
85         DECL_LINK( OnControlAction, VclWindowEvent* );
86 
87     private:
88         const ::comphelper::ComponentContext    m_aContext;
89         ::svt::OFileURLControl&                 m_rLocationInput;
90         PushButton&                             m_rBrowseButton;
91         Sequence< ::rtl::OUString >             m_aFilterExtensions;
92         ::rtl::OUString                         m_sFilterUIName;
93         bool                                    m_bNeedExistenceCheck;
94     };
95 
96 	//--------------------------------------------------------------------
DatabaseLocationInputController_Impl(const::comphelper::ComponentContext & _rContext,::svt::OFileURLControl & _rLocationInput,PushButton & _rBrowseButton)97     DatabaseLocationInputController_Impl::DatabaseLocationInputController_Impl( const ::comphelper::ComponentContext& _rContext,
98             ::svt::OFileURLControl& _rLocationInput, PushButton& _rBrowseButton )
99         :m_aContext( _rContext )
100         ,m_rLocationInput( _rLocationInput )
101         ,m_rBrowseButton( _rBrowseButton )
102         ,m_aFilterExtensions()
103         ,m_sFilterUIName()
104         ,m_bNeedExistenceCheck( true )
105     {
106         impl_initFilterProperties_nothrow();
107 
108         // forward the allowed extensions to the input control
109         ::rtl::OUStringBuffer aExtensionList;
110         for (   const ::rtl::OUString* pExtension = m_aFilterExtensions.getConstArray();
111                 pExtension != m_aFilterExtensions.getConstArray() + m_aFilterExtensions.getLength();
112                 ++pExtension
113             )
114         {
115             aExtensionList.append( *pExtension );
116             aExtensionList.append( (sal_Unicode)';' );
117         }
118         m_rLocationInput.SetFilter( aExtensionList.makeStringAndClear() );
119 
120         m_rBrowseButton.AddEventListener( LINK( this, DatabaseLocationInputController_Impl, OnControlAction ) );
121         m_rLocationInput.AddEventListener( LINK( this, DatabaseLocationInputController_Impl, OnControlAction ) );
122     }
123 
124     //--------------------------------------------------------------------
~DatabaseLocationInputController_Impl()125     DatabaseLocationInputController_Impl::~DatabaseLocationInputController_Impl()
126     {
127         m_rBrowseButton.RemoveEventListener( LINK( this, DatabaseLocationInputController_Impl, OnControlAction ) );
128         m_rLocationInput.RemoveEventListener( LINK( this, DatabaseLocationInputController_Impl, OnControlAction ) );
129     }
130 
131 	//--------------------------------------------------------------------
prepareCommit()132     bool DatabaseLocationInputController_Impl::prepareCommit()
133     {
134 		::rtl::OUString sURL( impl_getCurrentURL() );
135         if ( !sURL.getLength() )
136             return false;
137 
138         // check if the name exists
139 		if ( m_bNeedExistenceCheck )
140 		{
141 			if ( ::utl::UCBContentHelper::Exists( sURL ) )
142 			{
143 				QueryBox aBox( m_rLocationInput.GetSystemWindow(), WB_YES_NO, SVX_RES( RID_STR_ALREADYEXISTOVERWRITE ) );
144 				if ( aBox.Execute() != RET_YES )
145 					return false;
146 			}
147 		}
148 
149         return true;
150     }
151 
152 	//--------------------------------------------------------------------
setURL(const String & _rURL)153     void DatabaseLocationInputController_Impl::setURL( const String& _rURL )
154     {
155         ::svt::OFileNotation aTransformer( _rURL );
156         m_rLocationInput.SetText( aTransformer.get( ::svt::OFileNotation::N_SYSTEM ) );
157     }
158 
159 	//--------------------------------------------------------------------
getURL() const160     String DatabaseLocationInputController_Impl::getURL() const
161     {
162         return impl_getCurrentURL();
163     }
164 
165 	//--------------------------------------------------------------------
impl_initFilterProperties_nothrow()166     void DatabaseLocationInputController_Impl::impl_initFilterProperties_nothrow()
167     {
168         try
169         {
170             // get the name of the default filter for database documents
171             ::utl::OConfigurationTreeRoot aConfig(
172                 ::utl::OConfigurationTreeRoot::createWithServiceFactory(
173                     m_aContext.getLegacyServiceFactory(),
174                     ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "/org.openoffice.Setup/Office/Factories/com.sun.star.sdb.OfficeDatabaseDocument" ) )
175             ) );
176             ::rtl::OUString sDatabaseFilter;
177             OSL_VERIFY( aConfig.getNodeValue( "ooSetupFactoryActualFilter" ) >>= sDatabaseFilter );
178 
179             // get the type this filter is responsible for
180             Reference< XNameAccess > xFilterFactory(
181                 m_aContext.createComponent( "com.sun.star.document.FilterFactory" ),
182                 UNO_QUERY_THROW );
183             ::comphelper::NamedValueCollection aFilterProperties( xFilterFactory->getByName( sDatabaseFilter ) );
184             ::rtl::OUString sDocumentType = aFilterProperties.getOrDefault( "Type", ::rtl::OUString() );
185 
186             // get the extension(s) for this type
187             Reference< XNameAccess > xTypeDetection(
188                 m_aContext.createComponent( "com.sun.star.document.TypeDetection" ),
189                 UNO_QUERY_THROW );
190 
191             ::comphelper::NamedValueCollection aTypeProperties( xTypeDetection->getByName( sDocumentType ) );
192             m_aFilterExtensions = aTypeProperties.getOrDefault( "Extensions", m_aFilterExtensions );
193             m_sFilterUIName = aTypeProperties.getOrDefault( "UIName", m_sFilterUIName );
194         }
195         catch( const Exception& )
196         {
197         	DBG_UNHANDLED_EXCEPTION();
198         }
199 
200         // ensure we have at least one extension
201         OSL_ENSURE( m_aFilterExtensions.getLength(),
202             "DatabaseLocationInputController_Impl::impl_initFilterProperties_nothrow: unable to determine the file extension(s)!" );
203         if ( m_aFilterExtensions.getLength() == 0 )
204         {
205             m_aFilterExtensions.realloc(1);
206             m_aFilterExtensions[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "*.odb" ) );
207         }
208     }
209 
210     // -----------------------------------------------------------------------------
IMPL_LINK(DatabaseLocationInputController_Impl,OnControlAction,VclWindowEvent *,_pEvent)211     IMPL_LINK( DatabaseLocationInputController_Impl, OnControlAction, VclWindowEvent*, _pEvent )
212     {
213         if  (   ( _pEvent->GetWindow() == &m_rBrowseButton )
214             &&  ( _pEvent->GetId() == VCLEVENT_BUTTON_CLICK )
215             )
216         {
217             impl_onBrowseButtonClicked();
218         }
219 
220         if  (   ( _pEvent->GetWindow() == &m_rLocationInput )
221             &&  ( _pEvent->GetId() == VCLEVENT_EDIT_MODIFY )
222             )
223         {
224             impl_onLocationModified();
225         }
226 
227         return 0L;
228     }
229 
230     // -----------------------------------------------------------------------------
impl_getCurrentURL() const231     String DatabaseLocationInputController_Impl::impl_getCurrentURL() const
232     {
233         String sCurrentFile( m_rLocationInput.GetText() );
234         if ( sCurrentFile.Len() )
235         {
236             ::svt::OFileNotation aCurrentFile( sCurrentFile );
237             sCurrentFile = aCurrentFile.get( ::svt::OFileNotation::N_URL );
238         }
239         return sCurrentFile;
240     }
241 
242     // -----------------------------------------------------------------------------
impl_onBrowseButtonClicked()243     void DatabaseLocationInputController_Impl::impl_onBrowseButtonClicked()
244     {
245         ::sfx2::FileDialogHelper aFileDlg(
246             TemplateDescription::FILESAVE_AUTOEXTENSION,
247             WB_STDMODAL | WB_SAVEAS,
248             m_rLocationInput.GetSystemWindow()
249         );
250         aFileDlg.SetDisplayDirectory( impl_getCurrentURL() );
251 
252         aFileDlg.AddFilter( m_sFilterUIName, ::rtl::OUStringBuffer().appendAscii( "*." ).append( m_aFilterExtensions[0] ).makeStringAndClear() );
253         aFileDlg.SetCurrentFilter( m_sFilterUIName );
254 
255         if ( aFileDlg.Execute() == ERRCODE_NONE )
256         {
257             INetURLObject aURL( aFileDlg.GetPath() );
258             if( aURL.GetProtocol() != INET_PROT_NOT_VALID )
259             {
260                 ::svt::OFileNotation aFileNotation( aURL.GetMainURL( INetURLObject::NO_DECODE ) );
261                 m_rLocationInput.SetText( aFileNotation.get( ::svt::OFileNotation::N_SYSTEM ) );
262                 m_rLocationInput.GetModifyHdl().Call( &m_rLocationInput );
263                 // the dialog already checked for the file's existence, so we don't need to, again
264                 m_bNeedExistenceCheck = false;
265             }
266         }
267     }
268 
269     // -----------------------------------------------------------------------------
impl_onLocationModified()270     void DatabaseLocationInputController_Impl::impl_onLocationModified()
271     {
272         m_bNeedExistenceCheck = true;
273     }
274 
275     //====================================================================
276 	//= DatabaseLocationInputController
277 	//====================================================================
278 	//--------------------------------------------------------------------
DatabaseLocationInputController(const::comphelper::ComponentContext & _rContext,::svt::OFileURLControl & _rLocationInput,PushButton & _rBrowseButton)279     DatabaseLocationInputController::DatabaseLocationInputController( const ::comphelper::ComponentContext& _rContext,
280             ::svt::OFileURLControl& _rLocationInput, PushButton& _rBrowseButton )
281         :m_pImpl( new DatabaseLocationInputController_Impl( _rContext, _rLocationInput, _rBrowseButton ) )
282     {
283     }
284 
285 	//--------------------------------------------------------------------
~DatabaseLocationInputController()286     DatabaseLocationInputController::~DatabaseLocationInputController()
287     {
288     }
289 
290 	//--------------------------------------------------------------------
prepareCommit()291     bool DatabaseLocationInputController::prepareCommit()
292     {
293         return m_pImpl->prepareCommit();
294     }
295 
296 	//--------------------------------------------------------------------
setURL(const String & _rURL)297     void DatabaseLocationInputController::setURL( const String& _rURL )
298     {
299         m_pImpl->setURL( _rURL );
300     }
301 
302 	//--------------------------------------------------------------------
getURL() const303     String DatabaseLocationInputController::getURL() const
304     {
305         return m_pImpl->getURL();
306     }
307 
308 //........................................................................
309 } // namespace svx
310 //........................................................................
311