[gitg] Implemented selection discard



commit e815ebc78f6009ed96cf0614db74b154c3fade1d
Author: Jesse van den Kieboom <jessevdk gnome org>
Date:   Tue Jul 1 15:13:28 2014 +0200

    Implemented selection discard

 gitg/commit/gitg-commit-paned.vala     |    8 ++
 gitg/commit/gitg-commit.vala           |   77 ++++++++++++++++++++
 gitg/resources/ui/gitg-commit-paned.ui |   11 +++
 libgitg/gitg-stage.vala                |  125 +++++++++++++++++++++++++++++---
 4 files changed, 211 insertions(+), 10 deletions(-)
---
diff --git a/gitg/commit/gitg-commit-paned.vala b/gitg/commit/gitg-commit-paned.vala
index 0af1e71..3ae26bc 100644
--- a/gitg/commit/gitg-commit-paned.vala
+++ b/gitg/commit/gitg-commit-paned.vala
@@ -38,6 +38,9 @@ class Paned : Gtk.Paned
        [GtkChild (name = "button_stage")]
        private Gtk.Button d_button_stage;
 
+       [GtkChild (name = "button_discard")]
+       private Gtk.Button d_button_discard;
+
        public Gitg.Sidebar sidebar
        {
                get { return d_tree_view_files; }
@@ -63,6 +66,11 @@ class Paned : Gtk.Paned
                get { return d_button_stage; }
        }
 
+       public Gtk.Button button_discard
+       {
+               get { return d_button_discard; }
+       }
+
        construct
        {
                var state_settings = new Settings("org.gnome.gitg.state.commit");
diff --git a/gitg/commit/gitg-commit.vala b/gitg/commit/gitg-commit.vala
index a6d2308..eeb079a 100644
--- a/gitg/commit/gitg-commit.vala
+++ b/gitg/commit/gitg-commit.vala
@@ -148,6 +148,7 @@ namespace GitgCommit
                                        d_main.diff_view.staged = false;
 
                                        d_main.button_stage.label = _("_Stage selection");
+                                       d_main.button_discard.visible = true;
 
                                        d_main.diff_view.diff = d;
                                }
@@ -232,6 +233,7 @@ namespace GitgCommit
                                        d_main.diff_view.staged = true;
 
                                        d_main.button_stage.label = _("_Unstage selection");
+                                       d_main.button_discard.visible = false;
 
                                        d_main.diff_view.diff = d;
                                }
@@ -826,6 +828,72 @@ namespace GitgCommit
                        }
                }
 
