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