Line data Source code
1 : /* -*- Mode: C++; 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 : */
19 :
20 : #ifdef AIX
21 : #define _LINUX_SOURCE_COMPAT
22 : #include <sys/timer.h>
23 : #undef _LINUX_SOURCE_COMPAT
24 : #endif
25 :
26 : #include <config_vclplug.h>
27 :
28 : #include <com/sun/star/awt/Toolkit.hpp>
29 : #include <com/sun/star/frame/Desktop.hpp>
30 : #include <com/sun/star/uno/XComponentContext.hpp>
31 : #include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp>
32 : #include <com/sun/star/ui/dialogs/CommonFilePickerElementIds.hpp>
33 : #include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp>
34 : #include <osl/diagnose.h>
35 : #include <osl/process.h>
36 : #include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
37 : #include <com/sun/star/ui/dialogs/ControlActions.hpp>
38 : #include <com/sun/star/uno/Any.hxx>
39 : #include <comphelper/string.hxx>
40 : #include <osl/mutex.hxx>
41 : #include "unx/gtk/gtkinst.hxx"
42 :
43 : #include <vcl/svapp.hxx>
44 :
45 : #include <tools/urlobj.hxx>
46 :
47 : #include <algorithm>
48 : #include <set>
49 : #include <string.h>
50 :
51 : #include "gtk/fpicker/SalGtkFilePicker.hxx"
52 :
53 : // namespace directives
54 :
55 : using namespace ::com::sun::star;
56 : using namespace ::com::sun::star::ui::dialogs;
57 : using namespace ::com::sun::star::ui::dialogs::TemplateDescription;
58 : using namespace ::com::sun::star::ui::dialogs::ExtendedFilePickerElementIds;
59 : using namespace ::com::sun::star::ui::dialogs::CommonFilePickerElementIds;
60 : using namespace ::com::sun::star::lang;
61 : using namespace ::com::sun::star::beans;
62 : using namespace ::com::sun::star::uno;
63 :
64 0 : void SalGtkFilePicker::dialog_mapped_cb(GtkWidget *, SalGtkFilePicker *pobjFP)
65 : {
66 0 : pobjFP->InitialMapping();
67 0 : }
68 :
69 0 : void SalGtkFilePicker::InitialMapping()
70 : {
71 0 : if (!mbPreviewState )
72 : {
73 0 : gtk_widget_hide( m_pPreview );
74 0 : gtk_file_chooser_set_preview_widget_active( GTK_FILE_CHOOSER( m_pDialog ), false);
75 : }
76 0 : gtk_widget_set_size_request (m_pPreview, -1, -1);
77 0 : }
78 :
79 0 : SalGtkFilePicker::SalGtkFilePicker( const uno::Reference< uno::XComponentContext >& xContext ) :
80 : SalGtkPicker( xContext ),
81 : SalGtkFilePicker_Base( m_rbHelperMtx ),
82 : m_pFilterList( NULL ),
83 : m_pVBox ( NULL ),
84 : mnHID_FolderChange( 0 ),
85 : mnHID_SelectionChange( 0 ),
86 : bVersionWidthUnset( false ),
87 : mbPreviewState( false ),
88 : mHID_Preview( 0 ),
89 : m_pPreview( NULL ),
90 : m_pPseudoFilter( NULL ),
91 : m_PreviewImageWidth( 256 ),
92 0 : m_PreviewImageHeight( 256 )
93 : {
94 : int i;
95 :
96 0 : for( i = 0; i < TOGGLE_LAST; i++ )
97 : {
98 0 : m_pToggles[i] = NULL;
99 0 : mbToggleVisibility[i] = false;
100 : }
101 :
102 0 : for( i = 0; i < BUTTON_LAST; i++ )
103 : {
104 0 : m_pButtons[i] = NULL;
105 0 : mbButtonVisibility[i] = false;
106 : }
107 :
108 0 : for( i = 0; i < LIST_LAST; i++ )
109 : {
110 0 : m_pHBoxs[i] = NULL;
111 0 : m_pAligns[i] = NULL;
112 0 : m_pLists[i] = NULL;
113 0 : m_pListLabels[i] = NULL;
114 0 : mbListVisibility[i] = false;
115 : }
116 :
117 0 : OUString aFilePickerTitle = getResString( FILE_PICKER_TITLE_OPEN );
118 :
119 : m_pDialog = gtk_file_chooser_dialog_new(
120 : OUStringToOString( aFilePickerTitle, RTL_TEXTENCODING_UTF8 ).getStr(),
121 : NULL,
122 : GTK_FILE_CHOOSER_ACTION_OPEN,
123 : GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
124 : GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
125 0 : (char *)NULL );
126 :
127 0 : gtk_dialog_set_default_response( GTK_DIALOG (m_pDialog), GTK_RESPONSE_ACCEPT );
128 :
129 : #if ENABLE_GNOME_VFS || ENABLE_GIO
130 0 : gtk_file_chooser_set_local_only( GTK_FILE_CHOOSER( m_pDialog ), false );
131 : #endif
132 0 : gtk_file_chooser_set_select_multiple( GTK_FILE_CHOOSER( m_pDialog ), false );
133 :
134 0 : m_pVBox = gtk_vbox_new( false, 0 );
135 :
136 : // We don't want clickable items to have a huge hit-area
137 0 : GtkWidget *pHBox = gtk_hbox_new( false, 0 );
138 0 : GtkWidget *pThinVBox = gtk_vbox_new( false, 0 );
139 :
140 0 : gtk_box_pack_end (GTK_BOX( m_pVBox ), pHBox, false, false, 0);
141 0 : gtk_box_pack_start (GTK_BOX( pHBox ), pThinVBox, false, false, 0);
142 0 : gtk_widget_show( pHBox );
143 0 : gtk_widget_show( pThinVBox );
144 :
145 0 : OUString aLabel;
146 :
147 0 : for( i = 0; i < TOGGLE_LAST; i++ )
148 : {
149 0 : m_pToggles[i] = gtk_check_button_new();
150 :
151 : #define LABEL_TOGGLE( elem ) \
152 : case elem : \
153 : aLabel = getResString( CHECKBOX_##elem ); \
154 : setLabel( CHECKBOX_##elem, aLabel ); \
155 : break
156 :
157 0 : switch( i ) {
158 :
159 0 : LABEL_TOGGLE( AUTOEXTENSION );
160 0 : LABEL_TOGGLE( PASSWORD );
161 0 : LABEL_TOGGLE( FILTEROPTIONS );
162 0 : LABEL_TOGGLE( READONLY );
163 0 : LABEL_TOGGLE( LINK );
164 0 : LABEL_TOGGLE( PREVIEW );
165 0 : LABEL_TOGGLE( SELECTION );
166 : default:
167 : OSL_TRACE("Handle unknown control %d", i);
168 0 : break;
169 : }
170 :
171 0 : gtk_box_pack_end( GTK_BOX( pThinVBox ), m_pToggles[i], false, false, 0 );
172 : }
173 :
174 0 : for( i = 0; i < LIST_LAST; i++ )
175 : {
176 0 : m_pHBoxs[i] = gtk_hbox_new( false, 0 );
177 :
178 0 : m_pAligns[i] = gtk_alignment_new(0, 0, 0, 1);
179 :
180 0 : m_pListStores[i] = gtk_list_store_new (1, G_TYPE_STRING);
181 0 : m_pLists[i] = gtk_combo_box_new_with_model(GTK_TREE_MODEL(m_pListStores[i]));
182 0 : g_object_unref (m_pListStores[i]); // owned by the widget.
183 0 : GtkCellRenderer *pCell = gtk_cell_renderer_text_new ();
184 : gtk_cell_layout_pack_start(
185 0 : GTK_CELL_LAYOUT(m_pLists[i]), pCell, TRUE);
186 : gtk_cell_layout_set_attributes(
187 0 : GTK_CELL_LAYOUT (m_pLists[i]), pCell, "text", 0, NULL);
188 :
189 0 : m_pListLabels[i] = gtk_label_new( "" );
190 :
191 : #define LABEL_LIST( elem ) \
192 : case elem : \
193 : aLabel = getResString( LISTBOX_##elem##_LABEL ); \
194 : setLabel( LISTBOX_##elem##_LABEL, aLabel ); \
195 : break
196 :
197 0 : switch( i )
198 : {
199 0 : LABEL_LIST( VERSION );
200 0 : LABEL_LIST( TEMPLATE );
201 0 : LABEL_LIST( IMAGE_TEMPLATE );
202 : default:
203 : OSL_TRACE("Handle unknown control %d", i);
204 0 : break;
205 : }
206 :
207 0 : gtk_container_add( GTK_CONTAINER( m_pAligns[i]), m_pLists[i] );
208 0 : gtk_box_pack_end( GTK_BOX( m_pHBoxs[i] ), m_pAligns[i], false, false, 0 );
209 :
210 0 : gtk_box_pack_end( GTK_BOX( m_pHBoxs[i] ), m_pListLabels[i], false, false, 0 );
211 :
212 0 : gtk_box_pack_end( GTK_BOX( m_pVBox ), m_pHBoxs[i], false, false, 0 );
213 : }
214 :
215 0 : aLabel = getResString( FILE_PICKER_FILE_TYPE );
216 : m_pFilterExpander = gtk_expander_new_with_mnemonic(
217 0 : OUStringToOString( aLabel, RTL_TEXTENCODING_UTF8 ).getStr());
218 :
219 0 : gtk_box_pack_end( GTK_BOX( m_pVBox ), m_pFilterExpander, false, true, 0 );
220 :
221 0 : GtkWidget *scrolled_window = gtk_scrolled_window_new (NULL, NULL);
222 0 : gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
223 0 : GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
224 0 : gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window),
225 0 : GTK_SHADOW_IN);
226 0 : gtk_container_add (GTK_CONTAINER (m_pFilterExpander), scrolled_window);
227 0 : gtk_widget_show (scrolled_window);
228 :
229 : m_pFilterStore = gtk_list_store_new (4, G_TYPE_STRING, G_TYPE_STRING,
230 0 : G_TYPE_STRING, G_TYPE_STRING);
231 0 : m_pFilterView = gtk_tree_view_new_with_model (GTK_TREE_MODEL(m_pFilterStore));
232 0 : gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(m_pFilterView), false);
233 0 : gtk_tree_view_set_rules_hint (GTK_TREE_VIEW(m_pFilterView), true);
234 :
235 : GtkTreeViewColumn *column;
236 : GtkCellRenderer *cell;
237 :
238 0 : for (i = 0; i < 2; ++i)
239 : {
240 0 : column = gtk_tree_view_column_new ();
241 0 : cell = gtk_cell_renderer_text_new ();
242 0 : gtk_tree_view_column_set_expand (column, true);
243 0 : gtk_tree_view_column_pack_start (column, cell, false);
244 0 : gtk_tree_view_column_set_attributes (column, cell, "text", i, (char *)NULL);
245 0 : gtk_tree_view_append_column (GTK_TREE_VIEW(m_pFilterView), column);
246 : }
247 :
248 0 : gtk_container_add (GTK_CONTAINER (scrolled_window), m_pFilterView);
249 0 : gtk_widget_show (m_pFilterView);
250 :
251 0 : gtk_file_chooser_set_extra_widget( GTK_FILE_CHOOSER( m_pDialog ), m_pVBox );
252 :
253 0 : m_pPreview = gtk_image_new();
254 0 : gtk_file_chooser_set_preview_widget( GTK_FILE_CHOOSER( m_pDialog ), m_pPreview );
255 :
256 0 : g_signal_connect( G_OBJECT( m_pToggles[PREVIEW] ), "toggled",
257 0 : G_CALLBACK( preview_toggled_cb ), this );
258 0 : g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW(m_pFilterView)), "changed",
259 0 : G_CALLBACK ( type_changed_cb ), this);
260 0 : g_signal_connect( G_OBJECT( m_pDialog ), "notify::filter",
261 0 : G_CALLBACK( filter_changed_cb ), this);
262 0 : g_signal_connect( G_OBJECT( m_pFilterExpander ), "activate",
263 0 : G_CALLBACK( expander_changed_cb ), this);
264 0 : g_signal_connect (G_OBJECT( m_pDialog ), "map",
265 0 : G_CALLBACK (dialog_mapped_cb), this);
266 :
267 0 : gtk_widget_show( m_pVBox );
268 :
269 0 : PangoLayout *layout = gtk_widget_create_pango_layout (m_pFilterView, NULL);
270 : guint ypad;
271 : PangoRectangle row_height;
272 0 : pango_layout_set_markup (layout, "All Files", -1);
273 0 : pango_layout_get_pixel_extents (layout, NULL, &row_height);
274 0 : g_object_unref (layout);
275 :
276 0 : g_object_get (cell, "ypad", &ypad, (char *)NULL);
277 0 : guint height = (row_height.height + 2*ypad) * 5;
278 0 : gtk_widget_set_size_request (m_pFilterView, -1, height);
279 0 : gtk_widget_set_size_request (m_pPreview, 1, height);
280 :
281 0 : gtk_file_chooser_set_preview_widget_active( GTK_FILE_CHOOSER( m_pDialog ), true);
282 0 : }
283 :
284 : // XFilePickerNotifier
285 :
286 0 : void SAL_CALL SalGtkFilePicker::addFilePickerListener( const uno::Reference<XFilePickerListener>& xListener )
287 : throw( uno::RuntimeException, std::exception )
288 : {
289 0 : SolarMutexGuard g;
290 :
291 : OSL_ENSURE(!m_xListener.is(),
292 : "SalGtkFilePicker only talks with one listener at a time...");
293 0 : m_xListener = xListener;
294 0 : }
295 :
296 0 : void SAL_CALL SalGtkFilePicker::removeFilePickerListener( const uno::Reference<XFilePickerListener>& )
297 : throw( uno::RuntimeException, std::exception )
298 : {
299 0 : SolarMutexGuard g;
300 :
301 0 : m_xListener.clear();
302 0 : }
303 :
304 : // XEventListener
305 :
306 0 : void SAL_CALL SalGtkFilePicker::disposing( const lang::EventObject& aEvent ) throw( uno::RuntimeException )
307 : {
308 : // no member access => no mutex needed
309 :
310 0 : uno::Reference<XFilePickerListener> xFilePickerListener( aEvent.Source, ::com::sun::star::uno::UNO_QUERY );
311 :
312 0 : if( xFilePickerListener.is() )
313 0 : removeFilePickerListener( xFilePickerListener );
314 0 : }
315 :
316 : // FilePicker Event functions
317 :
318 0 : void SalGtkFilePicker::impl_fileSelectionChanged( FilePickerEvent aEvent )
319 : {
320 : OSL_TRACE( "file selection changed");
321 0 : if (m_xListener.is()) m_xListener->fileSelectionChanged( aEvent );
322 0 : }
323 :
324 0 : void SalGtkFilePicker::impl_directoryChanged( FilePickerEvent aEvent )
325 : {
326 : OSL_TRACE("directory changed");
327 0 : if (m_xListener.is()) m_xListener->directoryChanged( aEvent );
328 0 : }
329 :
330 0 : void SalGtkFilePicker::impl_controlStateChanged( FilePickerEvent aEvent )
331 : {
332 : OSL_TRACE("control state changed");
333 0 : if (m_xListener.is()) m_xListener->controlStateChanged( aEvent );
334 0 : }
335 :
336 0 : struct FilterEntry
337 : {
338 : protected:
339 : OUString m_sTitle;
340 : OUString m_sFilter;
341 :
342 : UnoFilterList m_aSubFilters;
343 :
344 : public:
345 0 : FilterEntry( const OUString& _rTitle, const OUString& _rFilter )
346 : :m_sTitle( _rTitle )
347 0 : ,m_sFilter( _rFilter )
348 : {
349 0 : }
350 :
351 0 : OUString getTitle() const { return m_sTitle; }
352 0 : OUString getFilter() const { return m_sFilter; }
353 :
354 : /// determines if the filter has sub filter (i.e., the filter is a filter group in real)
355 : bool hasSubFilters( ) const;
356 :
357 : /** retrieves the filters belonging to the entry
358 : @return
359 : the number of sub filters
360 : */
361 : sal_Int32 getSubFilters( UnoFilterList& _rSubFilterList );
362 :
363 : // helpers for iterating the sub filters
364 0 : const UnoFilterEntry* beginSubFilters() const { return m_aSubFilters.getConstArray(); }
365 0 : const UnoFilterEntry* endSubFilters() const { return m_aSubFilters.getConstArray() + m_aSubFilters.getLength(); }
366 : };
367 :
368 0 : bool FilterEntry::hasSubFilters() const
369 : {
370 0 : return( 0 < m_aSubFilters.getLength() );
371 : }
372 :
373 0 : sal_Int32 FilterEntry::getSubFilters( UnoFilterList& _rSubFilterList )
374 : {
375 0 : _rSubFilterList = m_aSubFilters;
376 0 : return m_aSubFilters.getLength();
377 : }
378 :
379 : static bool
380 0 : isFilterString( const OUString &rFilterString, const char *pMatch )
381 : {
382 0 : sal_Int32 nIndex = 0;
383 0 : OUString aToken;
384 0 : bool bIsFilter = true;
385 :
386 0 : OUString aMatch(OUString::createFromAscii(pMatch));
387 :
388 0 : do
389 : {
390 0 : aToken = rFilterString.getToken( 0, ';', nIndex );
391 0 : if( !aToken.match( aMatch ) )
392 : {
393 0 : bIsFilter = false;
394 0 : break;
395 : }
396 : }
397 0 : while( nIndex >= 0 );
398 :
399 0 : return bIsFilter;
400 : }
401 :
402 : static OUString
403 0 : shrinkFilterName( const OUString &rFilterName, bool bAllowNoStar = false )
404 : {
405 : int i;
406 0 : int nBracketLen = -1;
407 0 : int nBracketEnd = -1;
408 0 : const sal_Unicode *pStr = rFilterName.getStr();
409 0 : OUString aRealName = rFilterName;
410 :
411 0 : for( i = aRealName.getLength() - 1; i > 0; i-- )
412 : {
413 0 : if( pStr[i] == ')' )
414 0 : nBracketEnd = i;
415 0 : else if( pStr[i] == '(' )
416 : {
417 0 : nBracketLen = nBracketEnd - i;
418 0 : if( nBracketEnd <= 0 )
419 0 : continue;
420 0 : if( isFilterString( rFilterName.copy( i + 1, nBracketLen - 1 ), "*." ) )
421 0 : aRealName = aRealName.replaceAt( i, nBracketLen + 1, OUString() );
422 0 : else if (bAllowNoStar)
423 : {
424 0 : if( isFilterString( rFilterName.copy( i + 1, nBracketLen - 1 ), ".") )
425 0 : aRealName = aRealName.replaceAt( i, nBracketLen + 1, OUString() );
426 : }
427 : }
428 : }
429 :
430 0 : return aRealName;
431 : }
432 :
433 : static void
434 0 : dialog_remove_buttons( GtkDialog *pDialog )
435 : {
436 0 : g_return_if_fail( GTK_IS_DIALOG( pDialog ) );
437 :
438 : GtkWidget *pActionArea;
439 :
440 : #if GTK_CHECK_VERSION(3,0,0)
441 : pActionArea = gtk_dialog_get_action_area( pDialog );
442 : #else
443 0 : pActionArea = pDialog->action_area;
444 : #endif
445 :
446 : GList *pChildren =
447 0 : gtk_container_get_children( GTK_CONTAINER( pActionArea ) );
448 :
449 0 : for( GList *p = pChildren; p; p = p->next )
450 0 : gtk_widget_destroy( GTK_WIDGET( p->data ) );
451 :
452 0 : g_list_free( pChildren );
453 : }
454 :
455 : namespace {
456 :
457 : struct FilterTitleMatch : public ::std::unary_function< FilterEntry, bool >
458 : {
459 : protected:
460 : const OUString& rTitle;
461 :
462 : public:
463 0 : FilterTitleMatch( const OUString& _rTitle ) : rTitle( _rTitle ) { }
464 :
465 0 : bool operator () ( const FilterEntry& _rEntry )
466 : {
467 : bool bMatch;
468 0 : if( !_rEntry.hasSubFilters() )
469 : // a real filter
470 0 : bMatch = (_rEntry.getTitle() == rTitle)
471 0 : || (shrinkFilterName(_rEntry.getTitle()) == rTitle);
472 : else
473 : // a filter group -> search the sub filters
474 : bMatch =
475 0 : _rEntry.endSubFilters() != ::std::find_if(
476 : _rEntry.beginSubFilters(),
477 : _rEntry.endSubFilters(),
478 : *this
479 0 : );
480 :
481 0 : return bMatch;
482 : }
483 0 : bool operator () ( const UnoFilterEntry& _rEntry )
484 : {
485 0 : OUString aShrunkName = shrinkFilterName( _rEntry.First );
486 0 : return aShrunkName == rTitle;
487 : }
488 : };
489 : }
490 :
491 0 : bool SalGtkFilePicker::FilterNameExists( const OUString& rTitle )
492 : {
493 0 : bool bRet = false;
494 :
495 0 : if( m_pFilterList )
496 : bRet =
497 0 : m_pFilterList->end() != ::std::find_if(
498 : m_pFilterList->begin(),
499 : m_pFilterList->end(),
500 : FilterTitleMatch( rTitle )
501 0 : );
502 :
503 0 : return bRet;
504 : }
505 :
506 0 : bool SalGtkFilePicker::FilterNameExists( const UnoFilterList& _rGroupedFilters )
507 : {
508 0 : bool bRet = false;
509 :
510 0 : if( m_pFilterList )
511 : {
512 0 : const UnoFilterEntry* pStart = _rGroupedFilters.getConstArray();
513 0 : const UnoFilterEntry* pEnd = pStart + _rGroupedFilters.getLength();
514 0 : for( ; pStart != pEnd; ++pStart )
515 0 : if( m_pFilterList->end() != ::std::find_if(
516 : m_pFilterList->begin(),
517 : m_pFilterList->end(),
518 0 : FilterTitleMatch( pStart->First ) ) )
519 0 : break;
520 :
521 0 : bRet = pStart != pEnd;
522 : }
523 :
524 0 : return bRet;
525 : }
526 :
527 0 : void SalGtkFilePicker::ensureFilterList( const OUString& _rInitialCurrentFilter )
528 : {
529 0 : if( !m_pFilterList )
530 : {
531 0 : m_pFilterList = new FilterList;
532 :
533 : // set the first filter to the current filter
534 0 : if ( m_aCurrentFilter.isEmpty() )
535 0 : m_aCurrentFilter = _rInitialCurrentFilter;
536 : }
537 0 : }
538 :
539 0 : void SAL_CALL SalGtkFilePicker::appendFilter( const OUString& aTitle, const OUString& aFilter )
540 : throw( lang::IllegalArgumentException, uno::RuntimeException, std::exception )
541 : {
542 0 : SolarMutexGuard g;
543 :
544 : OSL_ASSERT( m_pDialog != NULL );
545 :
546 0 : if( FilterNameExists( aTitle ) )
547 0 : throw IllegalArgumentException();
548 :
549 : // ensure that we have a filter list
550 0 : ensureFilterList( aTitle );
551 :
552 : // append the filter
553 0 : m_pFilterList->insert( m_pFilterList->end(), FilterEntry( aTitle, aFilter ) );
554 0 : }
555 :
556 0 : void SAL_CALL SalGtkFilePicker::setCurrentFilter( const OUString& aTitle )
557 : throw( lang::IllegalArgumentException, uno::RuntimeException, std::exception )
558 : {
559 0 : SolarMutexGuard g;
560 :
561 : OSL_ASSERT( m_pDialog != NULL );
562 :
563 : OSL_TRACE( "Setting current filter to %s\n",
564 : OUStringToOString( aTitle, RTL_TEXTENCODING_UTF8 ).getStr() );
565 :
566 0 : if( aTitle != m_aCurrentFilter )
567 : {
568 0 : m_aCurrentFilter = aTitle;
569 0 : SetCurFilter( m_aCurrentFilter );
570 : OSL_TRACE( "REALLY Setting current filter to %s\n",
571 : OUStringToOString( aTitle, RTL_TEXTENCODING_UTF8 ).getStr() );
572 :
573 0 : }
574 :
575 : // TODO m_pImpl->setCurrentFilter( aTitle );
576 0 : }
577 :
578 0 : void SalGtkFilePicker::updateCurrentFilterFromName(const gchar* filtername)
579 : {
580 0 : OUString aFilterName(filtername, strlen(filtername), RTL_TEXTENCODING_UTF8);
581 0 : FilterList::iterator aEnd = m_pFilterList->end();
582 0 : for (FilterList::iterator aIter = m_pFilterList->begin(); aIter != aEnd; ++aIter)
583 : {
584 0 : if (aFilterName == shrinkFilterName( aIter->getTitle()))
585 : {
586 0 : m_aCurrentFilter = aIter->getTitle();
587 0 : break;
588 : }
589 0 : }
590 0 : }
591 :
592 0 : void SalGtkFilePicker::UpdateFilterfromUI()
593 : {
594 : // Update the filtername from the users selection if they have had a chance to do so.
595 : // If the user explicitly sets a type then use that, if not then take the implicit type
596 : // from the filter of the files glob on which he is currently searching
597 0 : if (!mnHID_FolderChange || !mnHID_SelectionChange)
598 0 : return;
599 :
600 0 : GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(m_pFilterView));
601 : GtkTreeIter iter;
602 : GtkTreeModel *model;
603 0 : if (gtk_tree_selection_get_selected (selection, &model, &iter))
604 : {
605 : gchar *title;
606 0 : gtk_tree_model_get (model, &iter, 2, &title, -1);
607 0 : updateCurrentFilterFromName(title);
608 0 : g_free (title);
609 : }
610 0 : else if( GtkFileFilter *filter = gtk_file_chooser_get_filter(GTK_FILE_CHOOSER(m_pDialog)))
611 : {
612 0 : if (m_pPseudoFilter != filter)
613 0 : updateCurrentFilterFromName(gtk_file_filter_get_name( filter ));
614 : else
615 0 : updateCurrentFilterFromName(OUStringToOString( m_aInitialFilter, RTL_TEXTENCODING_UTF8 ).getStr());
616 : }
617 : }
618 :
619 0 : OUString SAL_CALL SalGtkFilePicker::getCurrentFilter() throw( uno::RuntimeException, std::exception )
620 : {
621 0 : SolarMutexGuard g;
622 :
623 : OSL_ASSERT( m_pDialog != NULL );
624 :
625 : OSL_TRACE( "GetCURRENTfilter" );
626 :
627 0 : UpdateFilterfromUI();
628 :
629 : OSL_TRACE( "Returning current filter of %s\n",
630 : OUStringToOString( m_aCurrentFilter, RTL_TEXTENCODING_UTF8 ).getStr() );
631 :
632 0 : return m_aCurrentFilter;
633 : }
634 :
635 : // XFilterGroupManager functions
636 :
637 0 : void SAL_CALL SalGtkFilePicker::appendFilterGroup( const OUString& /*sGroupTitle*/, const uno::Sequence<beans::StringPair>& aFilters )
638 : throw( lang::IllegalArgumentException, uno::RuntimeException, std::exception )
639 : {
640 0 : SolarMutexGuard g;
641 :
642 : OSL_ASSERT( m_pDialog != NULL );
643 :
644 : // TODO m_pImpl->appendFilterGroup( sGroupTitle, aFilters );
645 : // check the names
646 0 : if( FilterNameExists( aFilters ) )
647 : // TODO: a more precise exception message
648 0 : throw IllegalArgumentException();
649 :
650 : // ensure that we have a filter list
651 0 : OUString sInitialCurrentFilter;
652 0 : if( aFilters.getLength() )
653 0 : sInitialCurrentFilter = aFilters[0].First;
654 :
655 0 : ensureFilterList( sInitialCurrentFilter );
656 :
657 : // append the filter
658 0 : const StringPair* pSubFilters = aFilters.getConstArray();
659 0 : const StringPair* pSubFiltersEnd = pSubFilters + aFilters.getLength();
660 0 : for( ; pSubFilters != pSubFiltersEnd; ++pSubFilters )
661 0 : m_pFilterList->insert( m_pFilterList->end(), FilterEntry( pSubFilters->First, pSubFilters->Second ) );
662 :
663 0 : }
664 :
665 : // XFilePicker functions
666 :
667 0 : void SAL_CALL SalGtkFilePicker::setMultiSelectionMode( sal_Bool bMode ) throw( uno::RuntimeException, std::exception )
668 : {
669 0 : SolarMutexGuard g;
670 :
671 : OSL_ASSERT( m_pDialog != NULL );
672 :
673 0 : gtk_file_chooser_set_select_multiple( GTK_FILE_CHOOSER(m_pDialog), bMode );
674 0 : }
675 :
676 0 : void SAL_CALL SalGtkFilePicker::setDefaultName( const OUString& aName )
677 : throw( uno::RuntimeException, std::exception )
678 : {
679 0 : SolarMutexGuard g;
680 :
681 : OSL_ASSERT( m_pDialog != NULL );
682 :
683 0 : OString aStr = OUStringToOString( aName, RTL_TEXTENCODING_UTF8 );
684 0 : GtkFileChooserAction eAction = gtk_file_chooser_get_action( GTK_FILE_CHOOSER( m_pDialog ) );
685 :
686 : // set_current_name launches a Gtk critical error if called for other than save
687 0 : if( GTK_FILE_CHOOSER_ACTION_SAVE == eAction )
688 0 : gtk_file_chooser_set_current_name( GTK_FILE_CHOOSER( m_pDialog ), aStr.getStr() );
689 0 : }
690 :
691 0 : void SAL_CALL SalGtkFilePicker::setDisplayDirectory( const OUString& rDirectory )
692 : throw( lang::IllegalArgumentException, uno::RuntimeException, std::exception )
693 : {
694 0 : SolarMutexGuard g;
695 :
696 0 : implsetDisplayDirectory(rDirectory);
697 0 : }
698 :
699 0 : OUString SAL_CALL SalGtkFilePicker::getDisplayDirectory() throw( uno::RuntimeException, std::exception )
700 : {
701 0 : SolarMutexGuard g;
702 :
703 0 : return implgetDisplayDirectory();
704 : }
705 :
706 0 : uno::Sequence<OUString> SAL_CALL SalGtkFilePicker::getFiles() throw( uno::RuntimeException, std::exception )
707 : {
708 : // no member access => no mutex needed
709 :
710 0 : uno::Sequence< OUString > aFiles = getSelectedFiles();
711 : /*
712 : The previous multiselection API design was completely broken
713 : and unimplementable for some hetrogenous pseudo-URIs eg. search:
714 : Thus crop unconditionally to a single selection.
715 : */
716 0 : aFiles.realloc (1);
717 0 : return aFiles;
718 : }
719 :
720 : namespace
721 : {
722 :
723 0 : bool lcl_matchFilter( const rtl::OUString& rFilter, const rtl::OUString& rExt )
724 : {
725 0 : const int nCount = comphelper::string::getTokenCount( rFilter, ';' );
726 :
727 0 : for ( int n = 0; n != nCount; ++n )
728 : {
729 0 : const rtl::OUString aToken = comphelper::string::getToken( rFilter, n, ';' );
730 0 : if ( aToken == rExt )
731 0 : return true;
732 0 : }
733 :
734 0 : return false;
735 : }
736 :
737 : }
738 :
739 0 : uno::Sequence<OUString> SAL_CALL SalGtkFilePicker::getSelectedFiles() throw( uno::RuntimeException, std::exception )
740 : {
741 0 : SolarMutexGuard g;
742 :
743 : OSL_ASSERT( m_pDialog != NULL );
744 :
745 0 : GSList* pPathList = gtk_file_chooser_get_uris( GTK_FILE_CHOOSER(m_pDialog) );
746 :
747 0 : int nCount = g_slist_length( pPathList );
748 0 : int nIndex = 0;
749 : OSL_TRACE( "GETFILES called %d files", nCount );
750 :
751 : // get the current action setting
752 : GtkFileChooserAction eAction = gtk_file_chooser_get_action(
753 0 : GTK_FILE_CHOOSER( m_pDialog ));
754 :
755 0 : uno::Sequence< OUString > aSelectedFiles(nCount);
756 :
757 : // Convert to OOo
758 0 : for( GSList *pElem = pPathList; pElem; pElem = pElem->next)
759 : {
760 0 : gchar *pURI = reinterpret_cast<gchar*>(pElem->data);
761 0 : aSelectedFiles[ nIndex ] = uritounicode(pURI);
762 :
763 0 : if( GTK_FILE_CHOOSER_ACTION_SAVE == eAction )
764 : {
765 0 : OUString sFilterName;
766 0 : sal_Int32 nTokenIndex = 0;
767 0 : bool bExtensionTypedIn = false;
768 :
769 0 : GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(m_pFilterView));
770 : GtkTreeIter iter;
771 : GtkTreeModel *model;
772 0 : if (gtk_tree_selection_get_selected (selection, &model, &iter))
773 : {
774 : gchar *title;
775 0 : gtk_tree_model_get (model, &iter, 2, &title, -1);
776 0 : sFilterName = OUString( title, strlen( title), RTL_TEXTENCODING_UTF8 );
777 0 : g_free (title);
778 : }
779 : else
780 : {
781 0 : if( aSelectedFiles[nIndex].indexOf('.') > 0 )
782 : {
783 0 : OUString sExtension;
784 0 : nTokenIndex = 0;
785 0 : do
786 0 : sExtension = aSelectedFiles[nIndex].getToken( 0, '.', nTokenIndex );
787 0 : while( nTokenIndex >= 0 );
788 :
789 0 : if( sExtension.getLength() >= 3 ) // 3 = typical/minimum extension length
790 : {
791 0 : static const OUString aStarDot( "*." );
792 :
793 0 : OUString aNewFilter;
794 0 : OUString aOldFilter = getCurrentFilter();
795 0 : bool bChangeFilter = true;
796 0 : for ( FilterList::iterator aListIter = m_pFilterList->begin();
797 0 : aListIter != m_pFilterList->end();
798 : ++aListIter
799 : )
800 : {
801 0 : if( lcl_matchFilter( aListIter->getFilter(), aStarDot+sExtension ) )
802 : {
803 0 : if( aNewFilter.isEmpty() )
804 0 : aNewFilter = aListIter->getTitle();
805 :
806 0 : if( aOldFilter == aListIter->getTitle() )
807 0 : bChangeFilter = false;
808 :
809 0 : bExtensionTypedIn = true;
810 : }
811 : }
812 0 : if( bChangeFilter && bExtensionTypedIn )
813 0 : setCurrentFilter( aNewFilter );
814 0 : }
815 : }
816 :
817 0 : GtkFileFilter *filter = gtk_file_chooser_get_filter(GTK_FILE_CHOOSER(m_pDialog));
818 0 : if (m_pPseudoFilter != filter)
819 : {
820 0 : const gchar* filtername = filter ? gtk_file_filter_get_name(filter) : NULL;
821 0 : if (filtername)
822 0 : sFilterName = OUString(filtername, strlen( filtername ), RTL_TEXTENCODING_UTF8);
823 : else
824 0 : sFilterName = OUString();
825 : }
826 : else
827 0 : sFilterName = m_aInitialFilter;
828 : }
829 :
830 : OSL_TRACE( "2: current filter is %s\n",
831 : OUStringToOString( sFilterName, RTL_TEXTENCODING_UTF8 ).getStr() );
832 :
833 : FilterList::iterator aListIter = ::std::find_if(
834 0 : m_pFilterList->begin(), m_pFilterList->end(), FilterTitleMatch(sFilterName) );
835 :
836 0 : OUString aFilter;
837 0 : if (aListIter != m_pFilterList->end())
838 0 : aFilter = aListIter->getFilter();
839 :
840 : OSL_TRACE( "turned into %s\n",
841 : OUStringToOString( aFilter, RTL_TEXTENCODING_UTF8 ).getStr() );
842 :
843 0 : nTokenIndex = 0;
844 0 : OUString sToken;
845 : // OUString strExt;
846 0 : do
847 : {
848 0 : sToken = aFilter.getToken( 0, '.', nTokenIndex );
849 :
850 0 : if ( sToken.lastIndexOf( ';' ) != -1 )
851 : {
852 0 : sal_Int32 nZero = 0;
853 0 : OUString aCurrentToken = sToken.getToken( 0, ';', nZero);
854 :
855 0 : sToken = aCurrentToken;
856 0 : break;
857 : }
858 : }
859 0 : while( nTokenIndex >= 0 );
860 :
861 0 : if( !bExtensionTypedIn && ( sToken != "*" ) )
862 : {
863 : //if the filename does not already have the auto extension, stick it on
864 0 : OUString sExtension = "." + sToken;
865 0 : OUString &rBase = aSelectedFiles[nIndex];
866 0 : sal_Int32 nExtensionIdx = rBase.getLength() - sExtension.getLength();
867 : OSL_TRACE( "idx are %d %d", rBase.lastIndexOf( sExtension ), nExtensionIdx );
868 :
869 0 : if( rBase.lastIndexOf( sExtension ) != nExtensionIdx )
870 0 : rBase += sExtension;
871 0 : }
872 :
873 : }
874 :
875 0 : nIndex++;
876 0 : g_free( pURI );
877 : }
878 :
879 0 : g_slist_free( pPathList );
880 :
881 0 : return aSelectedFiles;
882 : }
883 :
884 : // XExecutableDialog functions
885 :
886 0 : void SAL_CALL SalGtkFilePicker::setTitle( const OUString& rTitle ) throw( uno::RuntimeException, std::exception )
887 : {
888 0 : SolarMutexGuard g;
889 :
890 0 : implsetTitle(rTitle);
891 0 : }
892 :
893 0 : sal_Int16 SAL_CALL SalGtkFilePicker::execute() throw( uno::RuntimeException, std::exception )
894 : {
895 0 : SolarMutexGuard g;
896 :
897 : OSL_TRACE( "1: HERE WE ARE");
898 : OSL_ASSERT( m_pDialog != NULL );
899 :
900 0 : sal_Int16 retVal = 0;
901 :
902 0 : SetFilters();
903 :
904 : mnHID_FolderChange =
905 0 : g_signal_connect( GTK_FILE_CHOOSER( m_pDialog ), "current-folder-changed",
906 0 : G_CALLBACK( folder_changed_cb ), ( gpointer )this );
907 :
908 : mnHID_SelectionChange =
909 0 : g_signal_connect( GTK_FILE_CHOOSER( m_pDialog ), "selection-changed",
910 0 : G_CALLBACK( selection_changed_cb ), ( gpointer )this );
911 :
912 0 : int btn = GTK_RESPONSE_NO;
913 :
914 : uno::Reference< awt::XExtendedToolkit > xToolkit(
915 : awt::Toolkit::create(m_xContext),
916 0 : UNO_QUERY_THROW );
917 :
918 : uno::Reference< frame::XDesktop > xDesktop(
919 : frame::Desktop::create(m_xContext),
920 0 : UNO_QUERY_THROW );
921 :
922 0 : RunDialog* pRunDialog = new RunDialog(m_pDialog, xToolkit, xDesktop);
923 0 : uno::Reference < awt::XTopWindowListener > xLifeCycle(pRunDialog);
924 0 : while( GTK_RESPONSE_NO == btn )
925 : {
926 0 : btn = GTK_RESPONSE_YES; // we dont want to repeat unless user clicks NO for file save.
927 :
928 0 : gint nStatus = pRunDialog->run();
929 0 : switch( nStatus )
930 : {
931 : case GTK_RESPONSE_ACCEPT:
932 0 : if( GTK_FILE_CHOOSER_ACTION_SAVE == gtk_file_chooser_get_action( GTK_FILE_CHOOSER( m_pDialog ) ) )
933 : {
934 0 : Sequence < OUString > aPathSeq = getFiles();
935 0 : if( aPathSeq.getLength() == 1 )
936 : {
937 0 : OString sFileName = unicodetouri( aPathSeq[0] );
938 0 : gchar *gFileName = g_filename_from_uri ( sFileName.getStr(), NULL, NULL );
939 0 : if( g_file_test( gFileName, G_FILE_TEST_IS_REGULAR ) )
940 : {
941 0 : INetURLObject aFileObj( OStringToOUString(sFileName, RTL_TEXTENCODING_UTF8) );
942 :
943 : OString baseName(
944 : OUStringToOString(
945 : aFileObj.getName(
946 : INetURLObject::LAST_SEGMENT,
947 : true,
948 : INetURLObject::DECODE_WITH_CHARSET
949 : ),
950 : RTL_TEXTENCODING_UTF8
951 : )
952 0 : );
953 : OString aMsg(
954 : OUStringToOString(
955 : getResString( FILE_PICKER_OVERWRITE_PRIMARY ),
956 : RTL_TEXTENCODING_UTF8
957 : )
958 0 : );
959 0 : OString toReplace("$filename$");
960 :
961 0 : aMsg = aMsg.replaceAt(
962 : aMsg.indexOf( toReplace ),
963 : toReplace.getLength(),
964 : baseName
965 0 : );
966 :
967 : GtkWidget *dlg = gtk_message_dialog_new( NULL,
968 : GTK_DIALOG_MODAL,
969 : GTK_MESSAGE_QUESTION,
970 : GTK_BUTTONS_YES_NO,
971 : "%s",
972 : aMsg.getStr()
973 0 : );
974 :
975 0 : sal_Int32 nSegmentCount = aFileObj.getSegmentCount();
976 0 : if (nSegmentCount >= 2)
977 : {
978 : OString dirName(
979 : OUStringToOString(
980 : aFileObj.getName(
981 : nSegmentCount-2,
982 : true,
983 : INetURLObject::DECODE_WITH_CHARSET
984 : ),
985 : RTL_TEXTENCODING_UTF8
986 : )
987 0 : );
988 :
989 0 : aMsg =
990 : OUStringToOString(
991 : getResString( FILE_PICKER_OVERWRITE_SECONDARY ),
992 : RTL_TEXTENCODING_UTF8
993 0 : );
994 :
995 0 : toReplace = "$dirname$";
996 :
997 0 : aMsg = aMsg.replaceAt(
998 : aMsg.indexOf( toReplace ),
999 : toReplace.getLength(),
1000 : dirName
1001 0 : );
1002 :
1003 0 : gtk_message_dialog_format_secondary_text( GTK_MESSAGE_DIALOG( dlg ), "%s", aMsg.getStr() );
1004 : }
1005 :
1006 0 : gtk_window_set_title( GTK_WINDOW( dlg ),
1007 : OUStringToOString(getResString(FILE_PICKER_TITLE_SAVE ),
1008 0 : RTL_TEXTENCODING_UTF8 ).getStr() );
1009 :
1010 0 : RunDialog* pAnotherDialog = new RunDialog(dlg, xToolkit, xDesktop);
1011 0 : uno::Reference < awt::XTopWindowListener > xAnotherLifeCycle(pAnotherDialog);
1012 0 : btn = pAnotherDialog->run();
1013 :
1014 0 : gtk_widget_destroy( dlg );
1015 : }
1016 0 : g_free (gFileName);
1017 :
1018 0 : if( btn == GTK_RESPONSE_YES )
1019 0 : retVal = ExecutableDialogResults::OK;
1020 0 : }
1021 : }
1022 : else
1023 0 : retVal = ExecutableDialogResults::OK;
1024 0 : break;
1025 :
1026 : case GTK_RESPONSE_CANCEL:
1027 0 : retVal = ExecutableDialogResults::CANCEL;
1028 0 : break;
1029 :
1030 : case 1: //PLAY
1031 : {
1032 0 : FilePickerEvent evt;
1033 0 : evt.ElementId = PUSHBUTTON_PLAY;
1034 : OSL_TRACE( "filter_changed, isn't it great %p", this);
1035 0 : impl_controlStateChanged( evt );
1036 0 : btn = GTK_RESPONSE_NO;
1037 : }
1038 0 : break;
1039 :
1040 : default:
1041 0 : retVal = 0;
1042 0 : break;
1043 : }
1044 : }
1045 :
1046 0 : if (mnHID_FolderChange)
1047 0 : g_signal_handler_disconnect(GTK_FILE_CHOOSER( m_pDialog ), mnHID_FolderChange);
1048 0 : if (mnHID_SelectionChange)
1049 0 : g_signal_handler_disconnect(GTK_FILE_CHOOSER( m_pDialog ), mnHID_SelectionChange);
1050 :
1051 0 : return retVal;
1052 : }
1053 :
1054 : // cf. offapi/com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.idl
1055 0 : GtkWidget *SalGtkFilePicker::getWidget( sal_Int16 nControlId, GType *pType )
1056 : {
1057 : OSL_TRACE("control id is %d", nControlId);
1058 0 : GType tType = GTK_TYPE_TOGGLE_BUTTON; //prevent waring by initializing
1059 0 : GtkWidget *pWidget = 0;
1060 :
1061 : #define MAP_TOGGLE( elem ) \
1062 : case ExtendedFilePickerElementIds::CHECKBOX_##elem: \
1063 : pWidget = m_pToggles[elem]; tType = GTK_TYPE_TOGGLE_BUTTON; \
1064 : break
1065 : #define MAP_BUTTON( elem ) \
1066 : case ExtendedFilePickerElementIds::PUSHBUTTON_##elem: \
1067 : pWidget = m_pButtons[elem]; tType = GTK_TYPE_BUTTON; \
1068 : break
1069 : #define MAP_LIST( elem ) \
1070 : case ExtendedFilePickerElementIds::LISTBOX_##elem: \
1071 : pWidget = m_pLists[elem]; tType = GTK_TYPE_COMBO_BOX; \
1072 : break
1073 : #define MAP_LIST_LABEL( elem ) \
1074 : case ExtendedFilePickerElementIds::LISTBOX_##elem##_LABEL: \
1075 : pWidget = m_pListLabels[elem]; tType = GTK_TYPE_LABEL; \
1076 : break
1077 :
1078 0 : switch( nControlId )
1079 : {
1080 0 : MAP_TOGGLE( AUTOEXTENSION );
1081 0 : MAP_TOGGLE( PASSWORD );
1082 0 : MAP_TOGGLE( FILTEROPTIONS );
1083 0 : MAP_TOGGLE( READONLY );
1084 0 : MAP_TOGGLE( LINK );
1085 0 : MAP_TOGGLE( PREVIEW );
1086 0 : MAP_TOGGLE( SELECTION );
1087 0 : MAP_BUTTON( PLAY );
1088 0 : MAP_LIST( VERSION );
1089 0 : MAP_LIST( TEMPLATE );
1090 0 : MAP_LIST( IMAGE_TEMPLATE );
1091 0 : MAP_LIST_LABEL( VERSION );
1092 0 : MAP_LIST_LABEL( TEMPLATE );
1093 0 : MAP_LIST_LABEL( IMAGE_TEMPLATE );
1094 : default:
1095 : OSL_TRACE("Handle unknown control %d", nControlId);
1096 0 : break;
1097 : }
1098 : #undef MAP
1099 :
1100 0 : if( pType )
1101 0 : *pType = tType;
1102 0 : return pWidget;
1103 : }
1104 :
1105 : // XFilePickerControlAccess functions
1106 :
1107 0 : static void HackWidthToFirst(GtkComboBox *pWidget)
1108 : {
1109 : GtkRequisition requisition;
1110 0 : gtk_widget_size_request(GTK_WIDGET(pWidget), &requisition);
1111 0 : gtk_widget_set_size_request(GTK_WIDGET(pWidget), requisition.width, -1);
1112 0 : }
1113 :
1114 0 : static void ComboBoxAppendText(GtkComboBox *pCombo, const OUString &rStr)
1115 : {
1116 : GtkTreeIter aIter;
1117 0 : GtkListStore *pStore = GTK_LIST_STORE(gtk_combo_box_get_model(pCombo));
1118 0 : OString aStr = OUStringToOString(rStr, RTL_TEXTENCODING_UTF8);
1119 0 : gtk_list_store_append(pStore, &aIter);
1120 0 : gtk_list_store_set(pStore, &aIter, 0, aStr.getStr(), -1);
1121 0 : }
1122 :
1123 0 : void SalGtkFilePicker::HandleSetListValue(GtkComboBox *pWidget, sal_Int16 nControlAction, const uno::Any& rValue)
1124 : {
1125 0 : switch (nControlAction)
1126 : {
1127 : case ControlActions::ADD_ITEM:
1128 : {
1129 0 : OUString sItem;
1130 0 : rValue >>= sItem;
1131 0 : ComboBoxAppendText(pWidget, sItem);
1132 0 : if (!bVersionWidthUnset)
1133 : {
1134 0 : HackWidthToFirst(pWidget);
1135 0 : bVersionWidthUnset = true;
1136 0 : }
1137 : }
1138 0 : break;
1139 : case ControlActions::ADD_ITEMS:
1140 : {
1141 0 : Sequence< OUString > aStringList;
1142 0 : rValue >>= aStringList;
1143 0 : sal_Int32 nItemCount = aStringList.getLength();
1144 0 : for (sal_Int32 i = 0; i < nItemCount; ++i)
1145 : {
1146 0 : ComboBoxAppendText(pWidget,aStringList[i]);
1147 0 : if (!bVersionWidthUnset)
1148 : {
1149 0 : HackWidthToFirst(pWidget);
1150 0 : bVersionWidthUnset = true;
1151 : }
1152 0 : }
1153 : }
1154 0 : break;
1155 : case ControlActions::DELETE_ITEM:
1156 : {
1157 0 : sal_Int32 nPos=0;
1158 0 : rValue >>= nPos;
1159 :
1160 : GtkTreeIter aIter;
1161 0 : GtkListStore *pStore = GTK_LIST_STORE(
1162 : gtk_combo_box_get_model(GTK_COMBO_BOX(pWidget)));
1163 0 : if(gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(pStore), &aIter, NULL, nPos))
1164 0 : gtk_list_store_remove(pStore, &aIter);
1165 : }
1166 0 : break;
1167 : case ControlActions::DELETE_ITEMS:
1168 : {
1169 0 : gtk_combo_box_set_active(pWidget, -1);
1170 0 : GtkListStore *pStore = GTK_LIST_STORE(
1171 : gtk_combo_box_get_model(GTK_COMBO_BOX(pWidget)));
1172 0 : gtk_list_store_clear(pStore);
1173 : }
1174 0 : break;
1175 : case ControlActions::SET_SELECT_ITEM:
1176 : {
1177 0 : sal_Int32 nPos=0;
1178 0 : rValue >>= nPos;
1179 0 : gtk_combo_box_set_active(pWidget, nPos);
1180 : }
1181 0 : break;
1182 : default:
1183 : OSL_TRACE("undocumented/unimplemented ControlAction for a list");
1184 0 : break;
1185 : }
1186 :
1187 : //I think its best to make it insensitive unless there is the chance to
1188 : //actually select something from the list.
1189 : gint nItems = gtk_tree_model_iter_n_children(
1190 0 : gtk_combo_box_get_model(pWidget), NULL);
1191 0 : gtk_widget_set_sensitive(GTK_WIDGET(pWidget), nItems > 1);
1192 0 : }
1193 :
1194 0 : uno::Any SalGtkFilePicker::HandleGetListValue(GtkComboBox *pWidget, sal_Int16 nControlAction) const
1195 : {
1196 0 : uno::Any aAny;
1197 0 : switch (nControlAction)
1198 : {
1199 : case ControlActions::GET_ITEMS:
1200 : {
1201 0 : Sequence< OUString > aItemList;
1202 :
1203 0 : GtkTreeModel *pTree = gtk_combo_box_get_model(pWidget);
1204 : GtkTreeIter iter;
1205 0 : if (gtk_tree_model_get_iter_first(pTree, &iter))
1206 : {
1207 : sal_Int32 nSize = gtk_tree_model_iter_n_children(
1208 0 : pTree, NULL);
1209 :
1210 0 : aItemList.realloc(nSize);
1211 0 : for (sal_Int32 i=0; i < nSize; ++i)
1212 : {
1213 : gchar *item;
1214 : gtk_tree_model_get(gtk_combo_box_get_model(pWidget),
1215 0 : &iter, 0, &item, -1);
1216 0 : aItemList[i] = OUString(item, strlen(item), RTL_TEXTENCODING_UTF8);
1217 0 : g_free(item);
1218 0 : gtk_tree_model_iter_next(pTree, &iter);
1219 : }
1220 : }
1221 0 : aAny <<= aItemList;
1222 : }
1223 0 : break;
1224 : case ControlActions::GET_SELECTED_ITEM:
1225 : {
1226 : GtkTreeIter iter;
1227 0 : if (gtk_combo_box_get_active_iter(pWidget, &iter))
1228 : {
1229 : gchar *item;
1230 : gtk_tree_model_get(gtk_combo_box_get_model(pWidget),
1231 0 : &iter, 0, &item, -1);
1232 0 : OUString sItem(item, strlen(item), RTL_TEXTENCODING_UTF8);
1233 0 : aAny <<= sItem;
1234 0 : g_free(item);
1235 : }
1236 : }
1237 0 : break;
1238 : case ControlActions::GET_SELECTED_ITEM_INDEX:
1239 : {
1240 0 : gint nActive = gtk_combo_box_get_active(pWidget);
1241 0 : aAny <<= static_cast< sal_Int32 >(nActive);
1242 : }
1243 0 : break;
1244 : default:
1245 : OSL_TRACE("undocumented/unimplemented ControlAction for a list");
1246 0 : break;
1247 : }
1248 0 : return aAny;
1249 : }
1250 :
1251 0 : void SAL_CALL SalGtkFilePicker::setValue( sal_Int16 nControlId, sal_Int16 nControlAction, const uno::Any& rValue )
1252 : throw( uno::RuntimeException, std::exception )
1253 : {
1254 0 : SolarMutexGuard g;
1255 :
1256 : OSL_ASSERT( m_pDialog != NULL );
1257 :
1258 : OSL_TRACE( "SETTING VALUE %d", nControlAction );
1259 : GType tType;
1260 : GtkWidget *pWidget;
1261 :
1262 0 : if( !( pWidget = getWidget( nControlId, &tType ) ) )
1263 : OSL_TRACE("enable unknown control %d", nControlId);
1264 0 : else if( tType == GTK_TYPE_TOGGLE_BUTTON )
1265 : {
1266 0 : bool bChecked = false;
1267 0 : rValue >>= bChecked;
1268 0 : gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( pWidget ), bChecked );
1269 : }
1270 0 : else if( tType == GTK_TYPE_COMBO_BOX )
1271 0 : HandleSetListValue(GTK_COMBO_BOX(pWidget), nControlAction, rValue);
1272 : else
1273 : {
1274 : OSL_TRACE("Can't set value on button / list %d %d\n",
1275 : nControlId, nControlAction);
1276 0 : }
1277 0 : }
1278 :
1279 0 : uno::Any SAL_CALL SalGtkFilePicker::getValue( sal_Int16 nControlId, sal_Int16 nControlAction )
1280 : throw( uno::RuntimeException, std::exception )
1281 : {
1282 0 : SolarMutexGuard g;
1283 :
1284 : OSL_ASSERT( m_pDialog != NULL );
1285 :
1286 0 : uno::Any aRetval;
1287 :
1288 : GType tType;
1289 : GtkWidget *pWidget;
1290 :
1291 0 : if( !( pWidget = getWidget( nControlId, &tType ) ) )
1292 : OSL_TRACE("enable unknown control %d", nControlId);
1293 0 : else if( tType == GTK_TYPE_TOGGLE_BUTTON )
1294 0 : aRetval <<= bool( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( pWidget ) ) );
1295 0 : else if( tType == GTK_TYPE_COMBO_BOX )
1296 0 : aRetval = HandleGetListValue(GTK_COMBO_BOX(pWidget), nControlAction);
1297 : else
1298 : OSL_TRACE("Can't get value on button / list %d %d\n",
1299 : nControlId, nControlAction );
1300 :
1301 0 : return aRetval;
1302 : }
1303 :
1304 0 : void SAL_CALL SalGtkFilePicker::enableControl( sal_Int16 nControlId, sal_Bool bEnable )
1305 : throw( uno::RuntimeException, std::exception )
1306 : {
1307 0 : SolarMutexGuard g;
1308 :
1309 : OSL_ASSERT( m_pDialog != NULL );
1310 :
1311 : GtkWidget *pWidget;
1312 :
1313 0 : if ( ( pWidget = getWidget( nControlId ) ) )
1314 : {
1315 0 : if( bEnable )
1316 : {
1317 : OSL_TRACE( "enable" );
1318 0 : gtk_widget_set_sensitive( pWidget, true );
1319 : }
1320 : else
1321 : {
1322 : OSL_TRACE( "disable" );
1323 0 : gtk_widget_set_sensitive( pWidget, false );
1324 : }
1325 : }
1326 : else
1327 0 : OSL_TRACE("enable unknown control %d", nControlId );
1328 0 : }
1329 :
1330 0 : void SAL_CALL SalGtkFilePicker::setLabel( sal_Int16 nControlId, const OUString& rLabel )
1331 : throw( uno::RuntimeException, std::exception )
1332 : {
1333 0 : SolarMutexGuard g;
1334 :
1335 : OSL_ASSERT( m_pDialog != NULL );
1336 :
1337 : GType tType;
1338 : GtkWidget *pWidget;
1339 :
1340 0 : if( !( pWidget = getWidget( nControlId, &tType ) ) )
1341 : {
1342 : OSL_TRACE("Set label on unknown control %d", nControlId);
1343 0 : return;
1344 : }
1345 :
1346 0 : OString aTxt = OUStringToOString( rLabel.replace('~', '_'), RTL_TEXTENCODING_UTF8 );
1347 0 : if (nControlId == ExtendedFilePickerElementIds::PUSHBUTTON_PLAY)
1348 : {
1349 : #ifdef GTK_STOCK_MEDIA_PLAY
1350 0 : if (msPlayLabel.isEmpty())
1351 0 : msPlayLabel = rLabel;
1352 0 : if (msPlayLabel == rLabel)
1353 0 : gtk_button_set_label(GTK_BUTTON(pWidget), GTK_STOCK_MEDIA_PLAY);
1354 : else
1355 0 : gtk_button_set_label(GTK_BUTTON(pWidget), GTK_STOCK_MEDIA_STOP);
1356 : #else
1357 : gtk_button_set_label(GTK_BUTTON(pWidget), aTxt.getStr());
1358 : #endif
1359 : }
1360 0 : else if( tType == GTK_TYPE_TOGGLE_BUTTON || tType == GTK_TYPE_BUTTON || tType == GTK_TYPE_LABEL )
1361 : g_object_set( pWidget, "label", aTxt.getStr(),
1362 0 : "use_underline", true, (char *)NULL );
1363 : else
1364 0 : OSL_TRACE("Can't set label on list");
1365 : }
1366 :
1367 0 : OUString SAL_CALL SalGtkFilePicker::getLabel( sal_Int16 nControlId )
1368 : throw( uno::RuntimeException, std::exception )
1369 : {
1370 0 : SolarMutexGuard g;
1371 :
1372 : OSL_ASSERT( m_pDialog != NULL );
1373 :
1374 : GType tType;
1375 0 : OString aTxt;
1376 : GtkWidget *pWidget;
1377 :
1378 0 : if( !( pWidget = getWidget( nControlId, &tType ) ) )
1379 : OSL_TRACE("Get label on unknown control %d", nControlId);
1380 0 : else if( tType == GTK_TYPE_TOGGLE_BUTTON || tType == GTK_TYPE_BUTTON || tType == GTK_TYPE_LABEL )
1381 0 : aTxt = gtk_button_get_label( GTK_BUTTON( pWidget ) );
1382 : else
1383 : OSL_TRACE("Can't get label on list");
1384 :
1385 0 : return OStringToOUString( aTxt, RTL_TEXTENCODING_UTF8 );
1386 : }
1387 :
1388 : // XFilePreview functions
1389 :
1390 0 : uno::Sequence<sal_Int16> SAL_CALL SalGtkFilePicker::getSupportedImageFormats() throw( uno::RuntimeException, std::exception )
1391 : {
1392 0 : SolarMutexGuard g;
1393 :
1394 : OSL_ASSERT( m_pDialog != NULL );
1395 :
1396 : // TODO return m_pImpl->getSupportedImageFormats();
1397 0 : return uno::Sequence<sal_Int16>();
1398 : }
1399 :
1400 0 : sal_Int32 SAL_CALL SalGtkFilePicker::getTargetColorDepth() throw( uno::RuntimeException, std::exception )
1401 : {
1402 0 : SolarMutexGuard g;
1403 :
1404 : OSL_ASSERT( m_pDialog != NULL );
1405 :
1406 : // TODO return m_pImpl->getTargetColorDepth();
1407 0 : return 0;
1408 : }
1409 :
1410 0 : sal_Int32 SAL_CALL SalGtkFilePicker::getAvailableWidth() throw( uno::RuntimeException, std::exception )
1411 : {
1412 0 : SolarMutexGuard g;
1413 :
1414 : OSL_ASSERT( m_pDialog != NULL );
1415 :
1416 0 : return m_PreviewImageWidth;
1417 : }
1418 :
1419 0 : sal_Int32 SAL_CALL SalGtkFilePicker::getAvailableHeight() throw( uno::RuntimeException, std::exception )
1420 : {
1421 0 : SolarMutexGuard g;
1422 :
1423 : OSL_ASSERT( m_pDialog != NULL );
1424 :
1425 0 : return m_PreviewImageHeight;
1426 : }
1427 :
1428 0 : void SAL_CALL SalGtkFilePicker::setImage( sal_Int16 /*aImageFormat*/, const uno::Any& /*aImage*/ )
1429 : throw( lang::IllegalArgumentException, uno::RuntimeException, std::exception )
1430 : {
1431 0 : SolarMutexGuard g;
1432 :
1433 0 : OSL_ASSERT( m_pDialog != NULL );
1434 :
1435 : // TODO m_pImpl->setImage( aImageFormat, aImage );
1436 0 : }
1437 :
1438 0 : void SalGtkFilePicker::implChangeType( GtkTreeSelection *selection )
1439 : {
1440 0 : OUString aLabel = getResString( FILE_PICKER_FILE_TYPE );
1441 :
1442 : GtkTreeIter iter;
1443 : GtkTreeModel *model;
1444 0 : if (gtk_tree_selection_get_selected (selection, &model, &iter))
1445 : {
1446 : gchar *title;
1447 0 : gtk_tree_model_get (model, &iter, 2, &title, -1);
1448 0 : aLabel += ": ";
1449 0 : aLabel += OUString( title, strlen(title), RTL_TEXTENCODING_UTF8 );
1450 0 : g_free (title);
1451 : }
1452 0 : gtk_expander_set_label (GTK_EXPANDER (m_pFilterExpander),
1453 0 : OUStringToOString( aLabel, RTL_TEXTENCODING_UTF8 ).getStr());
1454 0 : FilePickerEvent evt;
1455 0 : evt.ElementId = LISTBOX_FILTER;
1456 0 : impl_controlStateChanged( evt );
1457 0 : }
1458 :
1459 0 : void SalGtkFilePicker::type_changed_cb( GtkTreeSelection *selection, SalGtkFilePicker *pobjFP )
1460 : {
1461 0 : pobjFP->implChangeType(selection);
1462 0 : }
1463 :
1464 0 : void SalGtkFilePicker::unselect_type()
1465 : {
1466 0 : gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(m_pFilterView)));
1467 0 : }
1468 :
1469 0 : void SalGtkFilePicker::expander_changed_cb( GtkExpander *expander, SalGtkFilePicker *pobjFP )
1470 : {
1471 0 : if (gtk_expander_get_expanded(expander))
1472 0 : pobjFP->unselect_type();
1473 0 : }
1474 :
1475 0 : void SalGtkFilePicker::filter_changed_cb( GtkFileChooser *, GParamSpec *,
1476 : SalGtkFilePicker *pobjFP )
1477 : {
1478 0 : FilePickerEvent evt;
1479 0 : evt.ElementId = LISTBOX_FILTER;
1480 : OSL_TRACE( "filter_changed, isn't it great %p", pobjFP );
1481 0 : pobjFP->impl_controlStateChanged( evt );
1482 0 : }
1483 :
1484 0 : void SalGtkFilePicker::folder_changed_cb( GtkFileChooser *, SalGtkFilePicker *pobjFP )
1485 : {
1486 0 : FilePickerEvent evt;
1487 : OSL_TRACE( "folder_changed, isn't it great %p", pobjFP );
1488 0 : pobjFP->impl_directoryChanged( evt );
1489 0 : }
1490 :
1491 0 : void SalGtkFilePicker::selection_changed_cb( GtkFileChooser *, SalGtkFilePicker *pobjFP )
1492 : {
1493 0 : FilePickerEvent evt;
1494 : OSL_TRACE( "selection_changed, isn't it great %p", pobjFP );
1495 0 : pobjFP->impl_fileSelectionChanged( evt );
1496 0 : }
1497 :
1498 0 : void SalGtkFilePicker::update_preview_cb( GtkFileChooser *file_chooser, SalGtkFilePicker* pobjFP )
1499 : {
1500 : GtkWidget *preview;
1501 : char *filename;
1502 : GdkPixbuf *pixbuf;
1503 0 : gboolean have_preview = false;
1504 :
1505 0 : preview = pobjFP->m_pPreview;
1506 0 : filename = gtk_file_chooser_get_preview_filename( file_chooser );
1507 :
1508 0 : if( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( pobjFP->m_pToggles[PREVIEW] ) ) && g_file_test( filename, G_FILE_TEST_IS_REGULAR ) )
1509 : {
1510 : pixbuf = gdk_pixbuf_new_from_file_at_size(
1511 : filename,
1512 : pobjFP->m_PreviewImageWidth,
1513 0 : pobjFP->m_PreviewImageHeight, NULL );
1514 :
1515 0 : have_preview = ( pixbuf != NULL );
1516 :
1517 0 : gtk_image_set_from_pixbuf( GTK_IMAGE( preview ), pixbuf );
1518 0 : if( pixbuf )
1519 0 : g_object_unref( G_OBJECT( pixbuf ) );
1520 :
1521 : }
1522 :
1523 0 : gtk_file_chooser_set_preview_widget_active( file_chooser, have_preview );
1524 :
1525 0 : if( filename )
1526 0 : g_free( filename );
1527 0 : }
1528 :
1529 0 : sal_Bool SAL_CALL SalGtkFilePicker::setShowState( sal_Bool bShowState ) throw( uno::RuntimeException, std::exception )
1530 : {
1531 0 : SolarMutexGuard g;
1532 :
1533 : OSL_ASSERT( m_pDialog != NULL );
1534 :
1535 : // TODO return m_pImpl->setShowState( bShowState );
1536 0 : if( bool(bShowState) != mbPreviewState )
1537 : {
1538 0 : if( bShowState )
1539 : {
1540 : // Show
1541 0 : if( !mHID_Preview )
1542 : {
1543 0 : mHID_Preview = g_signal_connect(
1544 : GTK_FILE_CHOOSER( m_pDialog ), "update-preview",
1545 0 : G_CALLBACK( update_preview_cb ), ( gpointer )this );
1546 : }
1547 0 : gtk_widget_show( m_pPreview );
1548 : }
1549 : else
1550 : {
1551 : // Hide
1552 0 : gtk_widget_hide( m_pPreview );
1553 : }
1554 :
1555 : // also emit the signal
1556 0 : g_signal_emit_by_name( G_OBJECT( m_pDialog ), "update-preview" );
1557 :
1558 0 : mbPreviewState = bShowState;
1559 : }
1560 0 : return true;
1561 : }
1562 :
1563 0 : sal_Bool SAL_CALL SalGtkFilePicker::getShowState() throw( uno::RuntimeException, std::exception )
1564 : {
1565 0 : SolarMutexGuard g;
1566 :
1567 : OSL_ASSERT( m_pDialog != NULL );
1568 :
1569 0 : return mbPreviewState;
1570 : }
1571 :
1572 : // XInitialization
1573 :
1574 0 : void SAL_CALL SalGtkFilePicker::initialize( const uno::Sequence<uno::Any>& aArguments )
1575 : throw( uno::Exception, uno::RuntimeException, std::exception )
1576 : {
1577 : // parameter checking
1578 0 : uno::Any aAny;
1579 0 : if( 0 == aArguments.getLength() )
1580 : throw lang::IllegalArgumentException(
1581 : OUString( "no arguments" ),
1582 0 : static_cast<XFilePicker2*>( this ), 1 );
1583 :
1584 0 : aAny = aArguments[0];
1585 :
1586 0 : if( ( aAny.getValueType() != cppu::UnoType<sal_Int16>::get()) &&
1587 0 : (aAny.getValueType() != cppu::UnoType<sal_Int8>::get()) )
1588 : throw lang::IllegalArgumentException(
1589 : OUString( "invalid argument type" ),
1590 0 : static_cast<XFilePicker2*>( this ), 1 );
1591 :
1592 0 : sal_Int16 templateId = -1;
1593 0 : aAny >>= templateId;
1594 :
1595 0 : GtkFileChooserAction eAction = GTK_FILE_CHOOSER_ACTION_OPEN;
1596 0 : const gchar *first_button_text = GTK_STOCK_OPEN;
1597 :
1598 0 : SolarMutexGuard g;
1599 :
1600 : // TODO: extract full semantic from
1601 : // svtools/source/filepicker/filepicker.cxx (getWinBits)
1602 0 : switch( templateId )
1603 : {
1604 : case FILEOPEN_SIMPLE:
1605 0 : eAction = GTK_FILE_CHOOSER_ACTION_OPEN;
1606 0 : first_button_text = GTK_STOCK_OPEN;
1607 : OSL_TRACE( "3all true" );
1608 0 : break;
1609 : case FILESAVE_SIMPLE:
1610 0 : eAction = GTK_FILE_CHOOSER_ACTION_SAVE;
1611 0 : first_button_text = GTK_STOCK_SAVE;
1612 : OSL_TRACE( "2all true" );
1613 0 : break;
1614 : case FILESAVE_AUTOEXTENSION_PASSWORD:
1615 0 : eAction = GTK_FILE_CHOOSER_ACTION_SAVE;
1616 0 : first_button_text = GTK_STOCK_SAVE;
1617 0 : mbToggleVisibility[PASSWORD] = true;
1618 : OSL_TRACE( "1all true" );
1619 : // TODO
1620 0 : break;
1621 : case FILESAVE_AUTOEXTENSION_PASSWORD_FILTEROPTIONS:
1622 0 : eAction = GTK_FILE_CHOOSER_ACTION_SAVE;
1623 0 : first_button_text = GTK_STOCK_SAVE;
1624 0 : mbToggleVisibility[PASSWORD] = true;
1625 0 : mbToggleVisibility[FILTEROPTIONS] = true;
1626 : OSL_TRACE( "4all true" );
1627 : // TODO
1628 0 : break;
1629 : case FILESAVE_AUTOEXTENSION_SELECTION:
1630 0 : eAction = GTK_FILE_CHOOSER_ACTION_SAVE; // SELECT_FOLDER ?
1631 0 : first_button_text = GTK_STOCK_SAVE;
1632 0 : mbToggleVisibility[SELECTION] = true;
1633 : OSL_TRACE( "5all true" );
1634 : // TODO
1635 0 : break;
1636 : case FILESAVE_AUTOEXTENSION_TEMPLATE:
1637 0 : eAction = GTK_FILE_CHOOSER_ACTION_SAVE;
1638 0 : first_button_text = GTK_STOCK_SAVE;
1639 0 : mbListVisibility[TEMPLATE] = true;
1640 : OSL_TRACE( "6all true" );
1641 : // TODO
1642 0 : break;
1643 : case FILEOPEN_LINK_PREVIEW_IMAGE_TEMPLATE:
1644 0 : eAction = GTK_FILE_CHOOSER_ACTION_OPEN;
1645 0 : first_button_text = GTK_STOCK_OPEN;
1646 0 : mbToggleVisibility[LINK] = true;
1647 0 : mbToggleVisibility[PREVIEW] = true;
1648 0 : mbListVisibility[IMAGE_TEMPLATE] = true;
1649 : // TODO
1650 0 : break;
1651 : case FILEOPEN_PLAY:
1652 0 : eAction = GTK_FILE_CHOOSER_ACTION_OPEN;
1653 0 : first_button_text = GTK_STOCK_OPEN;
1654 0 : mbButtonVisibility[PLAY] = true;
1655 : // TODO
1656 0 : break;
1657 : case FILEOPEN_READONLY_VERSION:
1658 0 : eAction = GTK_FILE_CHOOSER_ACTION_OPEN;
1659 0 : first_button_text = GTK_STOCK_OPEN;
1660 0 : mbToggleVisibility[READONLY] = true;
1661 0 : mbListVisibility[VERSION] = true;
1662 0 : break;
1663 : case FILEOPEN_LINK_PREVIEW:
1664 0 : eAction = GTK_FILE_CHOOSER_ACTION_OPEN;
1665 0 : first_button_text = GTK_STOCK_OPEN;
1666 0 : mbToggleVisibility[LINK] = true;
1667 0 : mbToggleVisibility[PREVIEW] = true;
1668 : // TODO
1669 0 : break;
1670 : case FILESAVE_AUTOEXTENSION:
1671 0 : eAction = GTK_FILE_CHOOSER_ACTION_SAVE;
1672 0 : first_button_text = GTK_STOCK_SAVE;
1673 : OSL_TRACE( "7all true" );
1674 : // TODO
1675 0 : break;
1676 : default:
1677 : throw lang::IllegalArgumentException(
1678 : OUString( "Unknown template" ),
1679 : static_cast< XFilePicker2* >( this ),
1680 0 : 1 );
1681 : }
1682 :
1683 0 : if( GTK_FILE_CHOOSER_ACTION_SAVE == eAction )
1684 : {
1685 0 : OUString aFilePickerTitle(getResString( FILE_PICKER_TITLE_SAVE ));
1686 0 : gtk_window_set_title ( GTK_WINDOW( m_pDialog ),
1687 0 : OUStringToOString( aFilePickerTitle, RTL_TEXTENCODING_UTF8 ).getStr() );
1688 : }
1689 :
1690 0 : gtk_file_chooser_set_action( GTK_FILE_CHOOSER( m_pDialog ), eAction);
1691 0 : dialog_remove_buttons( GTK_DIALOG( m_pDialog ) );
1692 0 : gtk_dialog_add_button( GTK_DIALOG( m_pDialog ), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL );
1693 0 : for( int nTVIndex = 0; nTVIndex < BUTTON_LAST; nTVIndex++ )
1694 : {
1695 0 : if( mbButtonVisibility[nTVIndex] )
1696 : {
1697 : #ifdef GTK_STOCK_MEDIA_PLAY
1698 0 : m_pButtons[ nTVIndex ] = gtk_dialog_add_button( GTK_DIALOG( m_pDialog ), GTK_STOCK_MEDIA_PLAY, 1 );
1699 : #else
1700 : OString aPlay = OUStringToOString( getResString( PUSHBUTTON_PLAY ), RTL_TEXTENCODING_UTF8 );
1701 : m_pButtons[ nTVIndex ] = gtk_dialog_add_button( GTK_DIALOG( m_pDialog ), aPlay.getStr(), 1 );
1702 : #endif
1703 : }
1704 : }
1705 0 : gtk_dialog_add_button( GTK_DIALOG( m_pDialog ), first_button_text, GTK_RESPONSE_ACCEPT );
1706 :
1707 0 : gtk_dialog_set_default_response( GTK_DIALOG (m_pDialog), GTK_RESPONSE_ACCEPT );
1708 :
1709 : // Setup special flags
1710 0 : for( int nTVIndex = 0; nTVIndex < TOGGLE_LAST; nTVIndex++ )
1711 : {
1712 0 : if( mbToggleVisibility[nTVIndex] )
1713 0 : gtk_widget_show( m_pToggles[ nTVIndex ] );
1714 : }
1715 :
1716 0 : for( int nTVIndex = 0; nTVIndex < LIST_LAST; nTVIndex++ )
1717 : {
1718 0 : if( mbListVisibility[nTVIndex] )
1719 : {
1720 0 : gtk_widget_set_sensitive( m_pLists[ nTVIndex ], false );
1721 0 : gtk_widget_show( m_pLists[ nTVIndex ] );
1722 0 : gtk_widget_show( m_pListLabels[ nTVIndex ] );
1723 0 : gtk_widget_show( m_pAligns[ nTVIndex ] );
1724 0 : gtk_widget_show( m_pHBoxs[ nTVIndex ] );
1725 : }
1726 0 : }
1727 0 : }
1728 :
1729 0 : void SalGtkFilePicker::preview_toggled_cb( GObject *cb, SalGtkFilePicker* pobjFP )
1730 : {
1731 0 : if( pobjFP->mbToggleVisibility[PREVIEW] )
1732 0 : pobjFP->setShowState( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( cb ) ) );
1733 0 : }
1734 :
1735 : // XCancellable
1736 :
1737 0 : void SAL_CALL SalGtkFilePicker::cancel() throw( uno::RuntimeException, std::exception )
1738 : {
1739 0 : SolarMutexGuard g;
1740 :
1741 0 : OSL_ASSERT( m_pDialog != NULL );
1742 :
1743 : // TODO m_pImpl->cancel();
1744 0 : }
1745 :
1746 : // Misc
1747 :
1748 0 : void SalGtkFilePicker::SetCurFilter( const OUString& rFilter )
1749 : {
1750 : // Get all the filters already added
1751 0 : GSList *filters = gtk_file_chooser_list_filters ( GTK_FILE_CHOOSER( m_pDialog ) );
1752 0 : bool bFound = false;
1753 :
1754 0 : for( GSList *iter = filters; !bFound && iter; iter = iter->next )
1755 : {
1756 0 : GtkFileFilter* pFilter = reinterpret_cast<GtkFileFilter *>( iter->data );
1757 0 : G_CONST_RETURN gchar * filtername = gtk_file_filter_get_name( pFilter );
1758 0 : OUString sFilterName( filtername, strlen( filtername ), RTL_TEXTENCODING_UTF8 );
1759 :
1760 0 : OUString aShrunkName = shrinkFilterName( rFilter );
1761 0 : if( aShrunkName.equals( sFilterName) )
1762 : {
1763 : OSL_TRACE( "actually setting %s", filtername );
1764 0 : gtk_file_chooser_set_filter( GTK_FILE_CHOOSER( m_pDialog ), pFilter );
1765 0 : bFound = true;
1766 : }
1767 0 : }
1768 :
1769 0 : g_slist_free( filters );
1770 0 : }
1771 :
1772 : extern "C"
1773 : {
1774 : static gboolean
1775 0 : case_insensitive_filter (const GtkFileFilterInfo *filter_info, gpointer data)
1776 : {
1777 0 : gboolean bRetval = false;
1778 0 : const char *pFilter = (const char *) data;
1779 :
1780 0 : g_return_val_if_fail( data != NULL, false );
1781 0 : g_return_val_if_fail( filter_info != NULL, false );
1782 :
1783 0 : if( !filter_info->uri )
1784 0 : return false;
1785 :
1786 0 : const char *pExtn = strrchr( filter_info->uri, '.' );
1787 0 : if( !pExtn )
1788 0 : return false;
1789 0 : pExtn++;
1790 :
1791 0 : if( !g_ascii_strcasecmp( pFilter, pExtn ) )
1792 0 : bRetval = true;
1793 :
1794 : SAL_INFO( "vcl.gtk", "'" << filter_info->uri << "' match extn '" << pExtn << "' vs '" << pFilter << "' yeilds " << bRetval );
1795 :
1796 0 : return bRetval;
1797 : }
1798 : }
1799 :
1800 0 : GtkFileFilter* SalGtkFilePicker::implAddFilter( const OUString& rFilter, const OUString& rType )
1801 : {
1802 0 : GtkFileFilter *filter = gtk_file_filter_new();
1803 :
1804 0 : OUString aShrunkName = shrinkFilterName( rFilter );
1805 0 : OString aFilterName = OUStringToOString( aShrunkName, RTL_TEXTENCODING_UTF8 );
1806 0 : gtk_file_filter_set_name( filter, aFilterName.getStr() );
1807 :
1808 0 : static const OUString aStarDot( "*." );
1809 0 : OUString aTokens;
1810 :
1811 0 : bool bAllGlob = rType.equalsAscii( "*.*" ) || rType.equalsAscii( "*" );
1812 0 : if (bAllGlob)
1813 0 : gtk_file_filter_add_pattern( filter, "*" );
1814 : else
1815 : {
1816 0 : sal_Int32 nIndex = 0;
1817 0 : OUString aToken;
1818 0 : do
1819 : {
1820 0 : aToken = rType.getToken( 0, ';', nIndex );
1821 : // Assume all have the "*.<extn>" syntax
1822 0 : sal_Int32 nStarDot = aToken.lastIndexOf( aStarDot );
1823 0 : if (nStarDot >= 0)
1824 0 : aToken = aToken.copy( nStarDot + 2 );
1825 0 : if (!aToken.isEmpty())
1826 : {
1827 0 : if (!aTokens.isEmpty())
1828 0 : aTokens += ",";
1829 0 : aTokens = aTokens += aToken;
1830 : gtk_file_filter_add_custom (filter, GTK_FILE_FILTER_URI,
1831 : case_insensitive_filter,
1832 0 : g_strdup( OUStringToOString(aToken, RTL_TEXTENCODING_UTF8).getStr() ),
1833 0 : (GDestroyNotify) g_free );
1834 :
1835 : OSL_TRACE( "fustering with %s", OUStringToOString( aToken, RTL_TEXTENCODING_UTF8 ).getStr());
1836 : }
1837 : #if OSL_DEBUG_LEVEL > 0
1838 : else
1839 : {
1840 : g_warning( "Duff filter token '%s'\n",
1841 : OUStringToOString(
1842 : rType.getToken( 0, ';', nIndex ), RTL_TEXTENCODING_UTF8 ).getStr() );
1843 : }
1844 : #endif
1845 : }
1846 0 : while( nIndex >= 0 );
1847 : }
1848 :
1849 0 : gtk_file_chooser_add_filter( GTK_FILE_CHOOSER( m_pDialog ), filter );
1850 :
1851 0 : if (!bAllGlob)
1852 : {
1853 : GtkTreeIter iter;
1854 0 : gtk_list_store_append (m_pFilterStore, &iter);
1855 : gtk_list_store_set (m_pFilterStore, &iter,
1856 : 0, OUStringToOString(shrinkFilterName( rFilter, true ), RTL_TEXTENCODING_UTF8).getStr(),
1857 : 1, OUStringToOString(aTokens, RTL_TEXTENCODING_UTF8).getStr(),
1858 : 2, aFilterName.getStr(),
1859 : 3, OUStringToOString(rType, RTL_TEXTENCODING_UTF8).getStr(),
1860 0 : -1);
1861 : }
1862 0 : return filter;
1863 : }
1864 :
1865 0 : void SalGtkFilePicker::implAddFilterGroup( const OUString& /*_rFilter*/, const Sequence< StringPair >& _rFilters )
1866 : {
1867 : // Gtk+ has no filter group concept I think so ...
1868 : // implAddFilter( _rFilter, String() );
1869 0 : const StringPair* pSubFilters = _rFilters.getConstArray();
1870 0 : const StringPair* pSubFiltersEnd = pSubFilters + _rFilters.getLength();
1871 0 : for( ; pSubFilters != pSubFiltersEnd; ++pSubFilters )
1872 0 : implAddFilter( pSubFilters->First, pSubFilters->Second );
1873 0 : }
1874 :
1875 0 : void SalGtkFilePicker::SetFilters()
1876 : {
1877 0 : if (m_aInitialFilter.isEmpty())
1878 0 : m_aInitialFilter = m_aCurrentFilter;
1879 :
1880 0 : OUString sPseudoFilter;
1881 0 : if( GTK_FILE_CHOOSER_ACTION_SAVE == gtk_file_chooser_get_action( GTK_FILE_CHOOSER( m_pDialog ) ) )
1882 : {
1883 0 : std::set<OUString> aAllFormats;
1884 0 : if( m_pFilterList && !m_pFilterList->empty() )
1885 : {
1886 0 : for ( FilterList::iterator aListIter = m_pFilterList->begin();
1887 0 : aListIter != m_pFilterList->end();
1888 : ++aListIter
1889 : )
1890 : {
1891 0 : if( aListIter->hasSubFilters() )
1892 : { // it's a filter group
1893 0 : UnoFilterList aSubFilters;
1894 0 : aListIter->getSubFilters( aSubFilters );
1895 0 : const StringPair* pSubFilters = aSubFilters.getConstArray();
1896 0 : const StringPair* pSubFiltersEnd = pSubFilters + aSubFilters.getLength();
1897 0 : for( ; pSubFilters != pSubFiltersEnd; ++pSubFilters )
1898 0 : aAllFormats.insert(pSubFilters->Second);
1899 : }
1900 : else
1901 0 : aAllFormats.insert(aListIter->getFilter());
1902 : }
1903 : }
1904 0 : if (aAllFormats.size() > 1)
1905 : {
1906 0 : OUString sAllFilter;
1907 0 : std::set<OUString>::const_iterator aEnd = aAllFormats.end();
1908 0 : for (std::set<OUString>::const_iterator aIter = aAllFormats.begin(); aIter != aEnd; ++aIter)
1909 : {
1910 0 : if (!sAllFilter.isEmpty())
1911 0 : sAllFilter += OUString(';');
1912 0 : sAllFilter += *aIter;
1913 : }
1914 0 : sPseudoFilter = getResString(FILE_PICKER_ALLFORMATS);
1915 0 : m_pPseudoFilter = implAddFilter( sPseudoFilter, sAllFilter );
1916 0 : }
1917 : }
1918 :
1919 0 : if( m_pFilterList && !m_pFilterList->empty() )
1920 : {
1921 0 : for ( FilterList::iterator aListIter = m_pFilterList->begin();
1922 0 : aListIter != m_pFilterList->end();
1923 : ++aListIter
1924 : )
1925 : {
1926 0 : if( aListIter->hasSubFilters() )
1927 : { // it's a filter group
1928 :
1929 0 : UnoFilterList aSubFilters;
1930 0 : aListIter->getSubFilters( aSubFilters );
1931 :
1932 0 : implAddFilterGroup( aListIter->getTitle(), aSubFilters );
1933 : }
1934 : else
1935 : {
1936 : // it's a single filter
1937 :
1938 0 : implAddFilter( aListIter->getTitle(), aListIter->getFilter() );
1939 : }
1940 : }
1941 : }
1942 :
1943 : // We always hide the expander now and depend on the user using the glob
1944 : // list, or type a filename suffix, to select a filter by inference.
1945 0 : gtk_widget_hide(m_pFilterExpander);
1946 :
1947 : // set the default filter
1948 0 : if (!sPseudoFilter.isEmpty())
1949 0 : SetCurFilter( sPseudoFilter );
1950 0 : else if(!m_aCurrentFilter.isEmpty())
1951 0 : SetCurFilter( m_aCurrentFilter );
1952 :
1953 0 : OSL_TRACE( "end setting filters");
1954 0 : }
1955 :
1956 0 : SalGtkFilePicker::~SalGtkFilePicker()
1957 : {
1958 0 : SolarMutexGuard g;
1959 :
1960 : int i;
1961 :
1962 0 : for( i = 0; i < TOGGLE_LAST; i++ )
1963 0 : gtk_widget_destroy( m_pToggles[i] );
1964 :
1965 0 : for( i = 0; i < LIST_LAST; i++ )
1966 : {
1967 0 : gtk_widget_destroy( m_pListLabels[i] );
1968 0 : gtk_widget_destroy( m_pAligns[i] ); //m_pAligns[i] owns m_pLists[i]
1969 0 : gtk_widget_destroy( m_pHBoxs[i] );
1970 : }
1971 :
1972 0 : delete m_pFilterList;
1973 :
1974 0 : gtk_widget_destroy( m_pVBox );
1975 0 : }
1976 :
1977 : using namespace ::com::sun::star;
1978 :
1979 : uno::Reference< ui::dialogs::XFilePicker2 >
1980 0 : GtkInstance::createFilePicker( const com::sun::star::uno::Reference<
1981 : com::sun::star::uno::XComponentContext > &xMSF )
1982 : {
1983 : return uno::Reference< ui::dialogs::XFilePicker2 >(
1984 0 : new SalGtkFilePicker( xMSF ) );
1985 0 : }
1986 :
1987 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|