/* -*- mode: C++; tab-width: 4; c-basic-offset: 4; -*- */ /* AbiSource Application Framework * Copyright (C) 1998 AbiSource, Inc. * Copyright (C) 2001-2003, 2009 Hubert Figuiere * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include #include #include #include #include #include #include "ut_assert.h" #include "ut_debugmsg.h" #include "ut_misc.h" #include "ut_string.h" #include "xap_CocoaDlg_FileOpenSaveAs.h" #include "xap_CocoaDialog_Utilities.h" #include "xap_CocoaApp.h" #include "xap_CocoaFrame.h" #include "xap_Dialog_Id.h" #include "xap_Dlg_MessageBox.h" #include "xap_Prefs.h" #include "xap_Strings.h" #include "ie_imp.h" #include "ie_impGraphic.h" #include "ie_types.h" #define PREVIEW_WIDTH 100 #define PREVIEW_HEIGHT 100 @implementation XAP_OpenSavePanel_AccessoryController - (id)initWithXAP:(XAP_CocoaDialog_FileOpenSaveAs*)xap { if (![super init]) { return nil; } _xap = xap; return self; } - (NSView *)fileTypeAccessoryView { return oFTAccessoryView; } - (void)setFileTypeLabel:(const std::string &)label { SetNSControlLabel(oFTLabel, label); } - (void)setSelectedFileType:(int)type { [oFTPopUp selectItem:[[oFTPopUp menu] itemWithTag:type]]; } - (void)removeItemsOfFileTypesMenu { [oFTPopUp removeAllItems]; } - (void)addItemWithTitle:(NSString *)title fileType:(int)type { [oFTPopUp addItemWithTitle:title]; [[oFTPopUp lastItem] setTag:type]; } - (IBAction)selectFileType:(id)sender { UT_UNUSED(sender); _xap->_setSelectedFileType([[sender selectedItem] tag]); } // delegate method #if 0 - (BOOL)panel:(id)sender shouldShowFilename:(NSString *)filename { return YES; } #endif @end /*****************************************************************/ static void addSuffixesToFileTypes(NSMutableArray * fileTypes, const char * suffix_list) { std::string suffix; while (const char * ptr1 = strstr(suffix_list, "*.")) { ptr1 += 2; bool bSingleExtension = true; const char * ptr2 = ptr1; while (*ptr2 && (*ptr2 != ';')) { if (*ptr2++ == '.') { bSingleExtension = false; } } suffix.assign(ptr1, ptr2 - ptr1); if (bSingleExtension) { UT_DEBUGMSG(("added suffix %s\n", suffix.c_str())); [fileTypes addObject:[NSString stringWithUTF8String:(suffix.c_str())]]; } suffix_list = ptr2; } } XAP_Dialog * XAP_CocoaDialog_FileOpenSaveAs::static_constructor(XAP_DialogFactory * pFactory, XAP_Dialog_Id dlgid) { XAP_CocoaDialog_FileOpenSaveAs * p = new XAP_CocoaDialog_FileOpenSaveAs(pFactory,dlgid); return p; } XAP_CocoaDialog_FileOpenSaveAs::XAP_CocoaDialog_FileOpenSaveAs(XAP_DialogFactory * pDlgFactory, XAP_Dialog_Id dlgid) : XAP_Dialog_FileOpenSaveAs(pDlgFactory,dlgid), m_accessoryViewsController(nil), m_panel(nil), m_fileTypes(nil), m_szFileTypeDescription(0), m_szFileTypeCount(0) { // } XAP_CocoaDialog_FileOpenSaveAs::~XAP_CocoaDialog_FileOpenSaveAs(void) { if (m_accessoryViewsController) { [m_accessoryViewsController release]; } if (m_fileTypes) { [m_fileTypes release]; } } NSSavePanel * XAP_CocoaDialog_FileOpenSaveAs::_makeOpenPanel() { NSOpenPanel *openPanel = [[NSOpenPanel openPanel] retain]; [openPanel setAllowsMultipleSelection:NO]; [openPanel setCanChooseDirectories:NO]; [openPanel setCanChooseFiles:YES]; // this call is 10.3 only. if ([openPanel respondsToSelector:@selector(setCanCreateDirectories:)]) [openPanel setCanCreateDirectories:NO]; [openPanel setCanSelectHiddenExtension:NO]; [openPanel setExtensionHidden:NO]; for (UT_uint32 i = 0; i < m_szFileTypeCount; i++) { addSuffixesToFileTypes(m_fileTypes, m_szSuffixes[i]); } if([m_fileTypes count]) { [openPanel setAllowedFileTypes:m_fileTypes]; } else { [openPanel setAllowedFileTypes:nil]; } return openPanel; } NSSavePanel * XAP_CocoaDialog_FileOpenSaveAs::_makeSavePanel(const std::string & fileTypeLabel) { NSSavePanel * savePanel = [[NSSavePanel savePanel] retain]; // this call is 10.3 only. if ([savePanel respondsToSelector:@selector(setCanCreateDirectories:)]) [savePanel setCanCreateDirectories:YES]; [savePanel setCanSelectHiddenExtension:YES]; [savePanel setExtensionHidden:NO]; [m_accessoryViewsController setFileTypeLabel:fileTypeLabel]; /* File-types PopUp: */ [m_accessoryViewsController removeItemsOfFileTypesMenu]; const XAP_StringSet * pSS = XAP_App::getApp()->getStringSet(); std::string label; if (pSS->getValueUTF8(XAP_STRING_ID_DLG_FOSA_FileTypeAutoDetect, label)) { NSString * title = [NSString stringWithUTF8String:(label.c_str())]; int type = (int) XAP_DIALOG_FILEOPENSAVEAS_FILE_TYPE_AUTO; [m_accessoryViewsController addItemWithTitle:title fileType:type]; } UT_sint32 defaultFileType = m_nDefaultFileType; for (UT_uint32 i = 0; i < m_szFileTypeCount; i++) { NSString * title = [NSString stringWithUTF8String:m_szDescriptions[i]]; int type = m_nTypeList[i]; [m_accessoryViewsController addItemWithTitle:title fileType:type]; } [m_accessoryViewsController setSelectedFileType:defaultFileType]; _setSelectedFileType(defaultFileType); [savePanel setAccessoryView:[m_accessoryViewsController fileTypeAccessoryView]]; return savePanel; } /*****************************************************************/ void XAP_CocoaDialog_FileOpenSaveAs::runModal(XAP_Frame * /*pFrame*/) { if (!m_accessoryViewsController) { m_accessoryViewsController = [[XAP_OpenSavePanel_AccessoryController alloc] initWithXAP:this]; if (m_accessoryViewsController) { if (![NSBundle loadNibNamed:@"xap_CocoaFileOpen_Views" owner:m_accessoryViewsController]) { NSLog (@"Couldn't load nib xap_CocoaFileOpen_Views"); [m_accessoryViewsController release]; m_accessoryViewsController = 0; } } } UT_ASSERT(m_accessoryViewsController); if (!m_accessoryViewsController) return; const XAP_StringSet * pSS = XAP_App::getApp()->getStringSet(); // do we want to let this function handle stating the Cocoa // directory for writability? Save/Export operations will want // this, open/import will not. bool bCheckWritePermission = false; bool bOpenPanel = false; bool bSavePanel = false; std::string szTitle; std::string szFileTypeLabel; switch (m_id) { case XAP_DIALOG_ID_INSERTMATHML: bOpenPanel = true; pSS->getValueUTF8(XAP_STRING_ID_DLG_FOSA_InsertMath, szTitle); pSS->getValueUTF8(XAP_STRING_ID_DLG_FOSA_FileInsertMath, szFileTypeLabel); bCheckWritePermission = false; break; case XAP_DIALOG_ID_INSERT_PICTURE: bOpenPanel = true; pSS->getValueUTF8(XAP_STRING_ID_DLG_IP_Title, szTitle); pSS->getValueUTF8(XAP_STRING_ID_DLG_FOSA_FileOpenTypeLabel, szFileTypeLabel); bCheckWritePermission = false; break; case XAP_DIALOG_ID_FILE_OPEN: bOpenPanel = true; pSS->getValueUTF8(XAP_STRING_ID_DLG_FOSA_OpenTitle, szTitle); pSS->getValueUTF8(XAP_STRING_ID_DLG_FOSA_FileOpenTypeLabel, szFileTypeLabel); bCheckWritePermission = false; break; case XAP_DIALOG_ID_FILE_SAVEAS: case XAP_DIALOG_ID_FILE_SAVE_IMAGE: bSavePanel = true; pSS->getValueUTF8(XAP_STRING_ID_DLG_FOSA_SaveAsTitle, szTitle); pSS->getValueUTF8(XAP_STRING_ID_DLG_FOSA_FileSaveTypeLabel, szFileTypeLabel); bCheckWritePermission = true; break; case XAP_DIALOG_ID_FILE_IMPORT: bOpenPanel = true; pSS->getValueUTF8(XAP_STRING_ID_DLG_FOSA_ImportTitle, szTitle); pSS->getValueUTF8(XAP_STRING_ID_DLG_FOSA_FileOpenTypeLabel, szFileTypeLabel); bCheckWritePermission = false; break; case XAP_DIALOG_ID_FILE_EXPORT: bSavePanel = true; pSS->getValueUTF8(XAP_STRING_ID_DLG_FOSA_ExportTitle, szTitle); pSS->getValueUTF8(XAP_STRING_ID_DLG_FOSA_FileSaveTypeLabel, szFileTypeLabel); bCheckWritePermission = true; break; case XAP_DIALOG_ID_INSERT_FILE: bOpenPanel = true; pSS->getValueUTF8(XAP_STRING_ID_DLG_FOSA_InsertTitle, szTitle); pSS->getValueUTF8(XAP_STRING_ID_DLG_FOSA_FileOpenTypeLabel, szFileTypeLabel); bCheckWritePermission = false; break; case XAP_DIALOG_ID_PRINTTOFILE: bSavePanel = true; pSS->getValueUTF8(XAP_STRING_ID_DLG_FOSA_PrintToFileTitle, szTitle); pSS->getValueUTF8(XAP_STRING_ID_DLG_FOSA_FilePrintTypeLabel, szFileTypeLabel); bCheckWritePermission = true; break; default: UT_ASSERT(UT_SHOULD_NOT_HAPPEN); break; } if (!m_fileTypes) m_fileTypes = [[NSMutableArray alloc] initWithCapacity:4]; UT_ASSERT(m_fileTypes); if (!m_fileTypes) return; m_panel = nil; // TODO WTF is this not in XP land? m_szFileTypeCount = g_strv_length((gchar **) m_szDescriptions); UT_ASSERT(g_strv_length((gchar **) m_szSuffixes) == m_szFileTypeCount); if (bOpenPanel) { m_panel = _makeOpenPanel(); } else if (bSavePanel) { m_panel = _makeSavePanel(szFileTypeLabel); } UT_ASSERT(m_panel); if (!m_panel) return; [m_panel setTitle:[NSString stringWithUTF8String:(szTitle.c_str())]]; [m_panel setDelegate:m_accessoryViewsController]; // use the persistence info and/or the suggested filename // to properly seed the dialog. NSString * szPersistDirectory = nil; NSString * szPersistFile = nil; if (!m_szInitialPathname || !*m_szInitialPathname) { // the caller did not supply initial pathname // (or supplied an empty one). see if we have // some persistent info. UT_ASSERT(!m_bSuggestName); if (m_szPersistPathname) { // we have a pathname from a previous use, // extract the directory portion and start // the dialog there (but without a filename). szPersistDirectory = [NSString stringWithUTF8String:m_szPersistPathname]; } else { // no initial pathname given and we don't have // a pathname from a previous use, so just let // it come up in the current working directory. } } else { // we have an initial pathname (the name of the document // in the frame that we were invoked on). if the caller // wanted us to suggest a filename, use the initial // pathname as is. if not, use the directory portion of // it. if (m_bSuggestName) { /* use m_szInitialPathname */ NSString * path = [NSString stringWithUTF8String:m_szInitialPathname]; szPersistDirectory = [path stringByDeletingLastPathComponent]; if ([szPersistDirectory isEqualToString:path]) // shouldn't happen { szPersistFile = [NSString string]; } else { szPersistFile = [path lastPathComponent]; } /* Slightly odd case where we're saving a file whose original document type * (guessing by the suffix) is not supported for saving to. */ if ((m_id == XAP_DIALOG_ID_FILE_SAVEAS) && [szPersistFile length]) { NSString * extension = [szPersistFile pathExtension]; std::string szSaveTypeSuffix = UT_pathSuffix(m_szSuffixes[m_nDefaultFileType]); if ([extension length] && !szSaveTypeSuffix.empty()) { if (*(szSaveTypeSuffix.c_str()) == '.') { NSString * new_suffix = [NSString stringWithUTF8String:(szSaveTypeSuffix.c_str() + 1)]; if (![new_suffix isEqualToString:extension]) { /* okay, the suggested extension doesn't match the desired extension */ NSString * filename = [szPersistFile stringByDeletingPathExtension]; szPersistFile = [filename stringByAppendingPathExtension:new_suffix]; } } } } } else { /* use directory(m_szInitialPathname) */ NSString * path = [NSString stringWithUTF8String:m_szInitialPathname]; szPersistDirectory = [path stringByDeletingLastPathComponent]; szPersistFile = [NSString string]; } } int result; m_bOpenPanel = bOpenPanel; m_bPanelActive = true; do { m_bIgnoreCancel = false; if (m_bOpenPanel) { // [m_panel setPanelCanOrderOut:YES]; NSOpenPanel * openPanel = (NSOpenPanel*)m_panel; if ([m_fileTypes count]) { NSString * type = (NSString *) [m_fileTypes objectAtIndex:0]; if (szPersistFile) { NSString * extension = [szPersistFile pathExtension]; if (![extension isEqualToString:type]) { szPersistFile = nil; } } } if ([m_fileTypes count]) { result = [openPanel runModalForDirectory:szPersistDirectory file:szPersistFile types:m_fileTypes]; } else { result = [openPanel runModalForDirectory:szPersistDirectory file:szPersistFile types:nil]; } result = (result == NSOKButton) ? NSFileHandlingPanelOKButton : NSFileHandlingPanelCancelButton; } else { if ([m_fileTypes count]) { NSString * type = (NSString *) [m_fileTypes objectAtIndex:0]; [m_panel setRequiredFileType:type]; if (szPersistFile) { NSString * extension = [szPersistFile pathExtension]; if ([extension length]) { if (![extension isEqualToString:type]) { szPersistFile = [szPersistFile stringByDeletingPathExtension]; szPersistFile = [szPersistFile stringByAppendingPathExtension:type]; } } else { szPersistFile = [szPersistFile stringByAppendingPathExtension:type]; } } } else { [m_panel setRequiredFileType:nil]; } // [m_panel setPanelCanOrderOut:YES]; result = [m_panel runModalForDirectory:szPersistDirectory file:szPersistFile]; } szPersistDirectory = [m_panel directory]; szPersistFile = [m_panel filename]; if (szPersistFile) szPersistFile = [szPersistFile lastPathComponent]; } while (m_bIgnoreCancel); m_bPanelActive = false; szPersistFile = [m_panel filename]; if ((result == NSFileHandlingPanelOKButton) && szPersistFile) { FREEP (m_szFinalPathname); // g_free before reassigning m_szFinalPathname = g_strdup([szPersistFile UTF8String]); m_answer = a_OK; } } void XAP_CocoaDialog_FileOpenSaveAs::_setSelectedFileType (UT_sint32 type) { m_nFileType = type; m_szFileTypeDescription = 0; [m_fileTypes removeAllObjects]; if (m_nFileType != XAP_DIALOG_FILEOPENSAVEAS_FILE_TYPE_AUTO) { for (UT_uint32 i = 0; i < m_szFileTypeCount; i++) { if (m_nFileType == m_nTypeList[i]) { m_szFileTypeDescription = m_szDescriptions[i]; addSuffixesToFileTypes(m_fileTypes, m_szSuffixes[i]); } } } if([m_fileTypes count]) { [m_panel setAllowedFileTypes:m_fileTypes]; } else { [m_panel setAllowedFileTypes:nil]; } [m_panel update]; // if (m_bPanelActive) { // [m_panel setPanelCanOrderOut:NO]; // m_bIgnoreCancel = true; // [NSApp stopModal]; // } }