~ubuntu-branches/debian/sid/pcmanfm/sid

« back to all changes in this revision

Viewing changes to src/tab-page.c

  • Committer: Package Import Robot
  • Author(s): Andriy Grytsenko
  • Date: 2014-02-25 04:07:51 UTC
  • mfrom: (1.2.6)
  • Revision ID: package-import@ubuntu.com-20140225040751-oo835klpwl58mcy4
Tags: 1.2.0-1
* Bump Standards-Version to actual one (fixes lintian warning, see QA page).
* Adding files NEWS to pcmanfm documentation.
* Bump Standards-Version to 3.9.5.
* Updating watch file to support XZ tarball format and non-numeric versions.
* Merging upstream version 1.2.0. (Closes: #656298, #731549)
* Use single docs directory for all packages.
* Raising version of libfm required to >= 1.2.0.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
//      fm-tab-page.c
2
2
//
3
3
//      Copyright 2011 Hong Jen Yee (PCMan) <pcman.tw@gmail.com>
 
4
//      Copyright 2012-2014 Andriy Grytsenko (LStranger) <andrej@rep.kiev.ua>
4
5
//
5
6
//      This program is free software; you can redistribute it and/or modify
6
7
//      it under the terms of the GNU General Public License as published by
27
28
#include "app-config.h"
28
29
#include "main-win.h"
29
30
#include "tab-page.h"
30
 
#include "pcmanfm.h"
31
31
 
32
32
#include "gseal-gtk-compat.h"
33
33
 
 
34
#include <stdlib.h>
 
35
#include <fnmatch.h>
 
36
 
34
37
/* Additional entries for FmFileMenu popup */
 
38
/* it is also used for FmSidePane context menu popup */
35
39
static const char folder_menu_xml[]=
36
40
"<popup>"
37
41
  "<placeholder name='ph1'>"
61
65
    CHDIR,
62
66
    OPEN_DIR,
63
67
    STATUS,
 
68
    GOT_FOCUS,
64
69
    N_SIGNALS
65
70
};
66
71
 
77
82
static FmJobErrorAction on_folder_error(FmFolder* folder, GError* err, FmJobErrorSeverity severity, FmTabPage* page);
78
83
 
79
84
static void on_folder_view_sel_changed(FmFolderView* fv, gint n_sel, FmTabPage* page);
 
85
#if FM_CHECK_VERSION(1, 2, 0)
 
86
static void  on_folder_view_columns_changed(FmFolderView *fv, FmTabPage *page);
 
87
#endif
 
88
static gboolean on_folder_view_focus_in(GtkWidget *widget, GdkEvent *event, FmTabPage *page);
80
89
static char* format_status_text(FmTabPage* page);
81
90
 
82
91
#if GTK_CHECK_VERSION(3, 0, 0)
88
97
static void fm_tab_page_realize(GtkWidget *page);
89
98
static void fm_tab_page_unrealize(GtkWidget *page);
90
99
 
 
100
static GQuark popup_qdata;
 
101
 
91
102
G_DEFINE_TYPE(FmTabPage, fm_tab_page, GTK_TYPE_HPANED)
92
103
 
93
104
static void fm_tab_page_class_init(FmTabPageClass *klass)
136
147
                    NULL, NULL,
137
148
                    g_cclosure_marshal_VOID__UINT_POINTER,
138
149
                    G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_POINTER);
 
150
    /* folder view received the focus */
 
151
    signals[GOT_FOCUS] =
 
152
        g_signal_new("got-focus",
 
153
                    G_TYPE_FROM_CLASS(klass),
 
154
                    G_SIGNAL_RUN_FIRST,
 
155
                    G_STRUCT_OFFSET (FmTabPageClass, got_focus),
 
156
                    NULL, NULL,
 
157
                    g_cclosure_marshal_VOID__VOID,
 
158
                    G_TYPE_NONE, 0);
 
159
 
 
160
    popup_qdata = g_quark_from_static_string("tab-page::popup-filelist");
139
161
}
140
162
 
141
163
 
152
174
    for(i = 0; i < FM_STATUS_TEXT_NUM; ++i)
153
175
        g_free(page->status_text[i]);
154
176
 
 
177
#if FM_CHECK_VERSION(1, 0, 2)
 
178
    g_free(page->filter_pattern);
 
179
#endif
 
180
 
155
181
    G_OBJECT_CLASS(fm_tab_page_parent_class)->finalize(object);
156
182
}
157
183
 
168
194
        g_signal_handlers_disconnect_by_func(page->folder, on_folder_unmount, page);
169
195
        g_object_unref(page->folder);
170
196
        page->folder = NULL;
 
197
#if FM_CHECK_VERSION(1, 2, 0)
 
198
        if (page->want_focus)
 
199
            fm_path_unref(page->want_focus);
 
200
        page->want_focus = NULL;
 
201
#endif
171
202
    }
172
203
}
173
204
 
 
205
/* workaround on FmStandardView: it should forward focus-in events but doesn't do */
 
206
static void on_folder_view_add(GtkContainer *container, GtkWidget *child, FmTabPage *page)
 
207
{
 
208
    g_signal_connect(child, "focus-in-event",
 
209
                     G_CALLBACK(on_folder_view_focus_in), page);
 
210
}
 
211
 
 
212
static void on_folder_view_remove(GtkContainer *container, GtkWidget *child, FmTabPage *page)
 
213
{
 
214
    g_signal_handlers_disconnect_by_func(child, on_folder_view_focus_in, page);
 
215
}
 
216
 
 
217
static void _connect_focus_in(FmFolderView *folder_view, FmTabPage *page)
 
218
{
 
219
    GList *children, *l;
 
220
 
 
221
    g_signal_connect(folder_view, "focus-in-event",
 
222
                     G_CALLBACK(on_folder_view_focus_in), page);
 
223
    g_signal_connect(folder_view, "add",
 
224
                     G_CALLBACK(on_folder_view_add), page);
 
225
    g_signal_connect(folder_view, "remove",
 
226
                     G_CALLBACK(on_folder_view_remove), page);
 
227
    children = gtk_container_get_children(GTK_CONTAINER(folder_view));
 
228
    for (l = children; l; l = l->next)
 
229
        g_signal_connect(l->data, "focus-in-event",
 
230
                         G_CALLBACK(on_folder_view_focus_in), page);
 
231
    g_list_free(children);
 
232
}
 
233
 
 
234
static void _disconnect_focus_in(FmFolderView *folder_view, FmTabPage *page)
 
235
{
 
236
    GList *children, *l;
 
237
 
 
238
    g_signal_handlers_disconnect_by_func(folder_view, on_folder_view_focus_in, page);
 
239
    g_signal_handlers_disconnect_by_func(folder_view, on_folder_view_add, page);
 
240
    g_signal_handlers_disconnect_by_func(folder_view, on_folder_view_remove, page);
 
241
    children = gtk_container_get_children(GTK_CONTAINER(folder_view));
 
242
    for (l = children; l; l = l->next)
 
243
        g_signal_handlers_disconnect_by_func(l->data, on_folder_view_focus_in, page);
 
244
    g_list_free(children);
 
245
}
 