+               private async void discard_selection() throws Error
+               {
+                       var selection = yield d_main.diff_view.get_selection();
+                       var stage = application.repository.stage;
+
+                       foreach (var pset in selection)
+                       {
+                               yield stage.revert_patch(pset);
+                       }
+               }
+
+               private void on_discard_clicked()
+               {
+                       var primary = _("Discard changes");
+                       var secondary = _("Are you sure you want to permanently discard the selected changes 
in the file `%s'?").printf(d_current_file.path);
+
+                       var q = new GitgExt.UserQuery();
+
+                       q.title = primary;
+                       q.message = secondary;
+                       q.message_type = Gtk.MessageType.QUESTION;
+
+                       q.responses = new GitgExt.UserQueryResponse[] {
+                               new GitgExt.UserQueryResponse(_("Discard"), Gtk.ResponseType.OK),
+                               new GitgExt.UserQueryResponse(_("_Cancel"), Gtk.ResponseType.CANCEL)
+                       };
+
+                       q.default_response = Gtk.ResponseType.OK;
+
+                       q.response.connect((w, r) => {
+                               if (r == Gtk.ResponseType.OK)
+                               {
+                                       return do_discard_selection(q);
+                               }
+
+                               return true;
+                       });
+
+                       application.user_query(q);
+               }
+
+               private bool do_discard_selection(GitgExt.UserQuery q)
+               {
+                       application.busy = true;
+
+                       discard_selection.begin((obj, res) => {
+                               try
+                               {
+                                       discard_selection.end(res);
+                               }
+                               catch (Error e)
+                               {
+                                       application.show_infobar(_("Failed to discard selection"),
+                                                                e.message,
+                                                                Gtk.MessageType.ERROR);
+                               }
+
+                               q.quit();
+                               application.busy = false;
+
+                               reload();
+                       });
+
+                       return false;
+               }
+
                private void on_stage_clicked()
                {
                        var staging = d_main.diff_view.unstaged;
@@ -944,12 +1012,21 @@ namespace GitgCommit
                                on_stage_clicked();
                        });
 
+                       d_main.button_discard.clicked.connect(() => {
+                               on_discard_clicked();
+                       });
+
                        d_main.sidebar.populate_popup.connect(do_populate_menu);
 
                        d_main.diff_view.bind_property("has-selection",
                                                       d_main.button_stage,
                                                       "sensitive",
                                                       BindingFlags.DEFAULT);
+
+                       d_main.diff_view.bind_property("has-selection",
+                                                      d_main.button_discard,
+                                                      "sensitive",
+                                                      BindingFlags.DEFAULT);
                }
        }
 }
diff --git a/gitg/resources/ui/gitg-commit-paned.ui b/gitg/resources/ui/gitg-commit-paned.ui
index 5b0c94e..fb8efef 100644
--- a/gitg/resources/ui/gitg-commit-paned.ui
+++ b/gitg/resources/ui/gitg-commit-paned.ui
@@ -94,6 +94,17 @@
                     <property name="pack-type">end</property>
                   </packing>
                 </child>
+                <child>
+                  <object class="GtkButton" id="button_discard">
+                    <property name="visible">True</property>
+                    <property name="use_underline">True</property>
+                    <property name="label" translatable="yes">D_iscard selection</property>
+                    <property name="sensitive">False</property>
+                  </object>
+                  <packing>
+                    <property name="pack-type">end</property>
+                  </packing>
+                </child>
               </object>
             </child>
           </object>
diff --git a/libgitg/gitg-stage.vala b/libgitg/gitg-stage.vala
index 39d2a0a..d8b9a41 100644
--- a/libgitg/gitg-stage.vala
+++ b/libgitg/gitg-stage.vala
@@ -552,6 +552,100 @@ public class Stage : Object
        }
 
        /**
+        * Revert a patch in the working directory.
+        *
+        * @param patch the patch to revert.
+        *
+        * Revert a provided patch from the working directory. The patch should
+        * contain changes of the file in the current working directory to the contents
+        * of the index (i.e. as obtained from diff_workdir)
+        */
+       public async void revert_patch(PatchSet patch) throws Error
+       {
+               // new file is the current file in the working directory
+               var workdirf = d_repository.get_workdir().resolve_relative_path(patch.filename);
+               var workdirf_stream = yield workdirf.read_async();
+
+               yield thread_index((index) => {
+                       var entries = index.get_entries();
+                       var entry = entries.get_by_path(workdirf, 0);
+
+                       if (entry == null)
+                       {
+                               throw new StageError.INDEX_ENTRY_NOT_FOUND(patch.filename);
+                       }
+
+                       var index_blob = d_repository.lookup<Ggit.Blob>(entry.get_id());
+                       unowned uchar[] index_content = index_blob.get_raw_content();
+
+                       var index_stream = new MemoryInputStream.from_bytes(new Bytes(index_content));
+                       var reversed = patch.reversed();
+
+                       FileIOStream? out_stream = null;
+                       File ?outf = null;
+
+                       try
+                       {
+                               outf = File.new_tmp(null, out out_stream);
+
+                               apply_patch_stream(workdirf_stream,
+                                                  index_stream,
+                                                  out_stream.output_stream,
+                                                  reversed);
+                       }
+                       catch (Error e)
+                       {
+                               workdirf_stream.close();
+                               index_stream.close();
+
+                               if (outf != null)
+                               {
+                                       try
+                                       {
+                                               outf.delete();
+                                       } catch {}
+                               }
+
+                               throw e;
+                       }
+
+                       workdirf_stream.close();
+                       index_stream.close();
+
+                       if (out_stream != null)
+                       {
+                               out_stream.close();
+                       }
+
+                       // Move outf to workdirf
+                       try
+                       {
+                               var repl = workdirf.replace(null,
+                                                           false,
+                                                           FileCreateFlags.NONE);
+
+                               repl.splice(outf.read(),
+                                           OutputStreamSpliceFlags.CLOSE_SOURCE |
+                                           OutputStreamSpliceFlags.CLOSE_TARGET);
+                       }
+                       catch (Error e)
+                       {
+                               try
+                               {
+                                       outf.delete();
+                               } catch {}
+
+                               throw e;
+                       }
+
+                       try
+                       {
+                               outf.delete();
+                       } catch {}
+               });
+       }
+
+       /**
         * Delete a file from the index.
         *
         * @param file the file to delete.
@@ -628,10 +722,30 @@ public class Stage : Object
                pos += length;
        }
 
-       private void apply_patch(Ggit.Index index, InputStream old_stream, InputStream new_stream, PatchSet 
patch) throws Error
+       private void apply_patch(Ggit.Index  index,
+                                InputStream old_stream,
+                                InputStream new_stream,
+                                PatchSet    patch) throws Error
        {
                var patched_stream = d_repository.create_blob();
 
+               apply_patch_stream(old_stream, new_stream, patched_stream, patch);
+
+               patched_stream.close();
+               var new_id = patched_stream.get_id();
+
+               var new_entry = d_repository.create_index_entry_for_path(patch.filename,
+                                                                        new_id);
+
+               index.add(new_entry);
+               index.write();
+       }
+
+       private void apply_patch_stream(InputStream  old_stream,
+                                       InputStream  new_stream,
+                                       OutputStream patched_stream,
+                                       PatchSet     patch) throws Error
+       {
                size_t old_ptr = 0;
                size_t new_ptr = 0;
 
@@ -665,15 +779,6 @@ public class Stage : Object
 
                // Copy remaining part of old
                patched_stream.splice(old_stream, OutputStreamSpliceFlags.NONE);
-               patched_stream.close();
-
-               var new_id = patched_stream.get_id();
-
-               var new_entry = d_repository.create_index_entry_for_path(patch.filename,
-                                                                        new_id);
-
-               index.add(new_entry);
-               index.write();
        }
 
        /**


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]