nautilus-file-conflict-dialog.c 13.5 KB
Newer Older
1
/* nautilus-file-conflict-dialog: dialog that handles file conflicts
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
 *  during transfer operations.
 *
 *  Copyright (C) 2008-2010 Cosimo Cecchi
 *
 *  This program is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU General Public License as
 *  published by the Free Software Foundation; either version 2 of the
 *  License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public
 *  License along with this program; if not, see <http://www.gnu.org/licenses/>.
 *
 *  Authors: Cosimo Cecchi <cosimoc@gnome.org>
 */
21 22 23 24

#include <config.h>
#include "nautilus-file-conflict-dialog.h"

Cosimo Cecchi's avatar
Cosimo Cecchi committed
25
#include <string.h>
26 27 28
#include <glib-object.h>
#include <gio/gio.h>
#include <glib/gi18n.h>
29
#include <pango/pango.h>
30 31
#include <eel/eel-vfs-extensions.h>

32 33
#include "nautilus-file.h"
#include "nautilus-icon-info.h"
34
#include "nautilus-operations-ui-manager.h"
35

36
struct _NautilusFileConflictDialog
37
{
38 39
    GtkDialog parent_instance;

40 41 42 43 44 45 46 47 48 49 50 51 52 53
    gchar *conflict_name;

    /* UI objects */
    GtkWidget *titles_vbox;
    GtkWidget *first_hbox;
    GtkWidget *second_hbox;
    GtkWidget *expander;
    GtkWidget *entry;
    GtkWidget *checkbox;
    GtkWidget *skip_button;
    GtkWidget *rename_button;
    GtkWidget *replace_button;
    GtkWidget *dest_image;
    GtkWidget *src_image;
54 55
};

56
G_DEFINE_TYPE (NautilusFileConflictDialog, nautilus_file_conflict_dialog, GTK_TYPE_DIALOG);
57

58 59
void
nautilus_file_conflict_dialog_set_text (NautilusFileConflictDialog *fcd,
60 61
                                        gchar                      *primary_text,
                                        gchar                      *secondary_text)
62
{
63 64 65 66 67 68 69
    GtkWidget *label;
    PangoAttrList *attr_list;

    label = gtk_label_new (primary_text);
    gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
    gtk_label_set_line_wrap_mode (GTK_LABEL (label), PANGO_WRAP_WORD_CHAR);
    gtk_label_set_xalign (GTK_LABEL (label), 0.0);
70
    gtk_box_pack_start (GTK_BOX (fcd->titles_vbox), label, FALSE, FALSE, 0);
71 72 73 74 75
    gtk_widget_show (label);

    attr_list = pango_attr_list_new ();
    pango_attr_list_insert (attr_list, pango_attr_weight_new (PANGO_WEIGHT_BOLD));
    pango_attr_list_insert (attr_list, pango_attr_scale_new (PANGO_SCALE_LARGE));
76
    g_object_set (label, "attributes", attr_list, NULL);
77 78 79 80 81 82

    pango_attr_list_unref (attr_list);

    label = gtk_label_new (secondary_text);
    gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
    gtk_label_set_xalign (GTK_LABEL (label), 0.0);
83
    gtk_box_pack_start (GTK_BOX (fcd->titles_vbox), label, FALSE, FALSE, 0);
84
    gtk_widget_show (label);
85 86
}

87 88
void
nautilus_file_conflict_dialog_set_images (NautilusFileConflictDialog *fcd,
89 90
                                          GdkPixbuf                  *destination_pixbuf,
                                          GdkPixbuf                  *source_pixbuf)
91
{
92
    if (fcd->dest_image == NULL)
93
    {
94 95 96
        fcd->dest_image = gtk_image_new_from_pixbuf (destination_pixbuf);
        gtk_box_pack_start (GTK_BOX (fcd->first_hbox), fcd->dest_image, FALSE, FALSE, 0);
        gtk_widget_show (fcd->dest_image);
97 98 99
    }
    else
    {
100
        gtk_image_set_from_pixbuf (GTK_IMAGE (fcd->dest_image), destination_pixbuf);
101 102
    }

103
    if (fcd->src_image == NULL)
104
    {
105 106 107
        fcd->src_image = gtk_image_new_from_pixbuf (source_pixbuf);
        gtk_box_pack_start (GTK_BOX (fcd->second_hbox), fcd->src_image, FALSE, FALSE, 0);
        gtk_widget_show (fcd->src_image);
108 109 110
    }
    else
    {
111
        gtk_image_set_from_pixbuf (GTK_IMAGE (fcd->src_image), source_pixbuf);
112
    }
113
}
Cosimo Cecchi's avatar
Cosimo Cecchi committed
114

115 116
void
nautilus_file_conflict_dialog_set_file_labels (NautilusFileConflictDialog *fcd,
117 118
                                               gchar                      *destination_label,
                                               gchar                      *source_label)
119
{
120 121 122
    GtkWidget *label;

    label = gtk_label_new (NULL);
123 124
    gtk_label_set_markup (GTK_LABEL (label), destination_label);
    gtk_box_pack_start (GTK_BOX (fcd->first_hbox), label, FALSE, FALSE, 0);
125 126 127
    gtk_widget_show (label);

    label = gtk_label_new (NULL);
128 129
    gtk_label_set_markup (GTK_LABEL (label), source_label);
    gtk_box_pack_start (GTK_BOX (fcd->second_hbox), label, FALSE, FALSE, 0);
130
    gtk_widget_show (label);
131
}
132

133 134
void
nautilus_file_conflict_dialog_set_conflict_name (NautilusFileConflictDialog *fcd,
135
                                                 gchar                      *conflict_name)
136
{
137
    fcd->conflict_name = g_strdup (conflict_name);
138

139
    gtk_entry_set_text (GTK_ENTRY (fcd->entry), fcd->conflict_name);
140 141
}

142 143
void
nautilus_file_conflict_dialog_set_replace_button_label (NautilusFileConflictDialog *fcd,
144
                                                        gchar                      *label)
145
{
146
    gtk_button_set_label (GTK_BUTTON (fcd->replace_button), label);
147 148
}

149 150
void
nautilus_file_conflict_dialog_disable_skip (NautilusFileConflictDialog *fcd)
151
{
152
    gtk_widget_hide (fcd->skip_button);
153
}
Cosimo Cecchi's avatar
Cosimo Cecchi committed
154

155 156 157 158 159 160
void
nautilus_file_conflict_dialog_disable_replace (NautilusFileConflictDialog *fcd)
{
    gtk_widget_set_sensitive (fcd->replace_button, FALSE);
}

161 162 163
void
nautilus_file_conflict_dialog_disable_apply_to_all (NautilusFileConflictDialog *fcd)
{
164
    gtk_widget_hide (fcd->checkbox);
165 166 167
}

static void
168 169
entry_text_changed_cb (GtkEditable                *entry,
                       NautilusFileConflictDialog *dialog)
170
{
171 172 173 174
    /* The rename button is visible only if there's text
     * in the entry.
     */
    if  (g_strcmp0 (gtk_entry_get_text (GTK_ENTRY (entry)), "") != 0 &&
175
         g_strcmp0 (gtk_entry_get_text (GTK_ENTRY (entry)), dialog->conflict_name) != 0)
176
    {
177 178
        gtk_widget_hide (dialog->replace_button);
        gtk_widget_show (dialog->rename_button);
179

180
        gtk_widget_set_sensitive (dialog->checkbox, FALSE);
181

182
        gtk_dialog_set_default_response (GTK_DIALOG (dialog), CONFLICT_RESPONSE_RENAME);
183 184 185
    }
    else
    {
186 187
        gtk_widget_hide (dialog->rename_button);
        gtk_widget_show (dialog->replace_button);
188

189
        gtk_widget_set_sensitive (dialog->checkbox, TRUE);
190

191
        gtk_dialog_set_default_response (GTK_DIALOG (dialog), CONFLICT_RESPONSE_REPLACE);
192
    }
193 194 195
}

static void
196 197
expander_activated_cb (GtkExpander                *w,
                       NautilusFileConflictDialog *dialog)
198
{
199 200 201 202
    int start_pos, end_pos;

    if (!gtk_expander_get_expanded (w))
    {
203
        if (g_strcmp0 (gtk_entry_get_text (GTK_ENTRY (dialog->entry)), dialog->conflict_name) == 0)
204
        {
205
            gtk_widget_grab_focus (dialog->entry);
206

207 208
            eel_filename_get_rename_region (dialog->conflict_name, &start_pos, &end_pos);
            gtk_editable_select_region (GTK_EDITABLE (dialog->entry), start_pos, end_pos);
209 210
        }
    }
Cosimo Cecchi's avatar
Cosimo Cecchi committed
211 212 213
}

static void
214 215
checkbox_toggled_cb (GtkToggleButton            *t,
                     NautilusFileConflictDialog *dialog)
Cosimo Cecchi's avatar
Cosimo Cecchi committed
216
{
217 218
    gtk_widget_set_sensitive (dialog->expander, !gtk_toggle_button_get_active (t));
    gtk_widget_set_sensitive (dialog->rename_button, !gtk_toggle_button_get_active (t));
219 220

    if  (!gtk_toggle_button_get_active (t) &&
221 222
         g_strcmp0 (gtk_entry_get_text (GTK_ENTRY (dialog->entry)), "") != 0 &&
         g_strcmp0 (gtk_entry_get_text (GTK_ENTRY (dialog->entry)), dialog->conflict_name) != 0)
223
    {
224 225
        gtk_widget_hide (dialog->replace_button);
        gtk_widget_show (dialog->rename_button);
226 227 228
    }
    else
    {
229 230
        gtk_widget_hide (dialog->rename_button);
        gtk_widget_show (dialog->replace_button);
231
    }
232 233 234
}

static void
235 236
reset_button_clicked_cb (GtkButton                  *w,
                         NautilusFileConflictDialog *dialog)
237
{
238 239
    int start_pos, end_pos;

240 241 242 243
    gtk_entry_set_text (GTK_ENTRY (dialog->entry), dialog->conflict_name);
    gtk_widget_grab_focus (dialog->entry);
    eel_filename_get_rename_region (dialog->conflict_name, &start_pos, &end_pos);
    gtk_editable_select_region (GTK_EDITABLE (dialog->entry), start_pos, end_pos);
Cosimo Cecchi's avatar
Cosimo Cecchi committed
244 245 246 247 248
}

static void
nautilus_file_conflict_dialog_init (NautilusFileConflictDialog *fcd)
{
249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273
    GtkWidget *hbox, *vbox, *vbox2;
    GtkWidget *widget, *dialog_area;
    GtkDialog *dialog;

    dialog = GTK_DIALOG (fcd);

    /* Setup the main hbox */
    hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
    dialog_area = gtk_dialog_get_content_area (dialog);
    gtk_box_pack_start (GTK_BOX (dialog_area), hbox, FALSE, FALSE, 0);
    gtk_container_set_border_width (GTK_CONTAINER (hbox), 6);

    /* Setup the dialog image */
    widget = gtk_image_new_from_icon_name ("dialog-warning",
                                           GTK_ICON_SIZE_DIALOG);
    gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
    gtk_widget_set_valign (widget, GTK_ALIGN_START);

    /* Setup the vbox containing the dialog body */
    vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
    gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0);

    /* Setup the vbox for the dialog labels */
    widget = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
    gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 0);
274
    fcd->titles_vbox = widget;
275 276 277 278 279 280 281 282 283

    /* Setup the hboxes to pack file infos into */
    vbox2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
    gtk_widget_set_halign (vbox2, GTK_ALIGN_START);
    gtk_widget_set_margin_start (vbox2, 12);
    gtk_box_pack_start (GTK_BOX (vbox), vbox2, FALSE, FALSE, 0);

    hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
    gtk_box_pack_start (GTK_BOX (vbox2), hbox, FALSE, FALSE, 0);
284
    fcd->first_hbox = hbox;
285 286 287

    hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
    gtk_box_pack_start (GTK_BOX (vbox2), hbox, FALSE, FALSE, 0);
288
    fcd->second_hbox = hbox;
289 290

    /* Setup the expander for the rename action */
291 292 293
    fcd->expander = gtk_expander_new_with_mnemonic (_("_Select a new name for the destination"));
    gtk_box_pack_start (GTK_BOX (vbox2), fcd->expander, FALSE, FALSE, 0);
    g_signal_connect (fcd->expander, "activate",
294 295 296
                      G_CALLBACK (expander_activated_cb), dialog);

    hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
297
    gtk_container_add (GTK_CONTAINER (fcd->expander), hbox);
298 299 300

    widget = gtk_entry_new ();
    gtk_box_pack_start (GTK_BOX (hbox), widget, TRUE, TRUE, 6);
301
    fcd->entry = widget;
302 303
    g_signal_connect (widget, "changed",
                      G_CALLBACK (entry_text_changed_cb), dialog);
304
    gtk_entry_set_activates_default (GTK_ENTRY (widget), TRUE);
305 306 307 308 309 310 311 312 313 314 315 316 317 318

    widget = gtk_button_new_with_label (_("Reset"));
    gtk_button_set_image (GTK_BUTTON (widget),
                          gtk_image_new_from_icon_name ("edit-undo",
                                                        GTK_ICON_SIZE_MENU));
    gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 6);
    g_signal_connect (widget, "clicked",
                      G_CALLBACK (reset_button_clicked_cb), dialog);

    gtk_widget_show_all (vbox2);

    /* Setup the checkbox to apply the action to all files */
    widget = gtk_check_button_new_with_mnemonic (_("Apply this action to all files and folders"));

319 320
    gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 0);
    fcd->checkbox = widget;
321 322 323 324
    g_signal_connect (widget, "toggled",
                      G_CALLBACK (checkbox_toggled_cb), dialog);

    /* Add buttons */
325 326 327 328 329 330 331 332 333 334 335 336
    gtk_dialog_add_button (dialog, _("_Cancel"), GTK_RESPONSE_CANCEL);

    fcd->skip_button = gtk_dialog_add_button (dialog,
                                              _("_Skip"),
                                              CONFLICT_RESPONSE_SKIP);

    fcd->rename_button = gtk_dialog_add_button (dialog,
                                                _("Re_name"),
                                                CONFLICT_RESPONSE_RENAME);
    gtk_widget_hide (fcd->rename_button);

    fcd->replace_button = gtk_dialog_add_button (dialog,
337
                                                 _("Re_place"),
338
                                                 CONFLICT_RESPONSE_REPLACE);
339
    gtk_widget_grab_focus (fcd->replace_button);
340 341 342 343 344 345 346

    /* Setup HIG properties */
    gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
    gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (dialog)), 14);
    gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);

    gtk_widget_show_all (dialog_area);
347 348 349 350 351
}

static void
do_finalize (GObject *self)
{
352
    NautilusFileConflictDialog *dialog = NAUTILUS_FILE_CONFLICT_DIALOG (self);
353

354
    g_free (dialog->conflict_name);
355

356
    G_OBJECT_CLASS (nautilus_file_conflict_dialog_parent_class)->finalize (self);
357 358 359 360 361
}

static void
nautilus_file_conflict_dialog_class_init (NautilusFileConflictDialogClass *klass)
{
362
    G_OBJECT_CLASS (klass)->finalize = do_finalize;
363 364
}

365 366 367
char *
nautilus_file_conflict_dialog_get_new_name (NautilusFileConflictDialog *dialog)
{
368
    return g_strdup (gtk_entry_get_text (GTK_ENTRY (dialog->entry)));
369 370 371 372 373
}

gboolean
nautilus_file_conflict_dialog_get_apply_to_all (NautilusFileConflictDialog *dialog)
{
374
    return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->checkbox));
375 376
}

377 378
NautilusFileConflictDialog *
nautilus_file_conflict_dialog_new (GtkWindow *parent)
379
{
380
    NautilusFileConflictDialog *dialog;
381

382 383 384 385
    dialog = NAUTILUS_FILE_CONFLICT_DIALOG (g_object_new (NAUTILUS_TYPE_FILE_CONFLICT_DIALOG,
                                                          "use-header-bar", TRUE,
                                                          "modal", TRUE,
                                                          NULL));
386

387
    gtk_window_set_transient_for (GTK_WINDOW (dialog), parent);
388

389
    return dialog;
390
}