570
570
set_cursor (path, false, true, false);
573
protected void select_and_scroll_to_gof_file (GOF.File file) {
574
var iter = Gtk.TreeIter ();
575
if (!model.get_first_iter_for_file (file, out iter))
576
return; /* file not in model */
578
var path = model.get_path (iter);
579
set_cursor (path, false, true, true);
573
582
protected void add_gof_file_to_selection (GOF.File file) {
574
583
var iter = Gtk.TreeIter ();
879
888
Marlin.FileOperations.new_folder (null, null, slot.location, (Marlin.CreateCallback?) create_file_done, this);
891
private void after_new_file_added (GOF.File? file) {
892
slot.directory.file_added.disconnect (after_new_file_added);
882
898
protected void rename_file (GOF.File file_to_rename) {
883
var iter = Gtk.TreeIter ();
885
/* Allow time for the file to appear in the tree model before renaming
887
GLib.Timeout.add (10, () => {
888
if (model.get_first_iter_for_file (file_to_rename, out iter)) {
889
/* Assume writability on remote locations */
890
/**TODO** Reliably determine writability with various remote protocols.*/
891
if (is_writable || !slot.directory.is_local)
892
start_renaming_file (file_to_rename, false);
894
warning ("You do not have permission to rename this file");
895
} else if (count < 100) {
896
/* Guard against possible infinite loop */
900
warning ("already renaming %s", file_to_rename.basename);
903
/* Assume writability on remote locations */
904
/**TODO** Reliably determine writability with various remote protocols.*/
905
if (is_writable || !slot.directory.is_local) {
906
start_renaming_file (file_to_rename);
908
warning ("You do not have permission to rename this file");
906
912
/** File operation callbacks */
907
913
static void create_file_done (GLib.File? new_file, void* data) {
908
914
var view = data as FM.AbstractDirectoryView;
916
922
warning ("View invalid after creating file");
920
var file_to_rename = GOF.File.@get (new_file);
921
view.rename_file (file_to_rename); /* will wait for file to appear in model */
925
/* Start to rename the file once we get signal that it has been added to model */
926
view.slot.directory.file_added.connect_after (view.after_new_file_added);
924
929
/** Must pass a pointer to an instance of FM.AbstractDirectoryView as 3rd parameter when
2780
2785
/** name renderer signals */
2781
protected void on_name_editing_started (Gtk.CellEditable? editable, string path) {
2786
protected void on_name_editing_started (Gtk.CellEditable? editable, string path_string) {
2788
warning ("on_name_edited re-entered");
2785
2791
renaming = true;
2787
editable_widget = editable as Marlin.AbstractEditableLabel;
2788
original_name = editable_widget.get_text ().dup ();
2793
var editable_widget = editable as Gtk.Editable?;
2794
if (editable_widget != null) {
2795
original_name = editable_widget.get_chars (0, -1);
2796
var path = new Gtk.TreePath.from_string (path_string);
2797
Gtk.TreeIter? iter = null;
2798
model.get_iter (out iter, path);
2799
GOF.File? file = null;
2800
model.@get (iter, FM.ListModel.ColumnID.FILE_COLUMN, out file);
2801
int start_offset= 0, end_offset = -1;
2802
/* Select whole name if the file is a folder, otherwise do not select the extension */
2803
if (!file.is_folder ()) {
2804
Marlin.get_rename_region (original_name, out start_offset, out end_offset, false);
2806
editable_widget.select_region (start_offset, end_offset);
2808
warning ("Editable widget is null");
2809
on_name_editing_canceled ();
2791
2813
protected void on_name_editing_canceled () {
2795
2814
renaming = false;
2796
2815
name_renderer.editable = false;
2797
2817
unfreeze_updates ();
2801
2821
protected void on_name_edited (string path_string, string new_name) {
2822
/* Must not re-enter */
2823
if (!renaming || proposed_name == new_name) {
2824
warning ("on_name_edited re-entered");
2805
2828
if (new_name != "") {
2806
2829
var path = new Gtk.TreePath.from_string (path_string);
2807
2830
Gtk.TreeIter? iter = null;
2811
2834
model.@get (iter, FM.ListModel.ColumnID.FILE_COLUMN, out file);
2813
2836
/* Only rename if name actually changed */
2814
original_name = file.info.get_name ();
2837
/* Because GOF.File.rename does not work correctly for remote files we handle ourselves */
2815
2839
if (new_name != original_name) {
2816
2840
proposed_name = new_name;
2817
file.rename (new_name, (GOF.FileOperationCallback)rename_callback, (void*)this);
2841
set_file_display_name (file.location, new_name, after_rename);
2843
warning ("Name unchanged");
2844
on_name_editing_canceled ();
2847
warning ("No new name");
2848
on_name_editing_canceled ();
2850
/* do not cancel editing here - will be cancelled in rename callback */
2853
public void set_file_display_name (GLib.File old_location, string new_name, PF.FileUtils.RenameCallbackFunc? f) {
2854
/* Wait for the file to be added to the model before trying to select and scroll to it */
2855
slot.directory.file_added.connect_after (after_renamed_file_added);
2856
PF.FileUtils.set_file_display_name (old_location, new_name, f);
2859
public void after_rename (GLib.File file, GLib.File? result_location, GLib.Error? e) {
2821
2860
on_name_editing_canceled ();
2825
public static void rename_callback (GOF.File file, GLib.File? result_location, GLib.Error error, void* data) {
2826
FM.AbstractDirectoryView? view = null;
2827
Marlin.View.PropertiesWindow? pw = null;
2829
var object = (GLib.Object)data;
2831
if (object is FM.AbstractDirectoryView)
2832
view = (FM.AbstractDirectoryView)data;
2833
else if (object is Marlin.View.PropertiesWindow) {
2834
pw = (Marlin.View.PropertiesWindow)object;
2838
assert (view != null);
2840
if (error != null) {
2841
Eel.show_error_dialog (_("Could not rename to '%s'").printf (view.proposed_name),
2843
view.window as Gtk.Window);
2845
Marlin.UndoManager.instance ().add_rename_action (file.location,
2846
view.original_name);
2848
view.select_gof_file (file); /* Select and scroll to show renamed file */
2853
pw.reset_entry_text (file.info.get_name ());
2855
pw.reset_entry_text (); //resets entry to old name
2863
private void after_renamed_file_added (GOF.File? new_file) {
2864
slot.directory.file_added.disconnect (after_renamed_file_added);
2865
/* new_file will be null if rename failed */
2866
if (new_file != null) {
2867
select_and_scroll_to_gof_file (new_file);
2859
2871
public virtual bool on_view_draw (Cairo.Context cr) {
2860
2872
/* If folder is empty, draw the empty message in the middle of the view
2861
2873
* otherwise pass on event */
3095
3107
view.style_updated ();
3098
private void start_renaming_file (GOF.File file, bool preselect_whole_name) {
3099
/* Select whole name if we are in renaming mode already */
3110
private void start_renaming_file (GOF.File file) {
3111
if (updates_frozen) {
3112
warning ("Trying to rename when frozen");
3103
3115
Gtk.TreeIter? iter = null;
3104
3116
if (!model.get_first_iter_for_file (file, out iter)) {
3105
3117
critical ("Failed to find rename file in model");
3109
3121
/* Freeze updates to the view to prevent losing rename focus when the tree view updates */
3110
3122
freeze_updates ();
3112
3123
Gtk.TreePath path = model.get_path (iter);
3126
bool ok_next_time = false;
3127
Gtk.TreePath? start_path = null;
3114
3128
/* Scroll to row to be renamed and then start renaming after a delay
3115
3129
* so that file to be renamed is on screen. This avoids the renaming being
3117
set_cursor (path, false, true, false);
3119
Gtk.TreePath? start_path = null;
3120
bool ok_next_time = false;
3122
3131
GLib.Timeout.add (50, () => {
3123
3132
/* Wait until view stops scrolling before starting to rename (up to 1 second)
3124
3133
* Scrolling is deemed to have stopped when the starting visible path is stable
3140
/* set cursor_on_cell also triggers editing-started, where we save the editable widget */
3149
/* set cursor_on_cell also triggers editing-started */
3141
3150
name_renderer.editable = true;
3142
3151
set_cursor_on_cell (path, name_renderer as Gtk.CellRenderer, true, false);
3144
if (editable_widget != null) {
3145
int start_offset= 0, end_offset = -1;
3146
if (!file.is_folder ())
3147
Marlin.get_rename_region (original_name, out start_offset, out end_offset, preselect_whole_name);
3149
editable_widget.select_region (start_offset, end_offset);
3151
warning ("Editable widget is null");
3152
on_name_editing_canceled ();