246
 
 
247
#if FM_CHECK_VERSION(1, 2, 0)
 
248
static void on_home_path_changed(FmAppConfig *cfg, FmSidePane *sp)
 
249
{
 
250
    if (cfg->home_path && cfg->home_path[0])
 
251
        fm_side_pane_set_home_dir(sp, cfg->home_path);
 
252
    else
 
253
        fm_side_pane_set_home_dir(sp, fm_get_home_dir());
 
254
}
 
255
#endif
 
256
 
174
257
#if GTK_CHECK_VERSION(3, 0, 0)
175
258
void fm_tab_page_destroy(GtkWidget *object)
176
259
#else
178
261
#endif
179
262
{
180
263
    FmTabPage* page = FM_TAB_PAGE(object);
 
264
 
181
265
    g_debug("fm_tab_page_destroy, folder: %s",
182
266
            page->folder ? fm_path_get_basename(fm_folder_get_path(page->folder)) : "(none)");
183
267
    free_folder(page);
188
272
    }
189
273
    if(page->folder_view)
190
274
    {
 
275
        /* tab page may be inactive now and there is a chance it does not contain
 
276
           own view therefore we have to destroy own folder view widget manually */
 
277
        GtkWidget *fv = GTK_WIDGET(page->folder_view);
 
278
        GtkWidget *parent = gtk_widget_get_parent(fv);
 
279
        GList *panes, *l;
 
280
 
 
281
        if (parent)
 
282
        {
 
283
            panes = gtk_container_get_children(GTK_CONTAINER(page->views));
 
284
            for (l = panes; l; l = l->next)
 
285
                if ((GtkWidget*)l->data == fv)
 
286
                    break;
 
287
            if (l == NULL)
 
288
                gtk_container_remove(GTK_CONTAINER(parent), fv);
 
289
            g_list_free(panes);
 
290
        }
 
291
 
191
292
        g_signal_handlers_disconnect_by_func(page->folder_view, on_folder_view_sel_changed, page);
 
293
#if FM_CHECK_VERSION(1, 2, 0)
 
294
        g_signal_handlers_disconnect_by_func(page->folder_view, on_folder_view_columns_changed, page);
 
295
#endif
 
296
#if FM_CHECK_VERSION(1, 2, 0)
 
297
        g_signal_handlers_disconnect_by_func(app_config, on_home_path_changed, page->side_pane);
 
298
#endif
 
299
        _disconnect_focus_in(page->folder_view, page);
 
300
        g_object_unref(page->folder_view);
192
301
        page->folder_view = NULL;
193
302
    }
 
303
#if FM_CHECK_VERSION(1, 0, 2)
 
304
    g_strfreev(page->columns);
 
305
    page->columns = NULL;
 
306
#endif
 
307
    if(page->update_scroll_id)
 
308
    {
 
309
        g_source_remove(page->update_scroll_id);
 
310
        page->update_scroll_id = 0;
 
311
    }
 
312
#if FM_CHECK_VERSION(1, 2, 0)
 
313
    fm_side_pane_set_popup_updater(page->side_pane, NULL, NULL);
 
314
#endif
 
315
    if (page->dd)
 
316
    {
 
317
        g_object_unref(page->dd);
 
318
        page->dd = NULL;
 
319
    }
194
320
 
195
321
#if GTK_CHECK_VERSION(3, 0, 0)
196
322
    if(GTK_WIDGET_CLASS(fm_tab_page_parent_class)->destroy)
214
340
static void on_folder_view_sel_changed(FmFolderView* fv, gint n_sel, FmTabPage* page)
215
341
{
216
342
    char* msg = page->status_text[FM_STATUS_TEXT_SELECTED_FILES];
 
343
    GString *str;
217
344
    g_free(msg);
218
345
 
219
346
    if(n_sel > 0)
220
347
    {
 
348
        str = g_string_sized_new(64);
221
349
        /* FIXME: display total size of all selected files. */
222
350
        if(n_sel == 1) /* only one file is selected */
223
351
        {
224
352
            FmFileInfoList* files = fm_folder_view_dup_selected_files(fv);
225
353
            FmFileInfo* fi = fm_file_info_list_peek_head(files);
226
354
            const char* size_str = fm_file_info_get_disp_size(fi);
 
355
#if FM_CHECK_VERSION(1, 2, 0)
 
356
            GList *l;
 
357
#endif
227
358
            if(size_str)
228
359
            {
229
 
                msg = g_strdup_printf("\"%s\" (%s) %s",
 
360
                g_string_printf(str, "\"%s\" (%s) %s",
230
361
                            fm_file_info_get_disp_name(fi),
231
362
                            size_str ? size_str : "",
232
363
                            fm_file_info_get_desc(fi));
233
364
            }
234
365
            else
235
366
            {
236
 
                msg = g_strdup_printf("\"%s\" %s",
 
367
                g_string_printf(str, "\"%s\" %s",
237
368
                            fm_file_info_get_disp_name(fi),
238
369
                            fm_file_info_get_desc(fi));
239
370
            }
 
371
#if FM_CHECK_VERSION(1, 2, 0)
 
372
            /* ---- statusbar plugins support ---- */
 
373
            CHECK_MODULES();
 
374
            for (l = _tab_page_modules; l; l = l->next)
 
375
            {
 
376
                FmTabPageStatusInit *module = l->data;
 
377
                char *message = module->sel_message(files, n_sel);
 
378
                if (message && message[0])
 
379
                {
 
380
                    g_string_append_c(str, ' ');
 
381
                    g_string_append(str, message);
 
382
                }
 
383
                g_free(message);
 
384
            }
 
385
#endif
240
386
            fm_file_info_list_unref(files);
241
387
        }
242
388
        else
243
389
        {
244
 
            msg = g_strdup_printf(ngettext("%d item selected", "%d items selected", n_sel), n_sel);
 
390
            FmFileInfoList* files;
 
391
            goffset sum;
 
392
            GList *l;
 
393
            char size_str[128];
 
394
 
 
395
            g_string_printf(str, ngettext("%d item selected", "%d items selected", n_sel), n_sel);
 
396
            /* don't count if too many files are selected, that isn't lightweight */
 
397
            if (n_sel < 1000)
 
398
            {
 
399
                sum = 0;
 
400
                files = fm_folder_view_dup_selected_files(fv);
 
401
                for (l = fm_file_info_list_peek_head_link(files); l; l = l->next)
 
402
                {
 
403
                    if (fm_file_info_is_dir(l->data))
 
404
                    {
 
405
                        /* if we got a directory then we cannot tell it's size
 
406
                           unless we do deep count but we cannot afford it */
 
407
                        sum = -1;
 
408
                        break;
 
409
                    }
 
410
                    sum += fm_file_info_get_size(l->data);
 
411
                }
 
412
                if (sum >= 0)
 
413
                {
 
414
                    fm_file_size_to_str(size_str, sizeof(size_str), sum,
 
415
                                        fm_config->si_unit);
 
416
                    g_string_append_printf(str, " (%s)", size_str);
 
417
                }
 
418
#if FM_CHECK_VERSION(1, 2, 0)
 
419
                /* ---- statusbar plugins support ---- */
 
420
                CHECK_MODULES();
 
421
                for (l = _tab_page_modules; l; l = l->next)
 
422
                {
 
423
                    FmTabPageStatusInit *module = l->data;
 
424
                    char *message = module->sel_message(files, n_sel);
 
425
                    if (message && message[0])
 
426
                    {
 
427
                        g_string_append_c(str, ' ');
 
428
                        g_string_append(str, message);
 
429
                    }
 
430
                    g_free(message);
 
431
                }
 
432
#endif
 
433
                fm_file_info_list_unref(files);
 
434
            }
 
435
            /* FIXME: can we show some more info on selection?
 
436
               that isn't lightweight if a lot of files are selected */
245
437
        }
 
438
        msg = g_string_free(str, FALSE);
246
439
    }
247
440
    else
248
441
        msg = NULL;
251
444
                  (guint)FM_STATUS_TEXT_SELECTED_FILES, msg);
252
445
}
253
446
 
 
447
#if FM_CHECK_VERSION(1, 2, 0)
 
448
static void  on_folder_view_columns_changed(FmFolderView *fv, FmTabPage *page)
 
449
{
 
450
    GSList *columns = fm_folder_view_get_columns(fv), *l;
 
451
    char **cols;
 
452
    guint i;
 
453
 
 
454
    if (columns == NULL)
 
455
        return;
 
456
    i = g_slist_length(columns);
 
457
    cols = g_new(char *, i+1);
 
458
    for (i = 0, l = columns; l; i++, l = l->next)
 
459
    {
 
460
        FmFolderViewColumnInfo *info = l->data;
 
461
 
 
462
        if (info->width > 0)
 
463
            cols[i] = g_strdup_printf("%s:%d",
 
464
                                      fm_folder_model_col_get_name(info->col_id),
 
465
                                      info->width);
 
466
        else
 
467
            cols[i] = g_strdup(fm_folder_model_col_get_name(info->col_id));
 
468
    }
 
469
    g_slist_free(columns);
 
470
    cols[i] = NULL; /* terminate the list */
 
471
    if (page->own_config)
 
472
    {
 
473
        g_strfreev(page->columns);
 
474
        page->columns = cols;
 
475
        fm_app_config_save_config_for_path(fm_folder_view_get_cwd(fv),
 
476
                                           page->sort_type, page->sort_by, -1,
 
477
                                           page->show_hidden, cols);
 
478
    }
 
479
    else
 
480
    {
 
481
        g_strfreev(app_config->columns);
 
482
        app_config->columns = cols;
 
483
        pcmanfm_save_config(FALSE);
 
484
    }
 
485
}
 
486
#endif
 
487
 
 
488
static gboolean on_folder_view_focus_in(GtkWidget *widget, GdkEvent *event, FmTabPage *page)
 
489
{
 
490
    g_signal_emit(page, signals[GOT_FOCUS], 0);
 
491
    return FALSE;
 
492
}
 
493
 
254
494
static FmJobErrorAction on_folder_error(FmFolder* folder, GError* err, FmJobErrorSeverity severity, FmTabPage* page)
255
495
{
256
496
    GtkWindow* win = GTK_WINDOW(GET_MAIN_WIN(page));
304
544
        fm_unset_busy_cursor(GTK_WIDGET(page));
305
545
}
306
546
 
 
547
#if FM_CHECK_VERSION(1, 0, 2)
 
548
static gboolean fm_tab_page_path_filter(FmFileInfo *file, gpointer user_data)
 
549
{
 
550
    FmTabPage *page;
 
551
    const char *disp_name;
 
552
    char *casefold, *key;
 
553
    gboolean result;
 
554
 
 
555
    g_return_val_if_fail(FM_IS_TAB_PAGE(user_data), FALSE);
 
556
    page = (FmTabPage*)user_data;
 
557
    if (page->filter_pattern == NULL)
 
558
        return TRUE;
 
559
    disp_name = fm_file_info_get_disp_name(file);
 
560
    casefold = g_utf8_casefold(disp_name, -1);
 
561
    key = g_utf8_normalize(casefold, -1, G_NORMALIZE_ALL);
 
562
    g_free(casefold);
 
563
    result = (fnmatch(page->filter_pattern, key, 0) == 0);
 
564
    g_free(key);
 
565
    return result;
 
566
}
 
567
#endif
 
568
 
307
569
static void on_folder_start_loading(FmFolder* folder, FmTabPage* page)
308
570
{
309
571
    FmFolderView* fv = page->folder_view;
317
579
        /* create a model for the folder and set it to the view
318
580
           it is delayed for non-incremental folders since adding rows into
319
581
           model is much faster without handlers connected to its signals */
320
 
        FmFolderModel* model = fm_folder_model_new(folder, FALSE);
 
582
        FmFolderModel* model = fm_folder_model_new(folder, page->show_hidden);
 
583
        if (page->filter_pattern)
 
584
        {
 
585
            fm_folder_model_add_filter(model, fm_tab_page_path_filter, page);
 
586
            fm_folder_model_apply_filters(model);
 
587
        }
321
588
        fm_folder_view_set_model(fv, model);
322
 
        fm_folder_model_set_sort(model, app_config->sort_by,
323
 
                                 (app_config->sort_type == GTK_SORT_ASCENDING) ?
324
 
                                        FM_SORT_ASCENDING : FM_SORT_DESCENDING);
 
589
        fm_folder_model_set_sort(model, page->sort_by, page->sort_type);
325
590
        g_object_unref(model);
326
591
    }
327
592
    else
329
594
        fm_folder_view_set_model(fv, NULL);
330
595
}
331
596
 
 
597
static gboolean update_scroll(gpointer data)
 
598
{
 
599
    FmTabPage* page = data;
 
600
    GtkScrolledWindow* scroll = GTK_SCROLLED_WINDOW(page->folder_view);
 
601
#if !FM_CHECK_VERSION(1, 0, 2)
 
602
    const FmNavHistoryItem* item;
 
603
 
 
604
    item = fm_nav_history_get_cur(page->nav_history);
 
605
    /* scroll to recorded position */
 
606
    gtk_adjustment_set_value(gtk_scrolled_window_get_vadjustment(scroll), item->scroll_pos);
 
607
#else
 
608
    gtk_adjustment_set_value(gtk_scrolled_window_get_vadjustment(scroll),
 
609
                             fm_nav_history_get_scroll_pos(page->nav_history));
 
610
#endif
 
611
#if FM_CHECK_VERSION(1, 2, 0)
 
612
    if (page->want_focus)
 
613
    {
 
614
        fm_folder_view_select_file_path(page->folder_view, page->want_focus);
 
615
        fm_folder_view_scroll_to_path(page->folder_view, page->want_focus, TRUE);
 
616
        fm_path_unref(page->want_focus);
 
617
        page->want_focus = NULL;
 
618
    }
 
619
#endif
 
620
    page->update_scroll_id = 0;
 
621
    return FALSE;
 
622
}
 
623
 
