calc: on editing invalidation of view with different zoom is wrong
[LibreOffice.git] / fpicker / source / aqua / SalAquaFilePicker.mm
blob01e6f80e92b5cb733d795720331c16fe2dd6ba9d
1 /* -*- Mode: ObjC; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
20 #include <config_features.h>
22 #include <sal/config.h>
23 #include <sal/log.hxx>
25 #include <com/sun/star/lang/DisposedException.hpp>
26 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
27 #include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp>
28 #include <com/sun/star/ui/dialogs/CommonFilePickerElementIds.hpp>
29 #include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp>
30 #include <cppuhelper/interfacecontainer.h>
31 #include <cppuhelper/supportsservice.hxx>
32 #include <osl/diagnose.h>
33 #include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
34 #include <com/sun/star/ui/dialogs/ControlActions.hpp>
35 #include <com/sun/star/uno/Any.hxx>
36 #include <osl/mutex.hxx>
37 #include <vcl/svapp.hxx>
39 #include "resourceprovider.hxx"
41 #include <osl/file.hxx>
42 #include "NSString_OOoAdditions.hxx"
43 #include "NSURL_OOoAdditions.hxx"
45 #include <iostream>
47 #include "SalAquaFilePicker.hxx"
49 #include <objc/objc-runtime.h>
51 #pragma mark DEFINES
53 using namespace ::com::sun::star;
54 using namespace ::com::sun::star::ui::dialogs;
55 using namespace ::com::sun::star::ui::dialogs::TemplateDescription;
56 using namespace ::com::sun::star::ui::dialogs::ExtendedFilePickerElementIds;
57 using namespace ::com::sun::star::ui::dialogs::CommonFilePickerElementIds;
58 using namespace ::com::sun::star::lang;
59 using namespace ::com::sun::star::beans;
60 using namespace ::com::sun::star::uno;
62 namespace
64     uno::Sequence<OUString> FilePicker_getSupportedServiceNames()
65     {
66         return { "com.sun.star.ui.dialogs.FilePicker",
67                  "com.sun.star.ui.dialogs.SystemFilePicker",
68                  "com.sun.star.ui.dialogs.AquaFilePicker" };
69     }
72 #pragma mark Constructor
74 SalAquaFilePicker::SalAquaFilePicker()
75   : SalAquaFilePicker_Base( m_rbHelperMtx )
76    , m_pFilterHelper( nullptr )
78     m_pDelegate = [[AquaFilePickerDelegate alloc] initWithFilePicker:this];
79     m_pControlHelper->setFilePickerDelegate(m_pDelegate);
82 SalAquaFilePicker::~SalAquaFilePicker()
84     if (nullptr != m_pFilterHelper)
85         delete m_pFilterHelper;
87     [m_pDelegate release];
91 #pragma mark XFilePickerNotifier
93 void SAL_CALL SalAquaFilePicker::addFilePickerListener( const uno::Reference<XFilePickerListener>& xListener )
95     SolarMutexGuard aGuard;
96     m_xListener = xListener;
99 void SAL_CALL SalAquaFilePicker::removeFilePickerListener( const uno::Reference<XFilePickerListener>& )
101     SolarMutexGuard aGuard;
102     m_xListener.clear();
105 #pragma mark XAsynchronousExecutableDialog
107 void SAL_CALL SalAquaFilePicker::setTitle( const OUString& aTitle )
109     SolarMutexGuard aGuard;
110     implsetTitle(aTitle);
113 sal_Int16 SAL_CALL SalAquaFilePicker::execute()
115     SolarMutexGuard aGuard;
117     sal_Int16 retVal = 0;
119     implInitialize();
121     // if m_pDialog is nil after initialization, something must have gone wrong before
122     // or there was no initialization (see issue https://bz.apache.org/ooo/show_bug.cgi?id=100214)
123     if (m_pDialog == nil) {
124         m_nDialogType = NAVIGATIONSERVICES_OPEN;
125     }
127     if (m_pFilterHelper) {
128         m_pFilterHelper->SetFilters();
129     }
131     if (m_nDialogType == NAVIGATIONSERVICES_SAVE) {
132         if (m_sSaveFileName.getLength() == 0) {
133             //if no filename is set, NavigationServices will set the name to "untitled". We don't want this!
134             //So let's try to get the window title to get the real untitled name
135             NSWindow *frontWindow = [NSApp keyWindow];
136             if (nullptr != frontWindow) {
137                 NSString *windowTitle = [frontWindow title];
138                 if (windowTitle != nil) {
139                     OUString ouName = [windowTitle OUString];
140                     //a window title will typically be something like "Untitled1 - OpenOffice.org Writer"
141                     //but we only want the "Untitled1" part of it
142                     sal_Int32 indexOfDash = ouName.indexOf(" - ");
143                     if (indexOfDash > -1) {
144                         m_sSaveFileName = ouName.copy(0,indexOfDash);
145                         if (m_sSaveFileName.getLength() > 0) {
146                             setDefaultName(m_sSaveFileName);
147                         }
148                     }
149                 }
150             }
151         }
152     }
154     //Set the delegate to be notified of certain events
156     [m_pDialog setDelegate:m_pDelegate];
158     int nStatus = runandwaitforresult();
160     [m_pDialog setDelegate:nil];
162     switch( nStatus )
163     {
164         case NSModalResponseOK:
165             retVal = ExecutableDialogResults::OK;
166             break;
168         case NSModalResponseCancel:
169             retVal = ExecutableDialogResults::CANCEL;
170             break;
172         default:
173             throw uno::RuntimeException(
174                       "The dialog returned with an unknown result!",
175                       static_cast<XFilePicker*>( static_cast<XFilePicker3*>( this ) ));
176             break;
177     }
179     return retVal;
183 #pragma mark XFilePicker
185 void SAL_CALL SalAquaFilePicker::setMultiSelectionMode( sal_Bool /* bMode */ )
187     SolarMutexGuard aGuard;
189     if (m_nDialogType == NAVIGATIONSERVICES_OPEN) {
190         [static_cast<NSOpenPanel*>(m_pDialog) setAllowsMultipleSelection:YES];
191     }
194 void SAL_CALL SalAquaFilePicker::setDefaultName( const OUString& aName )
196     SolarMutexGuard aGuard;
198     m_sSaveFileName = aName;
201 void SAL_CALL SalAquaFilePicker::setDisplayDirectory( const OUString& rDirectory )
203     SolarMutexGuard aGuard;
205     implsetDisplayDirectory(rDirectory);
208 OUString SAL_CALL SalAquaFilePicker::getDisplayDirectory()
210     OUString retVal = implgetDisplayDirectory();
212     return retVal;
215 uno::Sequence<OUString> SAL_CALL SalAquaFilePicker::getFiles()
217     uno::Sequence< OUString > aSelectedFiles = getSelectedFiles();
218     // multiselection doesn't really work with getFiles
219     // so just retrieve the first url
220     if (aSelectedFiles.getLength() > 1)
221         aSelectedFiles.realloc(1);
223     return aSelectedFiles;
226 uno::Sequence<OUString> SAL_CALL SalAquaFilePicker::getSelectedFiles()
228     SolarMutexGuard aGuard;
230 #if HAVE_FEATURE_MACOSX_SANDBOX
231     static NSUserDefaults *userDefaults;
232     static bool triedUserDefaults = false;
234     if (!triedUserDefaults)
235     {
236         userDefaults = [NSUserDefaults standardUserDefaults];
237         triedUserDefaults = true;
238     }
239 #endif
241     NSArray *files = nil;
242     if (m_nDialogType == NAVIGATIONSERVICES_OPEN) {
243         files = [static_cast<NSOpenPanel*>(m_pDialog) URLs];
244     }
245     else if (m_nDialogType == NAVIGATIONSERVICES_SAVE) {
246         files = [NSArray arrayWithObjects:[m_pDialog URL], nil];
247     }
249     NSUInteger nFiles = [files count];
250     SAL_INFO("fpicker.aqua", "# of items: " << nFiles);
252     uno::Sequence< OUString > aSelectedFiles(nFiles);
253     OUString* pSelectedFiles = aSelectedFiles.getArray();
255     for(NSUInteger nIndex = 0; nIndex < nFiles; nIndex += 1)
256     {
257         NSURL *url = [files objectAtIndex:nIndex];
259 #if HAVE_FEATURE_MACOSX_SANDBOX
260         if (userDefaults != NULL &&
261             [url respondsToSelector:@selector(bookmarkDataWithOptions:includingResourceValuesForKeys:relativeToURL:error:)])
262         {
263             // In the case of "Save As" when the user has input a new
264             // file name, this call will return nil, as bookmarks can
265             // (naturally) only be created for existing file system
266             // objects. In that case, code at a much lower level, in
267             // sal, takes care of creating a bookmark when a new file
268             // has been created outside the sandbox.
269             NSData *data = [url bookmarkDataWithOptions:NSURLBookmarkCreationWithSecurityScope
270                          includingResourceValuesForKeys:nil
271                                           relativeToURL:nil
272                                                   error:nil];
273             if (data != NULL)
274             {
275                 [userDefaults setObject:data
276                                  forKey:[@"bookmarkFor:" stringByAppendingString:[url absoluteString]]];
277             }
278         }
279 #endif
281         OUString sFileOrDirURL = [url OUString];
283         pSelectedFiles[nIndex] = sFileOrDirURL;
284     }
286     return aSelectedFiles;
289 #pragma mark XFilterManager
291 void SAL_CALL SalAquaFilePicker::appendFilter( const OUString& aTitle, const OUString& aFilter )
293     SolarMutexGuard aGuard;
295     ensureFilterHelper();
296     m_pFilterHelper->appendFilter( aTitle, aFilter );
297     m_pControlHelper->setFilterControlNeeded(true);
300 void SAL_CALL SalAquaFilePicker::setCurrentFilter( const OUString& aTitle )
302     SolarMutexGuard aGuard;
304     ensureFilterHelper();
305     m_pFilterHelper->setCurrentFilter(aTitle);
306     updateFilterUI();
308     updateSaveFileNameExtension();
311 OUString SAL_CALL SalAquaFilePicker::getCurrentFilter()
313     SolarMutexGuard aGuard;
315     ensureFilterHelper();
317     return m_pFilterHelper->getCurrentFilter();
320 #pragma mark XFilterGroupManager
322 void SAL_CALL SalAquaFilePicker::appendFilterGroup( const OUString&, const uno::Sequence<beans::StringPair>& aFilters )
324     SolarMutexGuard aGuard;
326     ensureFilterHelper();
327     m_pFilterHelper->appendFilterGroup(aFilters);
328     m_pControlHelper->setFilterControlNeeded(true);
331 #pragma mark XFilePickerControlAccess
333 void SAL_CALL SalAquaFilePicker::setValue( sal_Int16 nControlId, sal_Int16 nControlAction, const uno::Any& rValue )
335     SolarMutexGuard aGuard;
337     m_pControlHelper->setValue(nControlId, nControlAction, rValue);
339     if (nControlId == ExtendedFilePickerElementIds::CHECKBOX_AUTOEXTENSION && m_nDialogType == NAVIGATIONSERVICES_SAVE) {
340         updateSaveFileNameExtension();
341     }
344 uno::Any SAL_CALL SalAquaFilePicker::getValue( sal_Int16 nControlId, sal_Int16 nControlAction )
346     uno::Any aValue = m_pControlHelper->getValue(nControlId, nControlAction);
348     return aValue;
351 void SAL_CALL SalAquaFilePicker::enableControl( sal_Int16 nControlId, sal_Bool bEnable )
353     m_pControlHelper->enableControl(nControlId, bEnable);
356 void SAL_CALL SalAquaFilePicker::setLabel( sal_Int16 nControlId, const OUString& aLabel )
358     SolarMutexGuard aGuard;
360     NSString* sLabel = [NSString stringWithOUString:aLabel];
361     m_pControlHelper->setLabel( nControlId, sLabel ) ;
364 OUString SAL_CALL SalAquaFilePicker::getLabel( sal_Int16 nControlId )
366     return m_pControlHelper->getLabel(nControlId);
369 #pragma mark XInitialization
371 void SAL_CALL SalAquaFilePicker::initialize( const uno::Sequence<uno::Any>& aArguments )
373     SolarMutexGuard aGuard;
375     // parameter checking
376     uno::Any aAny;
377     if( 0 == aArguments.getLength() )
378         throw lang::IllegalArgumentException("no arguments",
379                                              static_cast<XFilePicker*>( static_cast<XFilePicker3*>(this) ), 1 );
381     aAny = aArguments[0];
383     if( ( aAny.getValueType() != ::cppu::UnoType<sal_Int16>::get() ) &&
384         (aAny.getValueType() != ::cppu::UnoType<sal_Int8>::get() ) )
385         throw lang::IllegalArgumentException("invalid argument type",
386                                              static_cast<XFilePicker*>( static_cast<XFilePicker3*>(this) ), 1 );
388     sal_Int16 templateId = -1;
389     aAny >>= templateId;
391     switch( templateId )
392     {
393         case FILEOPEN_SIMPLE:
394             m_nDialogType = NAVIGATIONSERVICES_OPEN;
395             break;
396         case FILESAVE_SIMPLE:
397             m_nDialogType = NAVIGATIONSERVICES_SAVE;
398             break;
399         case FILESAVE_AUTOEXTENSION_PASSWORD:
400             m_nDialogType = NAVIGATIONSERVICES_SAVE;
401             break;
402         case FILESAVE_AUTOEXTENSION_PASSWORD_FILTEROPTIONS:
403             m_nDialogType = NAVIGATIONSERVICES_SAVE;
404             break;
405         case FILESAVE_AUTOEXTENSION_SELECTION:
406             m_nDialogType = NAVIGATIONSERVICES_SAVE;
407             break;
408         case FILESAVE_AUTOEXTENSION_TEMPLATE:
409             m_nDialogType = NAVIGATIONSERVICES_SAVE;
410             break;
411         case FILEOPEN_LINK_PREVIEW_IMAGE_TEMPLATE:
412             m_nDialogType = NAVIGATIONSERVICES_OPEN;
413             break;
414         case FILEOPEN_LINK_PREVIEW_IMAGE_ANCHOR:
415             m_nDialogType = NAVIGATIONSERVICES_OPEN;
416             break;
417         case FILEOPEN_PLAY:
418             m_nDialogType = NAVIGATIONSERVICES_OPEN;
419             break;
420         case FILEOPEN_LINK_PLAY:
421             m_nDialogType = NAVIGATIONSERVICES_OPEN;
422             break;
423         case FILEOPEN_READONLY_VERSION:
424             m_nDialogType = NAVIGATIONSERVICES_OPEN;
425             break;
426         case FILEOPEN_LINK_PREVIEW:
427             m_nDialogType = NAVIGATIONSERVICES_OPEN;
428             break;
429         case FILESAVE_AUTOEXTENSION:
430             m_nDialogType = NAVIGATIONSERVICES_SAVE;
431             break;
432         case FILEOPEN_PREVIEW:
433             m_nDialogType = NAVIGATIONSERVICES_OPEN;
434             break;
435         default:
436             throw lang::IllegalArgumentException("Unknown template",
437                                                  static_cast<XFilePicker*>( static_cast<XFilePicker3*>(this) ),
438                                                  1 );
439     }
441     m_pControlHelper->initialize(templateId);
443     implInitialize();
446 #pragma mark XCancellable
448 void SAL_CALL SalAquaFilePicker::cancel()
450     SolarMutexGuard aGuard;
452     if (m_pDialog != nil) {
453         [m_pDialog cancel:nil];
454     }
457 #pragma mark XEventListener
459 void SalAquaFilePicker::disposing( const lang::EventObject& aEvent )
461     SolarMutexGuard aGuard;
463     uno::Reference<XFilePickerListener> xFilePickerListener( aEvent.Source, css::uno::UNO_QUERY );
465     if( xFilePickerListener.is() )
466         removeFilePickerListener( xFilePickerListener );
469 #pragma mark XServiceInfo
471 OUString SAL_CALL SalAquaFilePicker::getImplementationName()
473     return "com.sun.star.ui.dialogs.SalAquaFilePicker";
476 sal_Bool SAL_CALL SalAquaFilePicker::supportsService( const OUString& sServiceName )
478     return cppu::supportsService(this, sServiceName);
481 uno::Sequence<OUString> SAL_CALL SalAquaFilePicker::getSupportedServiceNames()
483     return FilePicker_getSupportedServiceNames();
486 #pragma mark Misc/Private
488 void SalAquaFilePicker::fileSelectionChanged( FilePickerEvent aEvent )
490     if (m_xListener.is())
491         m_xListener->fileSelectionChanged( aEvent );
494 void SalAquaFilePicker::directoryChanged( FilePickerEvent aEvent )
496     if (m_xListener.is())
497         m_xListener->directoryChanged( aEvent );
500 void SalAquaFilePicker::controlStateChanged( FilePickerEvent aEvent )
502     if (m_xListener.is())
503         m_xListener->controlStateChanged( aEvent );
506 void SalAquaFilePicker::dialogSizeChanged()
508     if (m_xListener.is())
509         m_xListener->dialogSizeChanged();
513 // Misc
515 void SalAquaFilePicker::ensureFilterHelper()
517     SolarMutexGuard aGuard;
519     if (nullptr == m_pFilterHelper) {
520         m_pFilterHelper = new FilterHelper;
521         m_pControlHelper->setFilterHelper(m_pFilterHelper);
522         [m_pDelegate setFilterHelper:m_pFilterHelper];
523     }
526 void SalAquaFilePicker::updateFilterUI()
528     m_pControlHelper->updateFilterUI();
531 void SalAquaFilePicker::updateSaveFileNameExtension()
533     if (m_nDialogType != NAVIGATIONSERVICES_SAVE) {
534         return;
535     }
537     // we need to set this here again because initial setting does
538     //[m_pDialog setExtensionHidden:YES];
540     SolarMutexGuard aGuard;
542     if (!m_pControlHelper->isAutoExtensionEnabled()) {
543         SAL_WNODEPRECATED_DECLARATIONS_PUSH // setAllowedFileTypes (12.0)
544         [m_pDialog setAllowedFileTypes:nil];
545         SAL_WNODEPRECATED_DECLARATIONS_POP
546         [m_pDialog setAllowsOtherFileTypes:YES];
547     } else {
548         ensureFilterHelper();
550         OUStringList aStringList = m_pFilterHelper->getCurrentFilterSuffixList();
551         if( aStringList.empty()) // #i9328#
552             return;
554         OUString suffix = (*(aStringList.begin())).copy(1);
555         NSString *requiredFileType = [NSString stringWithOUString:suffix];
557         SAL_WNODEPRECATED_DECLARATIONS_PUSH // setAllowedFileTypes (12.0)
558         [m_pDialog setAllowedFileTypes:[NSArray arrayWithObjects:requiredFileType, nil]];
559         SAL_WNODEPRECATED_DECLARATIONS_POP
561         [m_pDialog setAllowsOtherFileTypes:NO];
562     }
565 void SalAquaFilePicker::filterControlChanged()
567     if (m_pDialog == nil) {
568         return;
569     }
571     SolarMutexGuard aGuard;
573     updateSaveFileNameExtension();
575     [m_pDialog validateVisibleColumns];
577     FilePickerEvent evt;
578     evt.ElementId = LISTBOX_FILTER;
579     controlStateChanged( evt );
582 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
583 fpicker_SalAquaFilePicker_get_implementation(
584     css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&)
586     return cppu::acquire(new SalAquaFilePicker());
590 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */