1 /* -*- mode: C++; tab-width: 4; c-basic-offset: 4; -*- */
2 
3 /* AbiSource Application Framework
4  * Copyright (C) 1998 AbiSource, Inc.
5  * Copyright (C) 2009 Hubert Figuiere
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20  * 02110-1301 USA.
21  */
22 
23 /*
24  * Port to Maemo Development Platform
25  * Author: INdT - Renato Araujo <renato.filho@indt.org.br>
26  */
27 
28 
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32 
33 #include <gtk/gtk.h>
34 #include <gdk/gdkkeysyms.h> // this include seems to fix 12332 (it defines GDK_Escape)
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <strings.h>
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #include <unistd.h>
42 #include "ut_string.h"
43 #include "ut_assert.h"
44 #include "xap_UnixDialogHelper.h"
45 #include "xap_GtkComboBoxHelpers.h"
46 #include "xap_Dialog_Id.h"
47 #include "xap_Dlg_MessageBox.h"
48 #include "xap_UnixDlg_FileOpenSaveAs.h"
49 #include "xap_UnixApp.h"
50 #include "xap_Frame.h"
51 #include "xap_UnixFrameImpl.h"
52 #include "xap_Strings.h"
53 #include "xap_Prefs.h"
54 #include "ut_debugmsg.h"
55 #include "ut_string_class.h"
56 #include "ut_path.h"
57 #include "ut_png.h"
58 #include "ut_svg.h"
59 #include "ut_misc.h"
60 #include "fg_Graphic.h"
61 #include "fg_GraphicRaster.h"
62 #include "ie_impGraphic.h"
63 
64 #include "gr_UnixImage.h"
65 #include "gr_Painter.h"
66 #include "gr_UnixCairoGraphics.h"
67 #include "ut_bytebuf.h"
68 
69 #if defined(EMBEDDED_TARGET) && EMBEDDED_TARGET == EMBEDDED_TARGET_HILDON
70 #include <hildon/hildon-file-chooser-dialog.h>
71 #endif
72 
73 
74 #include <sys/stat.h>
75 
76 #include "../../../wp/impexp/xp/ie_types.h"
77 #include "../../../wp/impexp/xp/ie_imp.h"
78 #include "../../../wp/impexp/xp/ie_exp.h"
79 #include "../../../wp/impexp/xp/ie_impGraphic.h"
80 
81 #define PREVIEW_WIDTH  100
82 #define PREVIEW_HEIGHT 100
83 
84 
85 
86 /*****************************************************************/
static_constructor(XAP_DialogFactory * pFactory,XAP_Dialog_Id id)87 XAP_Dialog * XAP_UnixDialog_FileOpenSaveAs::static_constructor(XAP_DialogFactory * pFactory,
88 															 XAP_Dialog_Id id)
89 {
90 	XAP_UnixDialog_FileOpenSaveAs * p = new XAP_UnixDialog_FileOpenSaveAs(pFactory,id);
91 	return p;
92 }
93 
XAP_UnixDialog_FileOpenSaveAs(XAP_DialogFactory * pDlgFactory,XAP_Dialog_Id id)94 XAP_UnixDialog_FileOpenSaveAs::XAP_UnixDialog_FileOpenSaveAs(XAP_DialogFactory * pDlgFactory,
95 														   XAP_Dialog_Id id)
96   : XAP_Dialog_FileOpenSaveAs(pDlgFactory,id), m_FC(0), m_preview(0), m_bSave(true)
97 {
98 	m_szFinalPathnameCandidate = NULL;
99 }
100 
~XAP_UnixDialog_FileOpenSaveAs(void)101 XAP_UnixDialog_FileOpenSaveAs::~XAP_UnixDialog_FileOpenSaveAs(void)
102 {
103 	FREEP(m_szFinalPathnameCandidate);
104 }
105 
106 /*****************************************************************/
107 
s_dialog_response(GtkWidget *,gint answer,XAP_Dialog_FileOpenSaveAs::tAnswer * ptr,bool bQuit=true)108 static void s_dialog_response(GtkWidget * /* widget */,
109 						gint answer,
110 						XAP_Dialog_FileOpenSaveAs::tAnswer * ptr, bool bQuit = true)
111 {
112 	switch (answer)
113 	{
114 		case GTK_RESPONSE_CANCEL:
115 		case GTK_RESPONSE_ACCEPT:
116 		case GTK_RESPONSE_OK:
117 			if (answer == GTK_RESPONSE_CANCEL)
118 				*ptr = XAP_Dialog_FileOpenSaveAs::a_CANCEL;
119 			else
120 				*ptr = XAP_Dialog_FileOpenSaveAs::a_OK;
121 			if (bQuit)
122 				gtk_main_quit();
123 			break;
124 		default:
125 			// do nothing
126 			break;
127 	}
128 }
129 
dialog_response(GtkWidget * widget,gint answer,XAP_Dialog_FileOpenSaveAs::tAnswer * ptr)130 static void dialog_response(GtkWidget *widget,
131 							gint answer,
132 							XAP_Dialog_FileOpenSaveAs::tAnswer * ptr) {
133 	s_dialog_response(widget, answer, ptr);
134 }
135 
s_delete_clicked(GtkWidget *,GdkEvent *,gpointer data)136 static void s_delete_clicked(GtkWidget 	* /*widget*/,
137 							 GdkEvent 	* /*event*/,
138 							 gpointer 	 data)
139 {
140 	XAP_UnixDialog_FileOpenSaveAs *dlg = static_cast<XAP_UnixDialog_FileOpenSaveAs *>(data);
141 	dlg->onDeleteCancel();
142 	gtk_main_quit();
143 }
144 
145 #if GTK_CHECK_VERSION(3,0,0)
s_preview_draw(GtkWidget *,cairo_t *,gpointer ptr)146 static gint s_preview_draw(GtkWidget * /* widget */,
147 			      cairo_t * /* cr */,
148 			      gpointer ptr)
149 #else
150 static gint s_preview_exposed(GtkWidget * /* widget */,
151 						   GdkEventExpose*,
152 			      gpointer ptr)
153 #endif
154 {
155         XAP_UnixDialog_FileOpenSaveAs * dlg = static_cast<XAP_UnixDialog_FileOpenSaveAs *> (ptr);
156 	UT_ASSERT(dlg);
157 	dlg->previewPicture();
158 	return FALSE;
159 }
160 
s_filetypechanged(GtkWidget * w,gpointer p)161 static void s_filetypechanged(GtkWidget * w, gpointer p)
162 {
163 	XAP_UnixDialog_FileOpenSaveAs * dlg = static_cast<XAP_UnixDialog_FileOpenSaveAs *>(p);
164 	dlg->fileTypeChanged(w);
165 }
166 
167 static gint
fsel_key_event(GtkWidget * widget,GdkEventKey * event,XAP_Dialog_FileOpenSaveAs::tAnswer * answer)168 fsel_key_event (GtkWidget * widget, GdkEventKey * event, XAP_Dialog_FileOpenSaveAs::tAnswer * answer)
169 {
170 	if (event->keyval == GDK_KEY_Escape) {
171 		g_signal_stop_emission_by_name (G_OBJECT (widget), "key_press_event");
172 		s_dialog_response(widget, GTK_RESPONSE_CANCEL, answer);
173 		return TRUE;
174 	}
175 
176 	return FALSE;
177 }
178 
s_file_activated(GtkWidget * w,XAP_Dialog_FileOpenSaveAs::tAnswer * answer)179 static void s_file_activated(GtkWidget * w, XAP_Dialog_FileOpenSaveAs::tAnswer * answer)
180 {
181 	// whenever the "file-activated" signal is called, it will also be followed
182 	// (or preceded?) by a "response" signal. That "response" signal will manage
183 	// the closing of the dialog for us. Now we don't want to close the dialog
184 	// twice, hence the last 'false' parameter.
185 	// Hardly elegant, but none of this code is :/ It fixes bug #11647 too - MARCM.
186 	s_dialog_response(w, GTK_RESPONSE_ACCEPT, answer, false);
187 }
188 
file_selection_changed(GtkTreeSelection *,gpointer ptr)189 static void file_selection_changed  (GtkTreeSelection  * /*selection*/,
190                                     gpointer           ptr)
191 {
192   XAP_UnixDialog_FileOpenSaveAs * dlg = static_cast<XAP_UnixDialog_FileOpenSaveAs *> (ptr);
193 
194   UT_ASSERT(dlg);
195   dlg->previewPicture();
196 }
197 
_run_gtk_main(XAP_Frame * pFrame,GtkWidget * filetypes_pulldown)198 bool XAP_UnixDialog_FileOpenSaveAs::_run_gtk_main(XAP_Frame * pFrame,
199 													 GtkWidget * filetypes_pulldown)
200 {
201 	/*
202 	  Run the dialog in a loop to catch bad filenames.
203 	  The location of this check being in this dialog loop
204 	  could be considered temporary.  Doing this matches the Windows
205 	  common control behavior (where the dialog checks everything
206 	  for the programmer), but lacks flexibility for different
207 	  uses of this dialog (file export, print export, directory
208 	  (not file) selection).
209 
210 	  This check might need to be moved into the ap code which calls
211 	  this dialog, and certain interfaces exposed so that the
212 	  dialog is displayed throughout the verification.
213 
214 	  For right now you can signal this check on and off with
215 	  bCheckWritePermission.
216 	*/
217 
218 	char * szDialogFilename = NULL;		// this is the file name returned from the dialog
219 	char * szFinalPathname = NULL;		// this is the file name after suffix addition, if any
220 	char * szFinalPathnameCopy = NULL;	// one to mangle when looking for dirs, etc.
221 
222 	char * pLastSlash;
223 
224 	// if m_bSave is not set, we're looking to OPEN a file.
225 	// otherwise we are looking to SAVE a file.
226 	if (!m_bSave)
227 	{
228 		while (1)
229 		{
230 			gtk_main();
231 			if (m_answer == a_CANCEL)			// The easy way out
232 				return false;
233 
234 			m_szFinalPathnameCandidate = gtk_file_chooser_get_uri(m_FC);
235 			UT_ASSERT(m_szFinalPathnameCandidate);
236 			return (m_answer == a_OK);
237 		}
238 	}
239 	else
240 	{
241 		while(1)
242 		{
243 			gtk_main();
244 			if (m_answer == a_CANCEL)			// The easy way out
245 				return false;
246 
247 			// Give us a filename we can mangle
248 
249 			szDialogFilename = gtk_file_chooser_get_uri(m_FC);
250 			if (!szDialogFilename)
251 				continue;
252 
253 			// We append the suffix of the default type, so the user doesn't
254 			// have to.  This is adapted from the Windows front-end code
255 			// (xap_Win32Dlg_FileOpenSaveAs.cpp), since it should act the same.
256 			// If, however, the user doesn't want suffixes, they don't have to have them.
257 			{
258 				//UT_uint32 end = g_strv_length(m_szSuffixes);
259    				UT_sint32 nFileType = XAP_comboBoxGetActiveInt(GTK_COMBO_BOX(filetypes_pulldown));
260 
261 				// set to first item, which should probably be auto detect
262 				// TODO : "probably" isn't very good.
263 				UT_uint32 nIndex = 0;
264 
265 				// the index in the types table will match the index in the suffix
266 				// table.  nFileType is the data we are searching for.
267 				if(m_nTypeList != NULL)
268 				{
269 					for (UT_uint32 i = 0; m_nTypeList[i]; i++)
270 					{
271 						if (m_nTypeList[i] == nFileType)
272 						{
273 							nIndex = i;
274 							break;
275 						}
276 					}
277 				}
278 
279 				bool wantSuffix = true;
280 				XAP_Prefs *pPrefs= XAP_App::getApp()->getPrefs();
281 				pPrefs->getPrefsValueBool(static_cast<const gchar *>(XAP_PREF_KEY_UseSuffix), &wantSuffix);
282 				UT_DEBUGMSG(("UseSuffix: %d\n", wantSuffix));
283 
284 				if (nFileType > 0 && getDialogId() != XAP_DIALOG_ID_FILE_SAVE_IMAGE) // 0 means autodetect
285 				{
286 					if (!UT_pathSuffix(szDialogFilename).empty())
287 					{
288 						// warn if we have a suffix that doesn't match the selected file type
289 						IE_ExpSniffer* pSniffer = IE_Exp::snifferForFileType(m_nTypeList[nIndex]);
290 						if (pSniffer && !pSniffer->recognizeSuffix(UT_pathSuffix(szDialogFilename).c_str()))
291 						{
292 							std::string msg;
293 							const XAP_StringSet * pSS = m_pApp->getStringSet();
294 							pSS->getValueUTF8(XAP_STRING_ID_DLG_FOSA_ExtensionDoesNotMatch, msg);
295 							if (pFrame->showMessageBox(msg.c_str(), XAP_Dialog_MessageBox::b_YN, XAP_Dialog_MessageBox::a_NO) != XAP_Dialog_MessageBox::a_YES)
296 								goto ContinueLoop;
297 						}
298 						szFinalPathname = g_strdup(szDialogFilename);
299 					}
300 					else if (wantSuffix)
301 					{
302 						// if the file doesn't have a suffix already, and the file type
303 						// is normal (special types are negative, like auto detect),
304 						// and the user wants extensions, slap a suffix on it.
305 						// add suffix based on selected file type
306                         // UT_UTF8String suffix (IE_Exp::preferredSuffixForFileType(m_nTypeList[nIndex]));
307 						// UT_uint32 length = strlen(szDialogFilename) + suffix.size() + 1;
308 
309 						// szFinalPathname = static_cast<char *>(UT_calloc(length,sizeof(char)));
310 
311 						// if (szFinalPathname)
312 						// {
313 						// 	char * p = szFinalPathname;
314 						// 	strcpy(p,szDialogFilename);
315 						// 	strcat(p,suffix.utf8_str());
316 						// }
317 
318                         std::string n = m_appendDefaultSuffixFunctor( szDialogFilename,
319                                                                       m_nTypeList[nIndex] );
320                         szFinalPathname = g_strdup( n.c_str() );
321 					}
322 					else
323 						szFinalPathname = g_strdup(szDialogFilename);
324 				}
325 				else
326 				{
327 					// the file type is special (auto detect)
328 					// set to plain name, and let the auto detector in the
329 					// exporter figure it out
330 					szFinalPathname = g_strdup(szDialogFilename);
331 				}
332 
333 				// g_free szDialogFilename since it's been put into szFinalPathname (with
334 				// or without changes) and it's invalid (missing an extension which
335 				// might have been appended)
336 
337 				FREEP(szDialogFilename);
338 			}
339 
340 			szFinalPathnameCopy = g_strdup(szFinalPathname);
341 
342 			if (UT_go_file_exists(szFinalPathnameCopy))
343 			{
344 				// we have an existing file, ask to overwrite
345 				if (_askOverwrite_YesNo(pFrame, szFinalPathname))
346 				{
347 					m_szFinalPathnameCandidate = g_strdup(szFinalPathname);
348 					goto ReturnTrue;
349 				}
350 
351 				goto ContinueLoop;
352 			}
353 
354 			// We have a string that may contain a path, and may have a file
355 			// at the end.  First, strip off a file (if it exists), and test
356 			// for a matching directory.  We can then proceed with the file
357 			// if another stat of that dir passes.
358 
359 			if (szFinalPathnameCopy && strlen(szFinalPathnameCopy))
360 				pLastSlash = strrchr(szFinalPathnameCopy,'/');
361 			else
362 				pLastSlash = NULL;
363 
364 			if (!pLastSlash)
365 			{
366 				_notifyError_OKOnly(pFrame,XAP_STRING_ID_DLG_InvalidPathname);
367 				goto ContinueLoop;
368 			}
369 
370 			m_szFinalPathnameCandidate = g_strdup(szFinalPathname);
371 			goto ReturnTrue;
372 
373 			// complain about write permission on the directory.
374 			// lop off ugly trailing slash only if we don't have
375 			// the root dir ('/') for a path
376 
377 			if (pLastSlash > szFinalPathnameCopy)
378 				*pLastSlash = 0;
379 
380 			_notifyError_OKOnly(pFrame,XAP_STRING_ID_DLG_NoSaveFile_DirNotWriteable,
381 								szFinalPathname);
382 		ContinueLoop:
383 			FREEP(szFinalPathnameCopy);
384 		}
385 	} /* if m_bSave */
386 
387 	/*NOTREACHED*/
388 
389 ReturnTrue:
390 	FREEP(szFinalPathnameCopy);
391 	FREEP(szFinalPathname);
392 	return true;
393 }
394 
395 
_askOverwrite_YesNo(XAP_Frame * pFrame,const char * fileName)396 bool XAP_UnixDialog_FileOpenSaveAs::_askOverwrite_YesNo(XAP_Frame * pFrame, const char * fileName)
397 {
398 	return (pFrame->showMessageBox(XAP_STRING_ID_DLG_OverwriteFile,
399 				       XAP_Dialog_MessageBox::b_YN,
400 				       XAP_Dialog_MessageBox::a_NO, // should this be YES?
401 				       fileName)
402 		== XAP_Dialog_MessageBox::a_YES);
403 }
404 
_notifyError_OKOnly(XAP_Frame * pFrame,XAP_String_Id sid)405 void XAP_UnixDialog_FileOpenSaveAs::_notifyError_OKOnly(XAP_Frame * pFrame, XAP_String_Id sid)
406 {
407 	pFrame->showMessageBox(sid,
408 			       XAP_Dialog_MessageBox::b_O,
409 			       XAP_Dialog_MessageBox::a_OK);
410 }
411 
_notifyError_OKOnly(XAP_Frame * pFrame,XAP_String_Id sid,const char * sz1)412 void XAP_UnixDialog_FileOpenSaveAs::_notifyError_OKOnly(XAP_Frame * pFrame,
413 							XAP_String_Id sid,
414 							const char * sz1)
415 {
416 	pFrame->showMessageBox(sid,
417 			       XAP_Dialog_MessageBox::b_O,
418 			       XAP_Dialog_MessageBox::a_OK,
419 			       sz1);
420 }
421 
fileTypeChanged(GtkWidget * w)422 void XAP_UnixDialog_FileOpenSaveAs::fileTypeChanged(GtkWidget * w)
423 {
424 	if (!m_bSave)
425 		return;
426 
427 	UT_sint32 nFileType = XAP_comboBoxGetActiveInt(GTK_COMBO_BOX(w));
428 	UT_DEBUGMSG(("File type widget is %p filetype number is %d \n",w,nFileType));
429     // I have no idea for 0, but XAP_DIALOG_FILEOPENSAVEAS_FILE_TYPE_AUTO
430     // definitely means "skip this"
431 	if((nFileType == 0) || (nFileType == XAP_DIALOG_FILEOPENSAVEAS_FILE_TYPE_AUTO))
432 	{
433 		return;
434 	}
435 
436 	gchar * filename = gtk_file_chooser_get_filename(m_FC);
437 	UT_String sFileName = filename;
438 	FREEP(filename);
439 
440 	UT_String sSuffix = m_szSuffixes[nFileType-1];
441 	sSuffix = sSuffix.substr(1,sSuffix.length()-1);
442 	UT_sint32 i = 0;
443 	bool bFoundComma = false;
444 	for(i=0; i< static_cast<UT_sint32>(sSuffix.length()); i++)
445 	{
446 		if(sSuffix[i] == ';')
447 		{
448 			bFoundComma = true;
449 			break;
450 		}
451 	}
452 	if(bFoundComma)
453 	{
454 		sSuffix = sSuffix.substr(0,i);
455 	}
456 
457 //
458 // Hard code a suffix
459 //
460 	if(strstr(sSuffix.c_str(),"gz") != NULL)
461 	{
462 		sSuffix = ".zabw";
463 	}
464 	bool bFoundSuffix = false;
465 	for(i= sFileName.length()-1; i> 0; i--)
466 	{
467 		if(sFileName[i] == '.')
468 		{
469 			bFoundSuffix = true;
470 			break;
471 		}
472 	}
473 	if(!bFoundSuffix)
474 	{
475 		return;
476 	}
477 	sFileName = sFileName.substr(0,i);
478 	sFileName += sSuffix;
479 
480 	gtk_file_chooser_set_current_name(m_FC, UT_basename(sFileName.c_str()));
481 }
482 
onDeleteCancel()483 void XAP_UnixDialog_FileOpenSaveAs::onDeleteCancel()
484 {
485 	if (m_FC != NULL && gtk_widget_has_grab(GTK_WIDGET (m_FC))) {
486 		gtk_grab_remove (GTK_WIDGET (m_FC));
487 	}
488 	m_FC = NULL;
489 	m_answer = a_CANCEL;
490 }
491 
492 /*****************************************************************/
493 
runModal(XAP_Frame * pFrame)494 void XAP_UnixDialog_FileOpenSaveAs::runModal(XAP_Frame * pFrame)
495 {
496 	const XAP_StringSet * pSS = m_pApp->getStringSet();
497     std::string szTitle;
498     std::string szFileTypeLabel;
499 
500 	switch (m_id)
501 	{
502 		case XAP_DIALOG_ID_INSERT_PICTURE:
503 			{
504 				pSS->getValueUTF8(XAP_STRING_ID_DLG_IP_Title, szTitle);
505 				pSS->getValueUTF8(XAP_STRING_ID_DLG_FOSA_FileOpenTypeLabel, szFileTypeLabel);
506 				m_bSave = false;
507 				break;
508 			}
509 		case XAP_DIALOG_ID_FILE_OPEN:
510 			{
511 				pSS->getValueUTF8(XAP_STRING_ID_DLG_FOSA_OpenTitle,szTitle);
512 				pSS->getValueUTF8(XAP_STRING_ID_DLG_FOSA_FileOpenTypeLabel,szFileTypeLabel);
513 				m_bSave = false;
514 				break;
515 			}
516 		case XAP_DIALOG_ID_FILE_IMPORT:
517 			{
518 				pSS->getValueUTF8(XAP_STRING_ID_DLG_FOSA_ImportTitle,szTitle);
519 				pSS->getValueUTF8(XAP_STRING_ID_DLG_FOSA_FileOpenTypeLabel,szFileTypeLabel);
520 				m_bSave = false;
521 				break;
522 			}
523 		case XAP_DIALOG_ID_INSERTMATHML:
524 			{
525 				pSS->getValueUTF8(XAP_STRING_ID_DLG_FOSA_InsertMath,szTitle);
526 				pSS->getValueUTF8(XAP_STRING_ID_DLG_FOSA_FileInsertMath,szFileTypeLabel);
527 				m_bSave = false;
528 				break;
529 			}
530 		case XAP_DIALOG_ID_INSERTOBJECT:
531 			{
532 				pSS->getValueUTF8(XAP_STRING_ID_DLG_FOSA_InsertObject,szTitle);
533 				pSS->getValueUTF8(XAP_STRING_ID_DLG_FOSA_FileInsertObject,szFileTypeLabel);
534 				m_bSave = false;
535 				break;
536 			}
537 		case XAP_DIALOG_ID_INSERT_FILE:
538 			{
539 				pSS->getValueUTF8(XAP_STRING_ID_DLG_FOSA_InsertTitle,szTitle);
540 				pSS->getValueUTF8(XAP_STRING_ID_DLG_FOSA_FileOpenTypeLabel,szFileTypeLabel);
541 				m_bSave = false;
542 				break;
543 			}
544 		case XAP_DIALOG_ID_FILE_SAVEAS:
545 		case XAP_DIALOG_ID_FILE_SAVE_IMAGE:
546 			{
547 				pSS->getValueUTF8(XAP_STRING_ID_DLG_FOSA_SaveAsTitle,szTitle);
548 				pSS->getValueUTF8(XAP_STRING_ID_DLG_FOSA_FileSaveTypeLabel,szFileTypeLabel);
549 				m_bSave = true;
550 				break;
551 			}
552 		case XAP_DIALOG_ID_FILE_EXPORT:
553 			{
554 				pSS->getValueUTF8(XAP_STRING_ID_DLG_FOSA_ExportTitle,szTitle);
555 				pSS->getValueUTF8(XAP_STRING_ID_DLG_FOSA_FileSaveTypeLabel,szFileTypeLabel);
556 				m_bSave = true;
557 				break;
558 			}
559 		case XAP_DIALOG_ID_PRINTTOFILE:
560 			{
561 				pSS->getValueUTF8(XAP_STRING_ID_DLG_FOSA_PrintToFileTitle,szTitle);
562 				pSS->getValueUTF8(XAP_STRING_ID_DLG_FOSA_FilePrintTypeLabel,szFileTypeLabel);
563 				m_bSave = true;
564 				break;
565 			}
566 		case XAP_DIALOG_ID_RECORDTOFILE:
567 			{
568 				pSS->getValueUTF8(XAP_STRING_ID_DLG_FOSA_RecordToFileTitle,szTitle);
569 				pSS->getValueUTF8(XAP_STRING_ID_DLG_FOSA_RecordToFileLabel,szFileTypeLabel);
570 				m_bSave = true;
571 				break;
572 			}
573 		case XAP_DIALOG_ID_REPLAYFROMFILE:
574 			{
575 				pSS->getValueUTF8(XAP_STRING_ID_DLG_FOSA_ReplayFromFileTitle,szTitle);
576 				pSS->getValueUTF8(XAP_STRING_ID_DLG_FOSA_ReplayFromFileLabel,szFileTypeLabel);
577 				m_bSave = false;
578 				break;
579 			}
580 		default:
581 			UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
582 			m_bSave = false;
583 			break;
584 	}
585 
586 	// NOTE: we use our string mechanism to localize the dialog's
587 	// NOTE: title and the error/confirmation message boxes.  we
588 	// NOTE: let GTK take care of the localization of the actual
589 	// NOTE: buttons and labels on the FileSelection dialog.
590 
591 	// Get the GtkWindow of the parent frame
592 	XAP_UnixFrameImpl * pUnixFrameImpl = static_cast<XAP_UnixFrameImpl *>(pFrame->getFrameImpl());
593 	GtkWidget * parent = pUnixFrameImpl->getTopLevelWindow();
594 
595 	if(parent && (gtk_widget_is_toplevel(parent) != TRUE))
596 	{
597         parent = gtk_widget_get_toplevel (parent);
598 	}
599 
600 #if defined(EMBEDDED_TARGET) && EMBEDDED_TARGET == EMBEDDED_TARGET_HILDON
601 	m_FC = GTK_FILE_CHOOSER( hildon_file_chooser_dialog_new(GTK_WINDOW(parent),
602 							(!m_bSave ? GTK_FILE_CHOOSER_ACTION_OPEN : GTK_FILE_CHOOSER_ACTION_SAVE))
603 							);
604 #else
605 	m_FC = GTK_FILE_CHOOSER( gtk_file_chooser_dialog_new (szTitle.c_str(),
606 									GTK_WINDOW(parent),
607 									(!m_bSave ? GTK_FILE_CHOOSER_ACTION_OPEN : GTK_FILE_CHOOSER_ACTION_SAVE),
608 									GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
609 									(m_bSave ? GTK_STOCK_SAVE : GTK_STOCK_OPEN), GTK_RESPONSE_ACCEPT,
610 									(gchar*)NULL)
611 							);
612 #endif
613 
614 	gtk_file_chooser_set_local_only(m_FC, FALSE);
615 
616 	abiSetupModalDialog(GTK_DIALOG(m_FC), pFrame, this, GTK_RESPONSE_ACCEPT);
617 	GtkWidget * filetypes_pulldown = NULL;
618 
619     std::string s;
620 
621 	/*
622 	  Add a drop-down list of known types to facilitate a file-types selection.
623 	  We store an indexer in the user data for each menu item in the popup, so
624 	  we can read the type we need to return.
625 	*/
626 
627 	if (m_id == XAP_DIALOG_ID_INSERT_PICTURE)
628 	{
629 		GtkWidget * preview = createDrawingArea ();
630 		gtk_widget_show (preview);
631 		m_preview = preview;
632 		gtk_widget_set_size_request (preview, PREVIEW_WIDTH, PREVIEW_HEIGHT);
633 
634 		// place the preview area inside a container to get a nice border
635 		GtkWidget * preview_hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
636 		gtk_container_set_border_width  (GTK_CONTAINER(preview_hbox), 4);
637 		gtk_box_pack_start(GTK_BOX(preview_hbox), preview, TRUE, TRUE, 0);
638 
639 		// attach the preview area to the dialog
640 		gtk_file_chooser_set_preview_widget (m_FC, preview_hbox);
641 		gtk_file_chooser_set_preview_widget_active (m_FC, true);
642 
643 		// connect some signals
644 		g_signal_connect (m_FC, "update_preview",
645 								G_CALLBACK (file_selection_changed), static_cast<gpointer>(this));
646 
647 #if GTK_CHECK_VERSION(3,0,0)
648 		g_signal_connect (preview, "draw",
649 								G_CALLBACK (s_preview_draw), static_cast<gpointer>(this));
650 #else
651 		g_signal_connect (preview, "expose_event",
652 								G_CALLBACK (s_preview_exposed), static_cast<gpointer>(this));
653 #endif
654 	}
655 
656 #if defined(EMBEDDED_TARGET) && EMBEDDED_TARGET == EMBEDDED_TARGET_HILDON
657 	filetypes_pulldown = gtk_combo_box_new();
658 	gtk_widget_show(filetypes_pulldown);
659 	GtkWidget * pulldown_hbox = filetypes_pulldown;
660 #else
661 	// hbox for our pulldown menu (GTK does its pulldown this way */
662 	GtkWidget * pulldown_hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 15);
663 	gtk_widget_show(pulldown_hbox);
664 
665 	// pulldown label
666 	GtkWidget * filetypes_label = gtk_label_new_with_mnemonic(convertMnemonics(szFileTypeLabel).c_str());
667 	gtk_label_set_justify(GTK_LABEL(filetypes_label), GTK_JUSTIFY_RIGHT);
668 	gtk_misc_set_alignment(GTK_MISC(filetypes_label), 1.0, 0.5);
669 	gtk_widget_show(filetypes_label);
670 	gtk_box_pack_start(GTK_BOX(pulldown_hbox), filetypes_label, TRUE, TRUE, 0);
671 
672 	// pulldown menu
673 	filetypes_pulldown = gtk_combo_box_new();
674 	gtk_widget_show(filetypes_pulldown);
675 	gtk_box_pack_end(GTK_BOX(pulldown_hbox), filetypes_pulldown, TRUE, TRUE, 0);
676     gtk_label_set_mnemonic_widget(GTK_LABEL(filetypes_label), filetypes_pulldown);
677 #endif
678 	//
679 	// add the filters to the dropdown list
680 	//
681 	GtkComboBox* combo = GTK_COMBO_BOX(filetypes_pulldown);
682 	XAP_makeGtkComboBoxText(combo, G_TYPE_INT);
683 
684 	// Auto-detect is always an option, but a special one, so we use
685 	// a pre-defined constant for the type, and don't use the user-supplied
686 	// types yet.
687 	pSS->getValueUTF8(XAP_STRING_ID_DLG_FOSA_FileTypeAutoDetect,s);
688 	XAP_appendComboBoxTextAndInt(combo, s.c_str(), XAP_DIALOG_FILEOPENSAVEAS_FILE_TYPE_AUTO);
689 
690 	UT_sint32 activeItemIndex = -1;
691 
692 	// add list items
693 	{
694 		UT_ASSERT(g_strv_length((gchar **) m_szSuffixes) == g_strv_length((gchar **) m_szDescriptions));
695 
696 		// measure one list, they should all be the same length
697 		UT_uint32 end = g_strv_length((gchar **) m_szDescriptions);
698 
699 		for (UT_uint32 i = 0; i < end; i++)
700 		{
701 			// If this type is default, save its index (i) for later use
702 			if (m_nTypeList[i] == m_nDefaultFileType)
703 				activeItemIndex = i;
704 
705 			XAP_appendComboBoxTextAndInt(combo, m_szDescriptions[i], m_nTypeList[i]);
706 //
707 // Attach a callback when it is activated to change the file suffix
708 //
709 //			g_signal_connect(G_OBJECT(thismenuitem), "activate",
710 //							 G_CALLBACK(s_filetypechanged),
711 //							 reinterpret_cast<gpointer>(this));
712 		}
713 	}
714 
715 	m_wFileTypes_PullDown = filetypes_pulldown;
716 	// dialog; open dialog always does auto-detect
717 	// TODO: should this also apply to the open dialog?
718 	if (m_id == XAP_DIALOG_ID_FILE_SAVEAS
719         || m_id == XAP_DIALOG_ID_FILE_SAVE_IMAGE
720         || ( m_id == XAP_DIALOG_ID_FILE_EXPORT && activeItemIndex >= 0 )
721         )
722 	{
723 		gtk_combo_box_set_active(combo, activeItemIndex + 1);
724 	}
725 	else
726 	{
727 		gtk_combo_box_set_active(combo, 0);
728 	}
729 
730 #if defined(EMBEDDED_TARGET) && EMBEDDED_TARGET == EMBEDDED_TARGET_HILDON
731 	hildon_file_chooser_dialog_add_extra ((HildonFileChooserDialog*)m_FC,
732                                           pulldown_hbox);
733 #else
734 	gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER(m_FC), pulldown_hbox);
735 #endif
736 
737 	// connect the signals for OK and CANCEL and the requisite clean-close signals
738 	g_signal_connect(G_OBJECT(m_FC),
739 							 "delete-event",
740 							 G_CALLBACK(s_delete_clicked),
741 							 this);
742 
743 	g_signal_connect(G_OBJECT(m_FC),
744 			    "key_press_event",
745 			    G_CALLBACK(fsel_key_event), &m_answer);
746 
747 	g_signal_connect (G_OBJECT (m_FC),
748 				"response",
749 				G_CALLBACK(dialog_response), &m_answer);
750 
751 	g_signal_connect (G_OBJECT (m_FC),
752 				"file-activated",
753 				G_CALLBACK(s_file_activated), &m_answer);
754 
755 	g_signal_connect(G_OBJECT(filetypes_pulldown), "changed",
756 					 G_CALLBACK(s_filetypechanged),
757 					 reinterpret_cast<gpointer>(this));
758 
759 	// use the persistence info and/or the suggested filename
760 	// to properly seed the dialog.
761 
762 	gchar * szPersistDirectory = NULL;	// we must g_free this
763 
764 	if (!m_szInitialPathname || !*m_szInitialPathname)
765 	{
766 		// the caller did not supply initial pathname
767 		// (or supplied an empty one).  see if we have
768 		// some persistent info.
769 
770 		UT_ASSERT(!m_bSuggestName);
771 		if (m_szPersistPathname)
772 		{
773 			// we have a pathname from a previous use,
774 			// extract the directory portion and start
775 			// the dialog there (but without a filename).
776 
777 			szPersistDirectory = UT_go_dirname_from_uri(m_szPersistPathname, FALSE);
778 			gtk_file_chooser_set_current_folder_uri(m_FC, szPersistDirectory);
779 		}
780 		else
781 		{
782 			// no initial pathname given and we don't have
783 			// a pathname from a previous use, so just let
784 			// it come up in the current working directory.
785 		}
786 	}
787 	else
788 	{
789 		// we have an initial pathname (the name of the document
790 		// in the frame that we were invoked on).  if the caller
791 		// wanted us to suggest a filename, use the initial
792 		// pathname as is.  if not, use the directory portion of
793 		// it.
794 
795 		if (m_bSuggestName)
796 		{
797 			xxx_UT_DEBUGMSG(("Iniitial filename is %s \n",m_szInitialPathname));
798 #if 0
799 			if (!g_path_is_absolute (m_szInitialPathname)) { // DAL: todo: is this correct?
800 				gchar *dir = g_get_current_dir ();
801 				gchar *file = m_szInitialPathname;
802 				gchar *filename = g_build_filename (dir, file, (gchar *)NULL);
803 				m_szInitialPathname = UT_go_filename_to_uri(filename);
804 				g_free(filename);
805 				g_free (dir);
806 				g_free (file);
807 			}
808 #endif
809 			if(m_id == XAP_DIALOG_ID_FILE_SAVEAS)
810 			{
811 				std::string szInitialSuffix = UT_pathSuffix(m_szInitialPathname);
812 				std::string szSaveTypeSuffix = IE_Exp::preferredSuffixForFileType(m_nDefaultFileType).utf8_str();
813 				if(!szInitialSuffix.empty() && !szSaveTypeSuffix.empty()
814 					&& (szSaveTypeSuffix != szInitialSuffix))
815 				{
816 					std::string sFileName = m_szInitialPathname;
817 					std::string::size_type i = sFileName.find_last_of('.');
818 
819 					if(i != std::string::npos)
820 					{
821 						// erase to the end()
822 						sFileName.erase(i);
823 						sFileName += szSaveTypeSuffix;
824 						FREEP(m_szInitialPathname);
825 						m_szInitialPathname = g_strdup(sFileName.c_str());
826 					}
827 				}
828 			}
829 			if (UT_go_path_is_uri(m_szInitialPathname) || UT_go_path_is_path(m_szInitialPathname))
830 			{
831 				gtk_file_chooser_set_uri(m_FC, m_szInitialPathname);
832 			}
833 		}
834 		else
835 		{
836 			if (UT_go_path_is_uri(m_szInitialPathname) || UT_go_path_is_path(m_szInitialPathname))
837 			{
838 				szPersistDirectory = UT_go_dirname_from_uri(m_szInitialPathname, FALSE);
839 				gtk_file_chooser_set_current_folder_uri(m_FC, szPersistDirectory);
840 			}
841 			else
842 			{
843 				// we are dealing with a plain filename, not an URI or path, so
844 				// just let it come up in the current working directory.
845 			}
846 		}
847 	}
848 
849 	// center the dialog
850 	xxx_UT_DEBUGMSG(("before center IS WIDGET_TOP_LEVL %d \n",(GTK_WIDGET_TOPLEVEL(parent))));
851 	xxx_UT_DEBUGMSG(("before center IS WIDGET WINDOW %d \n",(GTK_IS_WINDOW(parent))));
852 	centerDialog(parent, GTK_WIDGET(m_FC));
853 	xxx_UT_DEBUGMSG(("After center IS WIDGET WINDOW %d \n",(GTK_IS_WINDOW(parent))));
854 
855 	gtk_widget_show(GTK_WIDGET(m_FC));
856 	gtk_grab_add(GTK_WIDGET(m_FC));
857 
858 	bool bResult = _run_gtk_main(pFrame,filetypes_pulldown);
859 
860 	if (bResult)
861 	{
862 		UT_ASSERT(m_szFinalPathnameCandidate);
863 
864 		// store final path name and file type
865 		m_szFinalPathname = g_strdup(m_szFinalPathnameCandidate);
866 
867 		FREEP(m_szFinalPathnameCandidate);
868 
869 		// what a long ugly line of code
870 		m_nFileType = XAP_comboBoxGetActiveInt(GTK_COMBO_BOX(filetypes_pulldown));
871 	}
872 
873 	if (m_FC != NULL) {
874 		gtk_grab_remove (GTK_WIDGET(m_FC));
875 		gtk_widget_destroy (GTK_WIDGET(m_FC));
876 		m_FC = NULL;
877 		FREEP(szPersistDirectory);
878 	}
879 
880 	return;
881 }
882 
previewPicture(void)883 gint XAP_UnixDialog_FileOpenSaveAs::previewPicture (void)
884 {
885 	UT_ASSERT (m_FC && m_preview);
886 
887 	UT_ASSERT(XAP_App::getApp());
888 
889 	const XAP_StringSet * pSS = m_pApp->getStringSet();
890 	UT_return_val_if_fail( pSS, 0 );
891 
892 	/* do not try to scale an image to a 1x1 pibuf, this might happen when
893 	   the widget size has notbeen allocated or if there is no room for it,
894 	   that might freeze gdk_pixbuf */
895 	GtkAllocation allocation;
896 	gtk_widget_get_allocation (m_preview, &allocation);
897 	if (allocation.width <= 1)
898 		return 0;
899 
900 	// attach and clear the area immediately
901 	GR_UnixCairoAllocInfo ai(m_preview);
902 	GR_CairoGraphics* pGr =
903 		(GR_CairoGraphics*) XAP_App::getApp()->newGraphics(ai);
904 
905 	const gchar * file_name = gtk_file_chooser_get_uri (m_FC);
906 
907 	GR_Font * fnt = pGr->findFont("Times New Roman",
908 								  "normal", "", "normal",
909 								  "", "12pt",
910 								  pSS->getLanguageName());
911 	pGr->setFont(fnt);
912 
913 	std::string s;
914 	pSS->getValueUTF8(XAP_STRING_ID_DLG_IP_No_Picture_Label, s);
915 	UT_UTF8String str(s);
916 
917 	int answer = 0;
918 
919 	FG_Graphic * pGraphic = 0;
920 	GR_Image *pImage = NULL;
921 
922 	double		scale_factor = 0.0;
923 	UT_sint32     scaled_width,scaled_height;
924 	UT_sint32     iImageWidth,iImageHeight;
925 
926 	{
927 	GR_Painter painter(pGr);
928 	GtkAllocation alloc;
929 	gtk_widget_get_allocation(m_preview, &alloc);
930 	painter.clearArea(0, 0, pGr->tlu(alloc.width), pGr->tlu(alloc.height));
931 
932 	if (!file_name)
933 	{
934 		painter.drawChars (str.ucs4_str().ucs4_str(), 0, str.size(), pGr->tlu(12), pGr->tlu(static_cast<int>(alloc.height / 2)) - pGr->getFontHeight(fnt)/2);
935 	    goto Cleanup;
936 	}
937 
938 	// are we dealing with a file or directory here?
939 	struct stat st;
940 	if (!stat (file_name, &st))
941 	{
942 		if (!S_ISREG(st.st_mode))
943 		{
944 			painter.drawChars (str.ucs4_str().ucs4_str(), 0, str.size(), pGr->tlu(12), pGr->tlu(static_cast<int>(alloc.height / 2)) - pGr->getFontHeight(fnt)/2);
945 			goto Cleanup;
946 		}
947 	}
948 
949 	GsfInput * input = NULL;
950 	UT_DEBUGMSG(("file_name %s \n",file_name));
951 	input = UT_go_file_open (file_name, NULL);
952 	if (!input)
953 		goto Cleanup;
954 	char Buf[4097] = "";  // 4096+nul ought to be enough
955 	UT_uint32 iNumbytes = UT_MIN(4096, gsf_input_size(input));
956 	gsf_input_read(input, iNumbytes, (guint8 *)(Buf));
957 	Buf[iNumbytes] = '\0';
958 
959 	IEGraphicFileType ief = IE_ImpGraphic::fileTypeForContents(Buf,4096);
960 	if((ief == IEGFT_Unknown) || (ief == IEGFT_Bogus))
961 	{
962 		    painter.drawChars (str.ucs4_str().ucs4_str(), 0, str.size(), pGr->tlu(12), pGr->tlu(static_cast<int>(alloc.height / 2)) - pGr->getFontHeight(fnt)/2);
963 			g_object_unref (G_OBJECT (input));
964 			goto Cleanup;
965 	}
966 	g_object_unref (G_OBJECT (input));
967 	input = UT_go_file_open (file_name, NULL);
968 	size_t num_bytes = gsf_input_size(input);
969 	UT_Byte * bytes = (UT_Byte *) gsf_input_read(input, num_bytes,NULL );
970 	if(bytes == NULL)
971 	{
972 		    painter.drawChars (str.ucs4_str().ucs4_str(), 0, str.size(), pGr->tlu(12), pGr->tlu(static_cast<int>(alloc.height / 2)) - pGr->getFontHeight(fnt)/2);
973 			g_object_unref (G_OBJECT (input));
974 			goto Cleanup;
975 	}
976 	UT_ByteBuf * pBB = new UT_ByteBuf();
977 	pBB->append(bytes,num_bytes);
978 	g_object_unref (G_OBJECT (input));
979 	//
980 	// OK load the data into a GdkPixbuf
981 	//
982 	// Jean: comented out next line (and an other one below), we don't use it
983 	// bool bLoadFailed = false;
984 	//
985 	GdkPixbuf * pixbuf = pixbufForByteBuf ( pBB);
986 	delete pBB;
987 	if(pixbuf == NULL)
988 	{
989 		//
990 		// Try a fallback loader here.
991 		//
992 		painter.drawChars (str.ucs4_str().ucs4_str(), 0, str.size(), pGr->tlu(12), pGr->tlu(static_cast<int>(alloc.height / 2)) - pGr->getFontHeight(fnt)/2);
993 		// bLoadFailed = true;
994 	    goto Cleanup;
995 	}
996 
997 	pImage = new GR_UnixImage(NULL,pixbuf);
998 
999 	iImageWidth = gdk_pixbuf_get_width (pixbuf);
1000 	iImageHeight = gdk_pixbuf_get_height (pixbuf);
1001 	if (alloc.width >= iImageWidth && alloc.height >= iImageHeight)
1002 		scale_factor = 1.0;
1003 	else
1004 		scale_factor = MIN( static_cast<double>(alloc.width)/iImageWidth,
1005 							static_cast<double>(alloc.height)/iImageHeight);
1006 
1007 	scaled_width  = static_cast<int>(scale_factor * iImageWidth);
1008 	scaled_height = static_cast<int>(scale_factor * iImageHeight);
1009 
1010 	static_cast<GR_UnixImage *>(pImage)->scale(scaled_width,scaled_height);
1011 	painter.drawImage(pImage,
1012 					  pGr->tlu(static_cast<int>((alloc.width  - scaled_width ) / 2)),
1013 					  pGr->tlu(static_cast<int>((alloc.height - scaled_height) / 2)));
1014 
1015 	answer = 1;
1016 	}
1017 
1018  Cleanup:
1019 	FREEP(file_name);
1020 	DELETEP(pImage);
1021 	DELETEP(pGr);
1022 	DELETEP(pGraphic);
1023 
1024 	return answer;
1025 }
1026 
_loadXPM(UT_ByteBuf * pBB)1027 GdkPixbuf *  XAP_UnixDialog_FileOpenSaveAs::_loadXPM(UT_ByteBuf * pBB)
1028 {
1029 	GdkPixbuf * pixbuf = NULL;
1030 	const char * pBC = reinterpret_cast<const char *>(pBB->getPointer(0));
1031 
1032 	UT_GenericVector<char*> vecStr;
1033 	UT_sint32 k =0;
1034 	UT_sint32 iBase =0;
1035 
1036 	//
1037 	// Find dimension line to start with.
1038 	//
1039 	UT_sint32 length = static_cast<UT_sint32>(pBB->getLength());
1040 	for(k =0; (*(pBC+k) != '"') &&( k < length); k++)
1041 		;
1042 
1043 	if(k >= length)
1044 	{
1045 		return NULL;
1046 	}
1047 
1048 	k++;
1049 	iBase = k;
1050 	for( ; (*(pBC+k) != '"') && (k < length); k++)
1051 		;
1052 	if(k >= length)
1053 	{
1054 		return NULL;
1055 	}
1056 
1057 	char * sz = NULL;
1058 	UT_sint32 kLen = k-iBase+1;
1059 	sz = static_cast<char *>(UT_calloc(kLen,sizeof(char)));
1060 	UT_sint32 i =0;
1061 
1062 	for(i=0; i< (kLen -1); i++)
1063 	{
1064 		*(sz+i) = *(pBC+iBase+i);
1065 	}
1066 	*(sz+i) = 0;
1067 	vecStr.addItem(sz);
1068 
1069 	//
1070 	// Now loop through all the lines until we get to "}" outside the
1071 	// '"'
1072 	while((*(pBC+k) != '}')  && (k < length) )
1073 	{
1074 		k++;
1075 
1076 		//
1077 		// Load a single string of data into our vector.
1078 		//
1079 		if(*(pBC+k) =='"')
1080 		{
1081 			//
1082 			// Start of a line
1083 			//
1084 			k++;
1085 			iBase = k;
1086 			for( ; (*(pBC+k) != '"') && (k < length); k++) {}
1087 			if(k >= length)
1088 			{
1089 				return NULL;
1090 			}
1091 			sz = NULL;
1092 			kLen = k-iBase+1;
1093 			sz = static_cast<char *>(UT_calloc(kLen,sizeof(char)));
1094 			for(i=0; i<(kLen -1); i++)
1095 			{
1096 				*(sz+i) = *(pBC+iBase+i);
1097 			}
1098 			*(sz +i) = 0;
1099 			vecStr.addItem(sz);
1100 		}
1101 	}
1102 
1103 	if(k >= length)
1104 	{
1105 		for(i=0; i<vecStr.getItemCount(); i++)
1106 		{
1107 			char * psz = vecStr.getNthItem(i);
1108 			FREEP(psz);
1109 		}
1110 		return NULL;
1111 	}
1112 
1113 	const char ** pszStr = static_cast<const char **>(UT_calloc(vecStr.getItemCount(),sizeof(char *)));
1114 	for(i=0; i<vecStr.getItemCount(); i++)
1115 		pszStr[i] = vecStr.getNthItem(i);
1116 	pixbuf = gdk_pixbuf_new_from_xpm_data(pszStr);
1117 	DELETEP(pszStr);
1118 	return pixbuf;
1119 }
1120 
pixbufForByteBuf(UT_ByteBuf * pBB)1121 GdkPixbuf *  XAP_UnixDialog_FileOpenSaveAs::pixbufForByteBuf (UT_ByteBuf * pBB)
1122 {
1123 	if ( !pBB || !pBB->getLength() )
1124 		return NULL;
1125 
1126 	GdkPixbuf * pixbuf = NULL;
1127 
1128 	bool bIsXPM = false;
1129 	const char * szBuf = reinterpret_cast<const char *>(pBB->getPointer(0));
1130 	if((pBB->getLength() > 9) && (strncmp (szBuf, "/* XPM */", 9) == 0))
1131 	{
1132 		bIsXPM = true;
1133 	}
1134 
1135 	if(bIsXPM)
1136 	{
1137 		pixbuf = _loadXPM(pBB);
1138 	}
1139 	else
1140 	{
1141 		GError * err = 0;
1142 		GdkPixbufLoader * ldr = 0;
1143 
1144 		ldr = gdk_pixbuf_loader_new ();
1145 		if (!ldr)
1146 			{
1147 				UT_DEBUGMSG (("GdkPixbuf: couldn't create loader! WTF?\n"));
1148 				UT_ASSERT (ldr);
1149 				return NULL ;
1150 			}
1151 
1152 		if ( FALSE== gdk_pixbuf_loader_write (ldr, static_cast<const guchar *>(pBB->getPointer (0)),
1153 											  static_cast<gsize>(pBB->getLength ()), &err) )
1154 			{
1155 				UT_DEBUGMSG(("DOM: couldn't write to loader: %s\n", err->message));
1156 				g_error_free(err);
1157 				gdk_pixbuf_loader_close (ldr, NULL);
1158 				g_object_unref (G_OBJECT(ldr));
1159 				return NULL ;
1160 			}
1161 
1162 		gdk_pixbuf_loader_close (ldr, NULL);
1163 		pixbuf = gdk_pixbuf_loader_get_pixbuf (ldr);
1164 
1165 		// ref before closing the loader
1166 		if ( pixbuf )
1167 			g_object_ref (G_OBJECT(pixbuf));
1168 
1169 		g_object_unref (G_OBJECT(ldr));
1170 	}
1171 
1172 	return pixbuf;
1173 }
1174