332
624
static void on_folder_finish_loading(FmFolder* folder, FmTabPage* page)
333
625
{
334
626
    FmFolderView* fv = page->folder_view;
335
 
    const FmNavHistoryItem* item;
336
 
    GtkScrolledWindow* scroll = GTK_SCROLLED_WINDOW(fv);
337
627
 
338
628
    /* Note: most of the time, we delay the creation of the 
339
629
     * folder model and do it after the whole folder is loaded.
345
635
    if(fm_folder_view_get_model(fv) == NULL)
346
636
    {
347
637
        /* create a model for the folder and set it to the view */
348
 
        FmFolderModel* model = fm_folder_model_new(folder, app_config->show_hidden);
 
638
        FmFolderModel* model = fm_folder_model_new(folder, page->show_hidden);
349
639
        fm_folder_view_set_model(fv, model);
350
640
#if FM_CHECK_VERSION(1, 0, 2)
 
641
        if (page->filter_pattern)
 
642
        {
 
643
            fm_folder_model_add_filter(model, fm_tab_page_path_filter, page);
 
644
            fm_folder_model_apply_filters(model);
 
645
        }
351
646
        /* since 1.0.2 sorting should be applied on model instead of view */
352
 
        fm_folder_model_set_sort(model, app_config->sort_by,
353
 
                                 (app_config->sort_type == GTK_SORT_ASCENDING) ?
354
 
                                        FM_SORT_ASCENDING : FM_SORT_DESCENDING);
 
647
        fm_folder_model_set_sort(model, page->sort_by, page->sort_type);
355
648
#endif
356
649
        g_object_unref(model);
357
650
    }
358
651
    fm_folder_query_filesystem_info(folder); /* FIXME: is this needed? */
359
652
 
360
653
    // fm_path_entry_set_path(entry, path);
361
 
    /* scroll to recorded position */
362
 
    item = fm_nav_history_get_cur(page->nav_history);
363
 
    gtk_adjustment_set_value(gtk_scrolled_window_get_vadjustment(scroll), item->scroll_pos);
 
654
    /* delaying scrolling since drawing folder view is delayed */
 
655
    if(!page->update_scroll_id)
 
656
        page->update_scroll_id = gdk_threads_add_timeout(20, update_scroll, page);
364
657
 
365
658
    /* update status bar */
366
659
    /* update status text */
376
669
 
377
670
static void on_folder_unmount(FmFolder* folder, FmTabPage* page)
378
671
{
379
 
    gtk_widget_destroy(GTK_WIDGET(page));
 
672
    if (app_config->close_on_unmount)
 
673
        gtk_widget_destroy(GTK_WIDGET(page));
 
674
    else
 
675
#if FM_CHECK_VERSION(1, 2, 0)
 
676
    if (app_config->home_path && app_config->home_path[0])
 
677
    {
 
678
        FmPath *path = fm_path_new_for_str(app_config->home_path);
 
679
 
 
680
        fm_tab_page_chdir(page, path);
 
681
        fm_path_unref(path);
 
682
    }
 
683
    else
 
684
#endif
 
685
        fm_tab_page_chdir(page, fm_path_get_home());
380
686
}
381
687
 
382
688
static void on_folder_removed(FmFolder* folder, FmTabPage* page)
383
689
{
384
 
    gtk_widget_destroy(GTK_WIDGET(page));
 
690
    if (app_config->close_on_unmount)
 
691
        gtk_widget_destroy(GTK_WIDGET(page));
 
692
    else
 
693
#if FM_CHECK_VERSION(1, 2, 0)
 
694
    if (app_config->home_path && app_config->home_path[0])
 
695
    {
 
696
        FmPath *path = fm_path_new_for_str(app_config->home_path);
 
697
 
 
698
        fm_tab_page_chdir(page, path);
 
699
        fm_path_unref(path);
 
700
    }
 
701
    else
 
702
#endif
 
703
        fm_tab_page_chdir(page, fm_path_get_home());
385
704
}
386
705
 
387
706
static void on_folder_fs_info(FmFolder* folder, FmTabPage* page)
429
748
 
430
749
static void on_open_in_new_tab(GtkAction* act, FmMainWin* win)
431
750
{
432
 
    FmPathList* sels = fm_folder_view_dup_selected_file_paths(win->folder_view);
 
751
    GObject* act_grp;
 
752
    FmFileInfoList* sels;
433
753
    GList* l;
434
 
    for( l = fm_path_list_peek_head_link(sels); l; l=l->next )
 
754
 
 
755
    g_object_get(act, "action-group", &act_grp, NULL);
 
756
    sels = g_object_get_qdata(act_grp, popup_qdata);
 
757
    g_object_unref(act_grp);
 
758
    for( l = fm_file_info_list_peek_head_link(sels); l; l=l->next )
435
759
    {
436
 
        FmPath* path = (FmPath*)l->data;
437
 
        fm_main_win_add_tab(win, path);
 
760
        FmFileInfo* fi = (FmFileInfo*)l->data;
 
761
        fm_main_win_add_tab(win, fm_file_info_get_path(fi));
438
762
    }
439
 
    fm_path_list_unref(sels);
440
763
}
441
764
 
442
765
static void on_open_in_new_win(GtkAction* act, FmMainWin* win)
443
766
{
444
 
    FmPathList* sels = fm_folder_view_dup_selected_file_paths(win->folder_view);
 
767
    GObject* act_grp;
 
768
    FmFileInfoList* sels;
445
769
    GList* l;
446
 
    for( l = fm_path_list_peek_head_link(sels); l; l=l->next )
 
770
 
 
771
    g_object_get(act, "action-group", &act_grp, NULL);
 
772
    sels = g_object_get_qdata(act_grp, popup_qdata);
 
773
    g_object_unref(act_grp);
 
774
    for( l = fm_file_info_list_peek_head_link(sels); l; l=l->next )
447
775
    {
448
 
        FmPath* path = (FmPath*)l->data;
449
 
        fm_main_win_add_win(win, path);
 
776
        FmFileInfo* fi = (FmFileInfo*)l->data;
 
777
        fm_main_win_add_win(win, fm_file_info_get_path(fi));
450
778
    }
451
 
    fm_path_list_unref(sels);
452
779
}
453
780
 
454
781
static void on_open_folder_in_terminal(GtkAction* act, FmMainWin* win)
455
782
{
456
 
    FmFileInfoList* files = fm_folder_view_dup_selected_files(win->folder_view);
 
783
    GObject* act_grp;
 
784
    FmFileInfoList* files;
457
785
    GList* l;
 
786
 
 
787
    g_object_get(act, "action-group", &act_grp, NULL);
 
788
    files = g_object_get_qdata(act_grp, popup_qdata);
 
789
    g_object_unref(act_grp);
458
790
    for(l=fm_file_info_list_peek_head_link(files);l;l=l->next)
459
791
    {
460
792
        FmFileInfo* fi = (FmFileInfo*)l->data;
461
 
        if(fm_file_info_is_dir(fi) /*&& !fm_file_info_is_virtual(fi)*/)
462
 
            pcmanfm_open_folder_in_terminal(GTK_WINDOW(win), fm_file_info_get_path(fi));
 
793
        pcmanfm_open_folder_in_terminal(GTK_WINDOW(win), fm_file_info_get_path(fi));
463
794
    }
464
 
    fm_file_info_list_unref(files);
465
795
}
466
796
 
467
797
/* folder view popups */
470
800
                               FmFileInfoList* files)
471
801
{
472
802
    GList* l;
 
803
    gboolean all_native = TRUE;
473
804
 
474
805
    for(l = fm_file_info_list_peek_head_link(files); l; l = l->next)
475
806
        if(!fm_file_info_is_dir(l->data))
476
807
            return; /* actions are valid only if all selected are directories */
 
808
        else if (!fm_file_info_is_native(l->data))
 
809
            all_native = FALSE;
 
810
    g_object_set_qdata_full(G_OBJECT(act_grp), popup_qdata,
 
811
                            fm_file_info_list_ref(files),
 
812
                            (GDestroyNotify)fm_file_info_list_unref);
477
813
    gtk_action_group_set_translation_domain(act_grp, NULL);
478
814
    gtk_action_group_add_actions(act_grp, folder_menu_actions,
479
815
                                 G_N_ELEMENTS(folder_menu_actions), win);
480
816
    gtk_ui_manager_add_ui_from_string(ui, folder_menu_xml, -1, NULL);
 
817
    if (!all_native)
 
818
        gtk_action_set_visible(gtk_action_group_get_action(act_grp, "Term"), FALSE);
481
819
}
482
820
 
483
821
static gboolean open_folder_func(GAppLaunchContext* ctx, GList* folder_infos, gpointer user_data, GError** err)
495
833
    return TRUE;
496
834
}
497
835
 
 
836
#if FM_CHECK_VERSION(1, 2, 0)
 
837
void _update_sidepane_popup(FmSidePane* sp, GtkUIManager* ui,
 
838
                            GtkActionGroup* act_grp,
 
839
                            FmFileInfo* file, gpointer user_data)
 
840
{
 
841
    FmMainWin *win = GET_MAIN_WIN(user_data); /* user_data is FmTabPage */
 
842
    FmFileInfoList* files;
 
843
 
 
844
    /* bookmark may contain not a directory */
 
845
    if (G_UNLIKELY(!file || !fm_file_info_is_dir(file)))
 
846
        return;
 
847
    /* well, it should be FmMainWin but let safeguard it */
 
848
    if (G_UNLIKELY(!IS_FM_MAIN_WIN(win)))
 
849
        return;
 
850
    files = fm_file_info_list_new();
 
851
    fm_file_info_list_push_tail(files, file);
 
852
    g_object_set_qdata_full(G_OBJECT(act_grp), popup_qdata, files,
 
853
                            (GDestroyNotify)fm_file_info_list_unref);
 
854
    gtk_action_group_set_translation_domain(act_grp, NULL);
 
855
    gtk_action_group_add_actions(act_grp, folder_menu_actions,
 
856
                                 G_N_ELEMENTS(folder_menu_actions), win);
 
857
    /* we use the same XML for simplicity */
 
858
    gtk_ui_manager_add_ui_from_string(ui, folder_menu_xml, -1, NULL);
 
859
    if (!fm_file_info_is_native(file))
 
860
        gtk_action_set_visible(gtk_action_group_get_action(act_grp, "Term"), FALSE);
 
861
}
 
862
#endif
 
863
 
 
864
static gboolean on_drag_motion(FmTabLabel *label, GdkDragContext *drag_context,
 
865
                               gint x, gint y, guint time, FmTabPage *page)
 
866
{
 
867
    GdkAtom target;
 
868
    GdkDragAction action = 0;
 
869
    FmFileInfo *file_info = NULL;
 
870
 
 
871
    /* if change_tab_on_drop is set then we should ignore it and drop file
 
872
       using classic behavior - drop after it unfolded, so not drop on label */
 
873
    if (!app_config->change_tab_on_drop && page->folder_view)
 
874
        file_info = fm_folder_view_get_cwd_info(page->folder_view);
 
875
    fm_dnd_dest_set_dest_file(page->dd, file_info);
 
876
    if (file_info == NULL)
 
877
        return FALSE; /* not in drop zone */
 
878
    target = fm_dnd_dest_find_target(page->dd, drag_context);
 
879
    if (target != GDK_NONE && fm_dnd_dest_is_target_supported(page->dd, target))
 
880
        action = fm_dnd_dest_get_default_action(page->dd, drag_context, target);
 
881
    if (action == 0)
 
882
        return FALSE; /* cannot drop on that destination */
 
883
    gdk_drag_status(drag_context, action, time);
 
884
    return TRUE;
 
885
}
 
886
 
498
887
static void fm_tab_page_init(FmTabPage *page)
499
888
{
500
889
    GtkPaned* paned = GTK_PANED(page);
501
890
    FmTabLabel* tab_label;
502
891
    FmFolderView* folder_view;
503
892
    GList* focus_chain = NULL;
 
893
    AtkObject *atk_widget, *atk_label;
 
894
    AtkRelation *relation;
504
895
    FmSidePaneMode mode = app_config->side_pane_mode;
505
896
 
506
897
    page->side_pane = fm_side_pane_new();
507
898
    fm_side_pane_set_mode(page->side_pane, (mode & FM_SP_MODE_MASK));
 
899
#if FM_CHECK_VERSION(1, 2, 0)
 
900
    fm_side_pane_set_popup_updater(page->side_pane, _update_sidepane_popup, page);
 
901
    if (app_config->home_path && app_config->home_path[0])
 
902
        fm_side_pane_set_home_dir(page->side_pane, app_config->home_path);
 
903
    g_signal_connect(app_config, "changed::home_path",
 
904
                     G_CALLBACK(on_home_path_changed), page->side_pane);
 
905
#endif
508
906
    /* TODO: add a close button to side pane */
509
907
    gtk_paned_add1(paned, GTK_WIDGET(page->side_pane));
510
908
    focus_chain = g_list_prepend(focus_chain, page->side_pane);
511
909
 
 
910
    /* setup initial view mode for the tab from configuration */
 
911
    page->view_mode = app_config->view_mode;
 
912
 
512
913
    /* handlers below will be used when FmMainWin detects new page added */
513
914
    folder_view = (FmFolderView*)fm_standard_view_new(app_config->view_mode,
514
915
                                                      update_files_popup,
515
916
                                                      open_folder_func);
516
 
    page->folder_view = folder_view;
517
 
#if !FM_CHECK_VERSION(1, 0, 2)
518
 
    /* since 1.0.2 sorting should be applied on model instead */
519
 
    fm_folder_view_sort(folder_view, app_config->sort_type, app_config->sort_by);
520
 
#endif
 
917
    /* FIXME: it is inefficient to set view mode to default one then change
 
918
       it per-folder but it will be default in most cases but might it be
 
919
       even more inefficient to add an object property for the mode and set
 
920
       it in fm_tab_page_init() from the property? let make it later */
 
921
    page->folder_view = g_object_ref_sink(folder_view);
521
922
    fm_folder_view_set_selection_mode(folder_view, GTK_SELECTION_MULTIPLE);
522
923
    page->nav_history = fm_nav_history_new();
523
 
    gtk_paned_add2(paned, GTK_WIDGET(page->folder_view));
524
 
    focus_chain = g_list_prepend(focus_chain, page->folder_view);
 
924
    page->views = GTK_BOX(gtk_hbox_new(TRUE, 4));
 
925
    gtk_box_pack_start(page->views, GTK_WIDGET(folder_view), TRUE, TRUE, 0);
 
926
    gtk_paned_add2(paned, GTK_WIDGET(page->views));
 
927
    focus_chain = g_list_prepend(focus_chain, page->views);
525
928
 
526
929
    /* We need this to change tab order to focus folder view before left pane. */
527
930
    gtk_container_set_focus_chain(GTK_CONTAINER(page), focus_chain);
539
942
#endif
540
943
    page->tab_label = tab_label;
541
944
 
542
 
    g_signal_connect(page->folder_view, "sel-changed",
 
945
    atk_widget = gtk_widget_get_accessible(GTK_WIDGET(folder_view));
 
946
    atk_label = gtk_widget_get_accessible(GTK_WIDGET(tab_label));
 
947
    relation = atk_relation_new(&atk_widget, 1, ATK_RELATION_LABEL_FOR);
 
948
    atk_relation_set_add(atk_object_ref_relation_set(atk_label), relation);
 
949
    g_object_unref(relation);
 
950
 
 
951
    g_signal_connect(folder_view, "sel-changed",
543
952
                     G_CALLBACK(on_folder_view_sel_changed), page);
 
953
#if FM_CHECK_VERSION(1, 2, 0)
 
954
    g_signal_connect(folder_view, "columns-changed",
 
955
                     G_CALLBACK(on_folder_view_columns_changed), page);
 
956
#endif
 
957
    _connect_focus_in(folder_view, page);
544
958
    /*
545
959
    g_signal_connect(page->folder_view, "chdir",
546
960
                     G_CALLBACK(on_folder_view_chdir), page);
550
964
                     G_CALLBACK(on_folder_view_error), page);
551
965
    */
552
966
 
 
967
    /* setup D&D on the tab label */
 
968
    page->dd = fm_dnd_dest_new_with_handlers(GTK_WIDGET(tab_label));
 
969
    g_signal_connect(tab_label, "drag-motion", G_CALLBACK(on_drag_motion), page);
 
970
 
553
971
    /* the folder view is already loded, call the "loaded" callback ourself. */
554
972
    //if(fm_folder_view_is_loaded(folder_view))
555
973
    //    on_folder_view_loaded(folder_view, fm_folder_view_get_cwd(folder_view), page);
560
978
{
561
979
    FmTabPage* page = (FmTabPage*)g_object_new(FM_TYPE_TAB_PAGE, NULL);
562
980
 
563
 
    fm_folder_view_set_show_hidden(page->folder_view, app_config->show_hidden);
564
981
    fm_tab_page_chdir(page, path);
565
982
    return page;
566
983
}
568
985
static void fm_tab_page_chdir_without_history(FmTabPage* page, FmPath* path)
569
986
{
570
987
    char* disp_name = fm_path_display_basename(path);
 
988
    char *disp_path;
 
989
    FmStandardViewMode view_mode;
 
990
    gboolean show_hidden;
 
991
    char **columns; /* unused with libfm < 1.0.2 */
 
992
#if FM_CHECK_VERSION(1, 2, 0)
 
993
    FmPath *prev_path = NULL;
 
994
#endif
 
995
 
 
996
#if FM_CHECK_VERSION(1, 0, 2)
 
997
    if (page->filter_pattern && page->filter_pattern[0])
 
998
    {
 
999
        /* include pattern into page title */
 
1000
        char *text = g_strdup_printf("%s [%s]", disp_name, page->filter_pattern);
 
1001
        g_free(disp_name);
 
1002
        disp_name = text;
 
1003
    }
 
1004
#endif
571
1005
    fm_tab_label_set_text(page->tab_label, disp_name);
572
1006
    g_free(disp_name);
573
1007
 
574
 
    char * disp_path = fm_path_display_name(path, FALSE);
 
1008
#if FM_CHECK_VERSION(1, 2, 0)
 
1009
    if (app_config->focus_previous && page->folder)
 
1010
    {
 
1011
        prev_path = fm_folder_get_path(page->folder);
 
1012
        if (fm_path_equal(fm_path_get_parent(prev_path), path))
 
1013
            fm_path_ref(prev_path);
 
1014
        else
 
1015
            prev_path = NULL;
 
1016
    }
 
1017
#endif
 
1018
 
 
1019
    disp_path = fm_path_display_name(path, FALSE);
575
1020
    fm_tab_label_set_tooltip_text(FM_TAB_LABEL(page->tab_label), disp_path);
576
1021
    g_free(disp_path);
577
1022
 
587
1032
    g_signal_connect(page->folder, "unmount", G_CALLBACK(on_folder_unmount), page);
588
1033
    g_signal_connect(page->folder, "content-changed", G_CALLBACK(on_folder_content_changed), page);
589
1034
 
 
1035
#if FM_CHECK_VERSION(1, 2, 0)
 
1036
    page->want_focus = prev_path;
 
1037
#endif
 
1038
 
 
1039
    /* get sort and view modes for new path */
 
1040
    page->own_config = fm_app_config_get_config_for_path(path, &page->sort_type,
 
1041
                                                         &page->sort_by,
 
1042
                                                         &view_mode,
 
1043
                                                         &show_hidden, &columns);
 
1044
    if (!page->own_config)
 
1045
        /* bug #3615242: view mode is reset to default when changing directory */
 
1046
        view_mode = page->view_mode;
 
1047
    page->show_hidden = show_hidden;
 
1048
    fm_folder_view_set_show_hidden(page->folder_view, show_hidden);
 
1049
#if FM_CHECK_VERSION(1, 2, 0)
 
1050
    fm_side_pane_set_show_hidden(page->side_pane, show_hidden);
 
1051
#endif
 
1052
 
590
1053
    if(fm_folder_is_loaded(page->folder))
591
1054
    {
592
1055
        on_folder_start_loading(page->folder, page);
596
1059
    else
597
1060
        on_folder_start_loading(page->folder, page);
598
1061
 
 
1062
    /* change view and sort modes according to new path */
 
1063
    fm_standard_view_set_mode(FM_STANDARD_VIEW(page->folder_view), view_mode);
 
1064
#if FM_CHECK_VERSION(1, 0, 2)
 
1065
    /* update columns from config */
 
1066
    if (columns)
 
1067
    {
 
1068
        guint i, n = g_strv_length(columns);
 
1069
        FmFolderViewColumnInfo *infos = g_new(FmFolderViewColumnInfo, n);
 
1070
        GSList *infos_list = NULL;
 
1071
 
 
1072
        for (i = 0; i < n; i++)
 
1073
        {
 
1074
            char *name = g_strdup(columns[i]), *delim;
 
1075
 
 
1076
#if FM_CHECK_VERSION(1, 2, 0)
 
1077
            infos[i].width = 0;
 
1078
#endif
 
1079
            delim = strchr(name, ':');
 
1080
            if (delim)
 
1081
            {
 
1082
                *delim++ = '\0';
 
1083
#if FM_CHECK_VERSION(1, 2, 0)
 
1084
                infos[i].width = atoi(delim);
 
1085
#endif
 
1086
            }
 
1087
            infos[i].col_id = fm_folder_model_get_col_by_name(name);
 
1088
            g_free(name);
 
1089
            infos_list = g_slist_append(infos_list, &infos[i]);
 
1090
        }
 
1091
#if FM_CHECK_VERSION(1, 2, 0)
 
1092
        g_signal_handlers_block_by_func(page->folder_view,
 
1093
                                        on_folder_view_columns_changed, page);
 
1094
#endif
 
1095
        fm_folder_view_set_columns(page->folder_view, infos_list);
 
1096
#if FM_CHECK_VERSION(1, 2, 0)
 
1097
        g_signal_handlers_unblock_by_func(page->folder_view,
 
1098
                                          on_folder_view_columns_changed, page);
 
1099
#endif
 
1100
        g_slist_free(infos_list);
 
1101
        g_free(infos);
 
1102
        if (page->own_config)
 
1103
            page->columns = g_strdupv(columns);
 
1104
    }
 
1105
#else
 
1106
    /* since 1.0.2 sorting should be applied on model instead */
 
1107
    fm_folder_view_sort(page->folder_view, page->sort_type, page->sort_by);
 
1108
#endif
 
1109
 
599
1110
    fm_side_pane_chdir(page->side_pane, path);
600
1111
 
601
1112
    /* tell the world that our current working directory is changed */
616
1127
void fm_tab_page_set_show_hidden(FmTabPage* page, gboolean show_hidden)
617
1128
{
618
1129
    fm_folder_view_set_show_hidden(page->folder_view, show_hidden);
 
1130
#if FM_CHECK_VERSION(1, 2, 0)
 
1131
    fm_side_pane_set_show_hidden(page->side_pane, show_hidden);
 
1132
#endif
619
1133
    /* update status text */
620
1134
    g_free(page->status_text[FM_STATUS_TEXT_NORMAL]);
621
1135
    page->status_text[FM_STATUS_TEXT_NORMAL] = format_status_text(page);
651
1165
 
652
1166
void fm_tab_page_forward(FmTabPage* page)
653
1167
{
 
1168
#if FM_CHECK_VERSION(1, 0, 2)
 
1169
    guint index = fm_nav_history_get_cur_index(page->nav_history);
 
1170
 
 
1171
    if (index > 0)
 
1172
#else
654
1173
    if(fm_nav_history_can_forward(page->nav_history))
 
1174
#endif
655
1175
    {
 
1176
#if !FM_CHECK_VERSION(1, 0, 2)
656
1177
        const FmNavHistoryItem* item;
 
1178
#endif
657
1179
        GtkAdjustment* vadjustment = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(page->folder_view));
658
1180
        int scroll_pos = gtk_adjustment_get_value(vadjustment);
 
1181
#if FM_CHECK_VERSION(1, 0, 2)
 
1182
        FmPath *path = fm_nav_history_go_to(page->nav_history, index - 1, scroll_pos);
 
1183
        fm_tab_page_chdir_without_history(page, path);
 
1184
#else
659
1185
        fm_nav_history_forward(page->nav_history, scroll_pos);
660
1186
        item = fm_nav_history_get_cur(page->nav_history);
661
1187
        fm_tab_page_chdir_without_history(page, item->path);
 
1188
#endif
662
1189
    }
663
1190
}
664
1191
 
666
1193
{
667
1194
    if(fm_nav_history_can_back(page->nav_history))
668
1195
    {
 
1196
#if !FM_CHECK_VERSION(1, 0, 2)
669
1197
        const FmNavHistoryItem* item;
 
1198
#endif
670
1199
        GtkAdjustment* vadjustment = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(page->folder_view));
671
1200
        int scroll_pos = gtk_adjustment_get_value(vadjustment);
 
1201
#if FM_CHECK_VERSION(1, 0, 2)
 
1202
        guint index = fm_nav_history_get_cur_index(page->nav_history);
 
1203
        FmPath *path = fm_nav_history_go_to(page->nav_history, index + 1, scroll_pos);
 
1204
        fm_tab_page_chdir_without_history(page, path);
 
1205
#else
672
1206
        fm_nav_history_back(page->nav_history, scroll_pos);
673
1207
        item = fm_nav_history_get_cur(page->nav_history);
674
1208
        fm_tab_page_chdir_without_history(page, item->path);
 
1209
#endif
675
1210
    }
676
1211
}
677
1212
 
 
1213
#if FM_CHECK_VERSION(1, 0, 2)
 
1214
void fm_tab_page_history(FmTabPage* page, guint history_item)
 
1215
{
 
1216
    GtkAdjustment* vadjustment = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(page->folder_view));
 
1217
    int scroll_pos = gtk_adjustment_get_value(vadjustment);
 
1218
    FmPath *path = fm_nav_history_go_to(page->nav_history, history_item, scroll_pos);
 
1219
    fm_tab_page_chdir_without_history(page, path);
 
1220
}
 
1221
#else
678
1222
void fm_tab_page_history(FmTabPage* page, GList* history_item_link)
679
1223
{
680
1224
    const FmNavHistoryItem* item = (FmNavHistoryItem*)history_item_link->data;
684
1228
    item = fm_nav_history_get_cur(page->nav_history);
685
1229
    fm_tab_page_chdir_without_history(page, item->path);
686
1230
}
 
1231
#endif
687
1232
 
688
1233
const char* fm_tab_page_get_title(FmTabPage* page)
689
1234
{
699
1244
void fm_tab_page_reload(FmTabPage* page)
700
1245
{
701
1246
    FmFolder* folder = fm_folder_view_get_folder(page->folder_view);
 
1247
 
702
1248
    if(folder)
 
1249
    {
 
1250
        GtkAdjustment* vadjustment = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(page->folder_view));
 
1251
        int scroll_pos = gtk_adjustment_get_value(vadjustment);
 
1252
        /* save the scroll position before reload */
 
1253
#if FM_CHECK_VERSION(1, 0, 2)
 
1254
        int idx = fm_nav_history_get_cur_index(page->nav_history);
 
1255
        fm_nav_history_go_to(page->nav_history, idx, scroll_pos);
 
1256
#else
 
1257
        FmNavHistoryItem* item = (FmNavHistoryItem*)fm_nav_history_get_cur(page->nav_history);
 
1258
        /* NOTE: ignoring const modifier due to invalid pre-1.0.2 design */
 
1259
        item->scroll_pos = scroll_pos;
 
1260
#endif
703
1261
        fm_folder_reload(folder);
704
 
}
 
1262
    }
 
1263
}
 
1264
 
 
1265
/**
 
1266
 * fm_tab_page_take_view_back
 
1267
 * @page: the page instance
 
1268
 *
 
1269
 * If folder view that is bound to page isn't present in the container,
 
1270
 * then moves it from the container where it is currently, to the @page.
 
1271
 * This API should be called only in single-pane mode, for two-pane use
 
1272
 * fm_tab_page_set_passive_view() instead.
 
1273
 *
 
1274
 * Returns: %TRUE if folder was not in @page and moved successfully.
 
1275
 */
 
1276
gboolean fm_tab_page_take_view_back(FmTabPage *page)
 
1277
{
 
1278
    GList *panes, *l;
 
1279
    GtkWidget *folder_view = GTK_WIDGET(page->folder_view);
 
1280
 
 
1281
    gtk_widget_set_state(folder_view, GTK_STATE_NORMAL);
 
1282
    panes = gtk_container_get_children(GTK_CONTAINER(page->views));
 
1283
    for (l = panes; l; l = l->next)
 
1284
        if ((GtkWidget*)l->data == folder_view)
 
1285
            break;
 
1286
    g_list_free(panes);
 
1287
    if (l)
 
1288
        return FALSE;
 
1289
    /* we already keep the reference, no need to do it again */
 
1290
    gtk_container_remove(GTK_CONTAINER(gtk_widget_get_parent(folder_view)),
 
1291
                         folder_view);
 
1292
    gtk_box_pack_start(page->views, folder_view, TRUE, TRUE, 0);
 
1293
    return TRUE;
 
1294
}
 
1295
 
 
1296
/**
 
1297
 * fm_tab_page_set_passive_view
 
1298
 * @page: the page instance
 
1299
 * @view: the folder view to add
 
1300
 * @on_right: %TRUE if @view should be moved to right pane
 
1301
 *
 
1302
 * If folder @view isn't already in designed place then moves it from the
 
1303
 * container where it is currently, to the @page. If @on_right is %TRUE
 
1304
 * then attempts to move into right pane. If @on_right is %FALSE then
 
1305
 * attempts to move into left pane.
 
1306
 *
 
1307
 * Also if folder view that is bound to @page isn't presented in the
 
1308
 * container, then moves it from the container where it is currently, to
 
1309
 * the @page on the side opposite to @view.
 
1310
 *
 
1311
 * See also: fm_tab_page_take_view_back().
 
1312
 *
 
1313
 * Returns: %TRUE if @view was moved successfully.
 
1314
 */
 
1315
gboolean fm_tab_page_set_passive_view(FmTabPage *page, FmFolderView *view,
 
1316
                                      gboolean on_right)
 
1317
{
 
1318
    GtkWidget *pane;
 
1319
 
 
1320
    g_return_val_if_fail(page != NULL && view != NULL, FALSE);
 
1321
    if (!fm_tab_page_take_view_back(page))
 
1322
    {
 
1323
#if !FM_CHECK_VERSION(1, 2, 0)
 
1324
        /* workaround on ExoIconView bug - it doesn't follow state change
 
1325
           so we re-add the folder view into our container to force change */
 
1326
        GtkWidget *fv = GTK_WIDGET(page->folder_view);
 
1327
 
 
1328
        /* we already keep the reference, no need to do it again */
 
1329
        gtk_container_remove(GTK_CONTAINER(gtk_widget_get_parent(fv)), fv);
 
1330
        gtk_box_pack_start(page->views, fv, TRUE, TRUE, 0);
 
1331
#endif
 
1332
    }
 
1333
    pane = GTK_WIDGET(view);
 
1334
    gtk_widget_set_state(pane, GTK_STATE_ACTIVE);
 
1335
    g_object_ref(view);
 
1336
    /* gtk_widget_reparent() is buggy so we do it manually */
 
1337
    if (gtk_widget_get_parent(pane))
 
1338
        gtk_container_remove(GTK_CONTAINER(gtk_widget_get_parent(pane)), pane);
 
1339
    gtk_box_pack_start(page->views, pane, TRUE, TRUE, 0);
 
1340
    g_object_unref(view);
 
1341
    if (!on_right)
 
1342
        gtk_box_reorder_child(page->views, pane, 0);
 
1343
    return TRUE;
 
1344
}
 
1345
 
 
1346
/**
 
1347
 * fm_tab_page_get_passive_view
 
1348
 * @page: the page instance
 
1349
 *
 
1350
 * Checks if the @page contains some folder view that was added via call
 
1351
 * to fm_tab_page_set_passive_view() and was not moved out yet.
 
1352
 *
 
1353
 * Returns: (transfer none): the folder view or %NULL.
 
1354
 */
 
1355
FmFolderView *fm_tab_page_get_passive_view(FmTabPage *page)
 
1356
{
 
1357
    GList *panes, *l;
 
1358
    FmFolderView *view;
 
1359
 
 
1360
    panes = gtk_container_get_children(GTK_CONTAINER(page->views));
 
1361
    for (l = panes; l; l = l->next)
 
1362
        if ((FmFolderView*)l->data != page->folder_view)
 
1363
            break;
 
1364
    view = l ? l->data : NULL;
 
1365
    g_list_free(panes);
 
1366
    return view;
 
1367
}
 
1368
 
 
1369
#if FM_CHECK_VERSION(1, 0, 2)
 
1370
/**
 
1371
 * fm_tab_page_set_filter_pattern
 
1372
 * @page: the page instance
 
1373
 * @pattern: (allow-none): new pattern
 
1374
 *
 
1375
 * Changes filter for the folder view in the @page. If @pattern is %NULL
 
1376
 * then folder contents will be not filtered anymore.
 
1377
 */
 
1378
void fm_tab_page_set_filter_pattern(FmTabPage *page, const char *pattern)
 
1379
{
 
1380
    FmFolderModel *model = NULL;
 
1381
    char *disp_name;
 
1382
 
 
1383
    /* validate pattern */
 
1384
    if (pattern && pattern[0] == '\0')
 
1385
        pattern = NULL;
 
1386
    if (page->folder_view != NULL)
 
1387
        model = fm_folder_view_get_model(page->folder_view);
 
1388
    if (page->filter_pattern == NULL && pattern == NULL)
 
1389
        return; /* nothing to change */
 
1390
    /* if we have model then update filter chain in it */
 
1391
    if (model)
 
1392
    {
 
1393
        if (page->filter_pattern == NULL && pattern)
 
1394
            fm_folder_model_add_filter(model, fm_tab_page_path_filter, page);
 
1395
        else if (page->filter_pattern && pattern == NULL)
 
1396
            fm_folder_model_remove_filter(model, fm_tab_page_path_filter, page);
 
1397
    }
 
1398
    /* update page own data */
 
1399
    g_free(page->filter_pattern);
 
1400
    if (pattern)
 
1401
    {
 
1402
        char *casefold = g_utf8_casefold(pattern, -1);
 
1403
        page->filter_pattern = g_utf8_normalize(casefold, -1, G_NORMALIZE_ALL);
 
1404
        g_free(casefold);
 
1405
    }
 
1406
    else
 
1407
        page->filter_pattern = NULL;
 
1408
    /* apply changes if needed */
 
1409
    if (model)
 
1410
        fm_folder_model_apply_filters(model);
 
1411
    /* update tab page title */
 
1412
    disp_name = fm_path_display_basename(fm_folder_view_get_cwd(page->folder_view));
 
1413
    if (page->filter_pattern)
 
1414
    {
 
1415
        /* include pattern into page title */
 
1416
        char *text = g_strdup_printf("%s [%s]", disp_name, page->filter_pattern);
 
1417
        g_free(disp_name);
 
1418
        disp_name = text;
 
1419
    }
 
1420
    fm_tab_label_set_text(page->tab_label, disp_name);
 
1421
    g_free(disp_name);
 
1422
}
 
1423
#endif