[gitg/wip/submodules: 6/8] Implement enumeration of submodules in commit view
- From: Jesse van den Kieboom <jessevdk src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gitg/wip/submodules: 6/8] Implement enumeration of submodules in commit view
- Date: Sun, 14 Dec 2014 09:06:51 +0000 (UTC)
commit 0c3b69cb305907b8ce08ce59a57865acc1aedc39
Author: Jesse van den Kieboom <jessevdk gmail com>
Date: Sat Dec 13 15:41:40 2014 +0100
Implement enumeration of submodules in commit view
gitg/Makefile.am | 2 +
gitg/commit/gitg-commit-paned.vala | 8 +
gitg/commit/gitg-commit-sidebar.vala | 90 ++--
gitg/commit/gitg-commit-submodule-diff-view.vala | 51 ++
gitg/commit/gitg-commit-submodule-info.vala | 97 ++++
gitg/commit/gitg-commit.vala | 532 +++++++++++++-------
gitg/resources/gitg-resources.xml | 2 +
gitg/resources/ui/gitg-commit-paned.ui | 18 +-
.../ui/gitg-commit-submodule-diff-view.ui | 96 ++++
gitg/resources/ui/gitg-commit-submodule-info.ui | 103 ++++
gitg/resources/ui/style.css | 14 +
libgitg/gitg-stage-status-enumerator.vala | 234 ++++++++--
libgitg/gitg-stage.vala | 43 +-
tests/libgitg/test-stage.vala | 10 +-
14 files changed, 1002 insertions(+), 298 deletions(-)
---
diff --git a/gitg/Makefile.am b/gitg/Makefile.am
index 61bba1b..9014446 100644
--- a/gitg/Makefile.am
+++ b/gitg/Makefile.am
@@ -78,6 +78,8 @@ gitg_gitg_VALASOURCES = \
gitg/commit/gitg-commit.vala \
gitg/commit/gitg-commit-paned.vala \
gitg/commit/gitg-commit-sidebar.vala \
+ gitg/commit/gitg-commit-submodule-diff-view.vala \
+ gitg/commit/gitg-commit-submodule-info.vala \
gitg/commit/gitg-commit-dialog.vala \
libgitg/libgitg-1.0.vapi \
libgitg-ext/libgitg-ext-1.0.vapi
diff --git a/gitg/commit/gitg-commit-paned.vala b/gitg/commit/gitg-commit-paned.vala
index fcb760d..10f8bad 100644
--- a/gitg/commit/gitg-commit-paned.vala
+++ b/gitg/commit/gitg-commit-paned.vala
@@ -29,6 +29,9 @@ class Paned : Gtk.Paned
[GtkChild (name = "diff_view")]
private Gitg.DiffView d_diff_view;
+ [GtkChild (name = "submodule_diff_view")]
+ private SubmoduleDiffView d_submodule_diff_view;
+
[GtkChild (name = "check_button_skip_hooks")]
private Gtk.CheckButton d_check_button_skip_hooks;
@@ -51,6 +54,11 @@ class Paned : Gtk.Paned
get { return d_diff_view; }
}
+ public SubmoduleDiffView submodule_diff_view
+ {
+ get { return d_submodule_diff_view; }
+ }
+
public bool skip_hooks
{
get { return d_check_button_skip_hooks.active; }
diff --git a/gitg/commit/gitg-commit-sidebar.vala b/gitg/commit/gitg-commit-sidebar.vala
index 517dbda..9dac9b0 100644
--- a/gitg/commit/gitg-commit-sidebar.vala
+++ b/gitg/commit/gitg-commit-sidebar.vala
@@ -33,33 +33,34 @@ class Sidebar : Gitg.Sidebar
public signal void selected_items_changed(Gitg.SidebarItem[] items);
- public class File : Object, Gitg.SidebarItem
+ public class Item : Object, Gitg.SidebarItem
{
public enum Type
{
NONE,
STAGED,
UNSTAGED,
- UNTRACKED
+ UNTRACKED,
+ SUBMODULE
}
- Gitg.StageStatusFile d_file;
+ Gitg.StageStatusItem d_item;
Type d_type;
- public File(Gitg.StageStatusFile f, Type type)
+ public Item(Gitg.StageStatusItem item, Type type)
{
- d_file = f;
+ d_item = item;
d_type = type;
}
- public Gitg.StageStatusFile file
+ public Gitg.StageStatusItem item
{
- get { return d_file; }
+ get { return d_item; }
}
public string text
{
- owned get { return d_file.path; }
+ owned get { return d_item.path; }
}
public Type stage_type
@@ -67,33 +68,9 @@ class Sidebar : Gitg.Sidebar
get { return d_type; }
}
- private string? icon_for_status(Ggit.StatusFlags status)
- {
- if ((status & (Ggit.StatusFlags.INDEX_NEW |
- Ggit.StatusFlags.WORKING_TREE_NEW)) != 0)
- {
- return "list-add-symbolic";
- }
- else if ((status & (Ggit.StatusFlags.INDEX_MODIFIED |
- Ggit.StatusFlags.INDEX_RENAMED |
- Ggit.StatusFlags.INDEX_TYPECHANGE |
- Ggit.StatusFlags.WORKING_TREE_MODIFIED |
- Ggit.StatusFlags.WORKING_TREE_TYPECHANGE)) != 0)
- {
- return "text-editor-symbolic";
- }
- else if ((status & (Ggit.StatusFlags.INDEX_DELETED |
- Ggit.StatusFlags.WORKING_TREE_DELETED)) != 0)
- {
- return "edit-delete-symbolic";
- }
-
- return null;
- }
-
public string? icon_name
{
- owned get { return icon_for_status(d_file.flags); }
+ owned get { return d_item.icon_name; }
}
}
@@ -123,38 +100,38 @@ class Sidebar : Gitg.Sidebar
sel.mode = Gtk.SelectionMode.MULTIPLE;
}
- private File.Type get_item_type(Gitg.SidebarItem item)
+ private Item.Type get_item_type(Gitg.SidebarItem item)
{
var header = item as Gitg.SidebarStore.SidebarHeader;
if (header != null)
{
- return (File.Type)header.id;
+ return (Item.Type)header.id;
}
- var file = item as File;
+ var sitem = item as Item;
- if (file != null)
+ if (sitem != null)
{
- return file.stage_type;
+ return sitem.stage_type;
}
- return File.Type.NONE;
+ return Item.Type.NONE;
}
- private File.Type selected_type()
+ private Item.Type selected_type()
{
foreach (var item in get_selected_items<Gitg.SidebarItem>())
{
var tp = get_item_type(item);
- if (tp != File.Type.NONE)
+ if (tp != Item.Type.NONE)
{
return tp;
}
}
- return File.Type.NONE;
+ return Item.Type.NONE;
}
protected override bool select_function(Gtk.TreeSelection sel,
@@ -182,21 +159,32 @@ class Sidebar : Gitg.Sidebar
var item = m.item_for_iter(iter);
- // Prevent selection of the untracked header
+ // Prevent selection of the untracked and submodule headers
var header = item as Gitg.SidebarStore.SidebarHeader;
- if (header != null && (File.Type)header.id == File.Type.UNTRACKED)
+ if (header != null)
{
- return false;
+ var id = (Item.Type)header.id;
+
+ if (id == Item.Type.UNTRACKED || id == Item.Type.SUBMODULE)
+ {
+ return false;
+ }
}
var seltp = selected_type();
- if (seltp == File.Type.NONE)
+ if (seltp == Item.Type.NONE)
{
return true;
}
+ // Do not allow multiple selections for submodules
+ if (seltp == Item.Type.SUBMODULE)
+ {
+ return false;
+ }
+
var tp = get_item_type(item);
return tp == seltp;
}
@@ -220,9 +208,9 @@ class Sidebar : Gitg.Sidebar
}
}
- public File[] items_of_type(File.Type type)
+ public Item[] items_of_type(Item.Type type)
{
- var ret = new File[0];
+ var ret = new Item[0];
model.foreach((m, path, iter) => {
var item = model.item_for_iter(iter);
@@ -232,11 +220,11 @@ class Sidebar : Gitg.Sidebar
return false;
}
- var file = item as File;
+ var sitem = item as Item;
- if (file != null && file.stage_type == type)
+ if (sitem != null && sitem.stage_type == type)
{
- ret += file;
+ ret += sitem;
}
return false;
diff --git a/gitg/commit/gitg-commit-submodule-diff-view.vala
b/gitg/commit/gitg-commit-submodule-diff-view.vala
new file mode 100644
index 0000000..1d2add9
--- /dev/null
+++ b/gitg/commit/gitg-commit-submodule-diff-view.vala
@@ -0,0 +1,51 @@
+/*
+ * This file is part of gitg
+ *
+ * Copyright (C) 2014 - Jesse van den Kieboom
+ *
+ * gitg 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.
+ *
+ * gitg 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 gitg. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+namespace GitgCommit
+{
+
+[GtkTemplate (ui = "/org/gnome/gitg/ui/gitg-commit-submodule-diff-view.ui")]
+class SubmoduleDiffView : Gtk.Box
+{
+ [GtkChild (name = "info")]
+ private SubmoduleInfo d_info;
+
+ [GtkChild (name = "diff_view_staged")]
+ private Gitg.DiffView d_diff_view_staged;
+
+ [GtkChild (name = "diff_view_unstaged")]
+ private Gitg.DiffView d_diff_view_unstaged;
+
+ public SubmoduleInfo info
+ {
+ get { return d_info; }
+ }
+
+ public Gitg.DiffView diff_view_staged
+ {
+ get { return d_diff_view_staged; }
+ }
+
+ public Gitg.DiffView diff_view_unstaged
+ {
+ get { return d_diff_view_unstaged; }
+ }
+}
+
+}
\ No newline at end of file
diff --git a/gitg/commit/gitg-commit-submodule-info.vala b/gitg/commit/gitg-commit-submodule-info.vala
new file mode 100644
index 0000000..c9e6023
--- /dev/null
+++ b/gitg/commit/gitg-commit-submodule-info.vala
@@ -0,0 +1,97 @@
+/*
+ * This file is part of gitg
+ *
+ * Copyright (C) 2014 - Jesse van den Kieboom
+ *
+ * gitg 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.
+ *
+ * gitg 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 gitg. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+namespace GitgCommit
+{
+
+[GtkTemplate (ui = "/org/gnome/gitg/ui/gitg-commit-submodule-info.ui")]
+class SubmoduleInfo : Gtk.Grid
+{
+ [GtkChild (name = "label_path")]
+ private Gtk.Label d_label_path;
+
+ [GtkChild (name = "label_url")]
+ private Gtk.Label d_label_url;
+
+ [GtkChild (name = "label_sha1")]
+ private Gtk.Label d_label_sha1;
+
+ [GtkChild (name = "label_subject")]
+ private Gtk.Label d_label_subject;
+
+ private Ggit.Submodule d_submodule;
+
+ public signal void request_open_repository(Ggit.Submodule submodule);
+
+ private void update_info_from_repository(Ggit.OId oid, Ggit.Submodule submodule)
+ {
+ Gitg.Repository repo;
+
+ d_label_subject.set_text("");
+
+ try
+ {
+ repo = submodule.open() as Gitg.Repository;
+ }
+ catch (Error e)
+ {
+ return;
+ }
+
+ try
+ {
+ var commit = repo.lookup<Gitg.Commit>(oid);
+
+ if (commit != null)
+ {
+ d_label_subject.set_text(commit.get_subject());
+ }
+ }
+ catch (Error e)
+ {
+ }
+ }
+
+ public Ggit.Submodule? submodule
+ {
+ set
+ {
+ d_submodule = value;
+
+ if (value != null)
+ {
+ d_label_path.set_text(value.get_path());
+ d_label_url.set_text(value.get_url());
+
+ var oid = value.get_workdir_id();
+ d_label_sha1.set_text(oid.to_string());
+
+ update_info_from_repository(oid, value);
+ }
+ }
+ }
+
+ [GtkCallback]
+ private void on_open_button_clicked()
+ {
+ request_open_repository(d_submodule);
+ }
+}
+
+}
\ No newline at end of file
diff --git a/gitg/commit/gitg-commit.vala b/gitg/commit/gitg-commit.vala
index 841bd7d..5226729 100644
--- a/gitg/commit/gitg-commit.vala
+++ b/gitg/commit/gitg-commit.vala
@@ -87,183 +87,266 @@ namespace GitgCommit
return action == "commit";
}
- private delegate void StageUnstageCallback(Sidebar.File f);
+ private delegate void StageUnstageCallback(Sidebar.Item item);
private delegate void UpdateDiffCallback();
private UpdateDiffCallback? d_update_diff_callback;
- private void show_unstaged_diff(Gitg.StageStatusFile[] files)
+ private void show_unstaged_diff(Gitg.StageStatusItem[] items)
{
- var stage = application.repository.stage;
+ show_submodule_ui(false);
+ show_unstaged_diff_intern(application.repository, d_main.diff_view, items, true);
+ }
+
+ private void show_unstaged_diff_intern(Gitg.Repository repository,
+ Gitg.DiffView view,
+ Gitg.StageStatusItem[]? items,
+ bool patchable)
+ {
+ var stage = repository.stage;
- stage.diff_workdir_all.begin(files, d_main.diff_view.options, (obj, res) => {
+ stage.diff_workdir_all.begin(items, view.options, (obj, res) => {
try
{
var d = stage.diff_workdir_all.end(res);
- d_main.diff_view.unstaged = true;
- d_main.diff_view.staged = false;
+ view.unstaged = patchable;
+ view.staged = false;
d_main.button_stage.label = _("_Stage selection");
+ d_main.button_stage.visible = patchable;
d_main.button_discard.visible = true;
- d_main.diff_view.diff = d;
+ view.diff = d;
}
catch
{
// TODO: show error in diff
- d_main.diff_view.diff = null;
+ view.diff = null;
}
});
d_update_diff_callback = () => {
- show_unstaged_diff(files);
+ show_unstaged_diff_intern(repository, view, items, patchable);
};
}
- private async void stage_files(owned Gitg.StageStatusFile[] files)
+ private async void stage_items(owned Gitg.StageStatusItem[] items)
{
var stage = application.repository.stage;
- foreach (var f in files)
+ foreach (var item in items)
{
- if ((f.flags & Ggit.StatusFlags.WORKING_TREE_DELETED) != 0)
+ var file = item as Gitg.StageStatusFile;
+
+ if (file != null)
{
- try
+ if ((file.flags & Ggit.StatusFlags.WORKING_TREE_DELETED) != 0)
{
- yield stage.delete_path(f.path);
+ try
+ {
+ yield stage.delete_path(file.path);
+ }
+ catch (Error e)
+ {
+ var msg = _("Failed to stage the removal of file
`%s'").printf(file.path);
+ application.show_infobar(msg, e.message,
Gtk.MessageType.ERROR);
+
+ break;
+ }
}
- catch (Error e)
+ else
{
- var msg = _("Failed to stage the removal of file
`%s'").printf(f.path);
- application.show_infobar(msg, e.message,
Gtk.MessageType.ERROR);
+ try
+ {
+ yield stage.stage_path(file.path);
+ }
+ catch (Error e)
+ {
+ var msg = _("Failed to stage the file
`%s'").printf(file.path);
+ application.show_infobar(msg, e.message,
Gtk.MessageType.ERROR);
- break;
+ break;
+ }
}
}
else
{
- try
- {
- yield stage.stage_path(f.path);
- }
- catch (Error e)
- {
- var msg = _("Failed to stage the file `%s'").printf(f.path);
- application.show_infobar(msg, e.message,
Gtk.MessageType.ERROR);
-
- break;
- }
+ // TODO: stage submodule item
}
}
reload();
}
- private void on_unstaged_activated(Gitg.StageStatusFile[] files)
+ private void show_submodule_ui(bool show)
+ {
+ d_main.submodule_diff_view.set_visible(show);
+ d_main.diff_view.set_visible(!show);
+
+ if (show)
+ {
+ d_main.diff_view.diff = null;
+ }
+ else
+ {
+ var view = d_main.submodule_diff_view;
+
+ view.info.submodule = null;
+ view.diff_view_staged.diff = null;
+ view.diff_view_unstaged.diff = null;
+ }
+ }
+
+ private void on_unstaged_activated(Gitg.StageStatusItem[] items)
{
- stage_files.begin(files, (obj, res) => {
- stage_files.end(res);
+ stage_items.begin(items, (obj, res) => {
+ stage_items.end(res);
});
}
- private void show_staged_diff(Gitg.StageStatusFile[] files)
+ private void show_submodule_diff(Gitg.StageStatusSubmodule sub)
{
- var stage = application.repository.stage;
+ show_submodule_ui(true);
+
+ var view = d_main.submodule_diff_view;
+
+ view.info.submodule = sub.submodule;
+
+ Gitg.Repository repo;
+
+ try
+ {
+ repo = sub.submodule.open() as Gitg.Repository;
+ }
+ catch (Error e)
+ {
+ view.diff_view_staged.diff = null;
+ view.diff_view_unstaged.diff = null;
+
+ return;
+ }
+
+ show_staged_diff_intern(repo, view.diff_view_staged, null, false);
+ show_unstaged_diff_intern(repo, view.diff_view_unstaged, null, false);
+ }
- stage.diff_index_all.begin(files, d_main.diff_view.options, (obj, res) => {
+ private void show_staged_diff_intern(Gitg.Repository repository,
+ Gitg.DiffView view,
+ Gitg.StageStatusItem[]? items,
+ bool patchable)
+ {
+ var stage = repository.stage;
+
+ stage.diff_index_all.begin(items, view.options, (obj, res) => {
try
{
var d = stage.diff_index_all.end(res);
- d_main.diff_view.unstaged = false;
- d_main.diff_view.staged = true;
+ view.unstaged = false;
+ view.staged = patchable;
d_main.button_stage.label = _("_Unstage selection");
+ d_main.button_stage.visible = patchable;
d_main.button_discard.visible = false;
- d_main.diff_view.diff = d;
+ view.diff = d;
}
catch
{
// TODO: error reporting
- d_main.diff_view.diff = null;
+ view.diff = null;
}
});
d_update_diff_callback = () => {
- show_staged_diff(files);
+ show_staged_diff_intern(repository, view, items, patchable);
};
}
- private async void unstage_files(owned Gitg.StageStatusFile[] files)
+ private void show_staged_diff(Gitg.StageStatusItem[] items)
+ {
+ show_submodule_ui(false);
+ show_staged_diff_intern(application.repository, d_main.diff_view, items, true);
+ }
+
+ private async void unstage_items(owned Gitg.StageStatusItem[] items)
{
var stage = application.repository.stage;
- foreach (var f in files)
+ foreach (var item in items)
{
- if ((f.flags & Ggit.StatusFlags.INDEX_NEW) != 0)
+ var file = item as Gitg.StageStatusFile;
+
+ if (file != null)
{
- try
+ if ((file.flags & Ggit.StatusFlags.INDEX_NEW) != 0)
{
- yield stage.delete_path(f.path);
+ try
+ {
+ yield stage.delete_path(file.path);
+ }
+ catch (Error e)
+ {
+ var msg = _("Failed to unstage the removal of file
`%s'").printf(file.path);
+ application.show_infobar(msg, e.message,
Gtk.MessageType.ERROR);
+
+ break;
+ }
}
- catch (Error e)
+ else
{
- var msg = _("Failed to unstage the removal of file
`%s'").printf(f.path);
- application.show_infobar(msg, e.message,
Gtk.MessageType.ERROR);
+ try
+ {
+ yield stage.unstage_path(file.path);
+ }
+ catch (Error e)
+ {
+ var msg = _("Failed to unstage the file
`%s'").printf(file.path);
+ application.show_infobar(msg, e.message,
Gtk.MessageType.ERROR);
- break;
+ break;
+ }
}
}
else
{
- try
- {
- yield stage.unstage_path(f.path);
- }
- catch (Error e)
- {
- var msg = _("Failed to unstage the file `%s'").printf(f.path);
- application.show_infobar(msg, e.message,
Gtk.MessageType.ERROR);
-
- break;
- }
+ // TODO: submodule?
}
}
reload();
}
- private void on_staged_activated(Gitg.StageStatusFile[] files)
+ private void on_staged_activated(Gitg.StageStatusItem[] items)
{
- unstage_files.begin(files, (obj, res) => {
- unstage_files.end(res);
+ unstage_items.begin(items, (obj, res) => {
+ unstage_items.end(res);
});
}
- private Sidebar.File[] append_files(Gitg.SidebarStore model,
- Gitg.StageStatusFile[] files,
- Sidebar.File.Type type,
+ private Sidebar.Item[] append_items(Gitg.SidebarStore model,
+ Gitg.StageStatusItem[] items,
+ Sidebar.Item.Type type,
Gee.HashSet<string>? selected_paths,
StageUnstageCallback? callback)
{
- var ret = new Sidebar.File[0];
+ var ret = new Sidebar.Item[0];
- foreach (var f in files)
+ foreach (var item in items)
{
- var item = new Sidebar.File(f, type);
+ var sitem = new Sidebar.Item(item, type);
- if (selected_paths != null && selected_paths.contains(f.path))
+ if (selected_paths != null && selected_paths.contains(item.path))
{
- ret += item;
+ ret += sitem;
}
- item.activated.connect((numclick) => {
- callback(item);
+ sitem.activated.connect((numclick) => {
+ callback(sitem);
});
- model.append(item);
+ model.append(sitem);
}
return ret;
@@ -283,17 +366,17 @@ namespace GitgCommit
var sb = d_main.sidebar;
var model = sb.model;
- Sidebar.File.Type selected_type;
- Gitg.StageStatusFile[] selected_files;
+ Sidebar.Item.Type selected_type;
+ Gitg.StageStatusItem[] selected_items;
- selected_files = files_for_items(sb.get_selected_items<Gitg.SidebarItem>(),
+ selected_items = items_for_items(sb.get_selected_items<Gitg.SidebarItem>(),
out selected_type);
var selected_paths = new Gee.HashSet<string>();
- foreach (var f in selected_files)
+ foreach (var item in selected_items)
{
- selected_paths.add(f.path);
+ selected_paths.add(item.path);
}
// Preload author avatar
@@ -320,78 +403,87 @@ namespace GitgCommit
var options = new Ggit.StatusOptions(opts, show, null);
var enumerator = stage.file_status(options);
- var indexflags = Ggit.StatusFlags.INDEX_NEW |
- Ggit.StatusFlags.INDEX_MODIFIED |
- Ggit.StatusFlags.INDEX_DELETED |
- Ggit.StatusFlags.INDEX_RENAMED |
- Ggit.StatusFlags.INDEX_TYPECHANGE;
-
- var workflags = Ggit.StatusFlags.WORKING_TREE_MODIFIED |
- Ggit.StatusFlags.WORKING_TREE_DELETED |
- Ggit.StatusFlags.WORKING_TREE_TYPECHANGE;
-
- var untrackedflags = Ggit.StatusFlags.WORKING_TREE_NEW;
-
- enumerator.next_files.begin(-1, (obj, res) => {
- var files = enumerator.next_files.end(res);
+ enumerator.next_items.begin(-1, (obj, res) => {
+ var items = enumerator.next_items.end(res);
- var staged = new Gitg.StageStatusFile[files.length];
+ var staged = new Gitg.StageStatusItem[items.length];
staged.length = 0;
- var unstaged = new Gitg.StageStatusFile[files.length];
+ var unstaged = new Gitg.StageStatusItem[items.length];
unstaged.length = 0;
- var untracked = new Gitg.StageStatusFile[files.length];
+ var untracked = new Gitg.StageStatusItem[items.length];
untracked.length = 0;
- foreach (var f in files)
+ var dirty = new Gitg.StageStatusItem[items.length];
+ dirty.length = 0;
+
+ bool hassub = false;
+
+ foreach (var item in items)
{
- if ((f.flags & indexflags) != 0)
+ if (item.is_staged)
+ {
+ staged += item;
+ }
+
+ if (item.is_unstaged)
{
- staged += f;
+ unstaged += item;
}
- if ((f.flags & workflags) != 0)
+ if (item.is_untracked)
{
- unstaged += f;
+ untracked += item;
}
- if ((f.flags & untrackedflags) != 0)
+ var sub = item as Gitg.StageStatusSubmodule;
+
+ if (sub != null)
{
- untracked += f;
+ hassub = true;
+
+ if (sub.is_dirty)
+ {
+ dirty += item;
+ }
}
}
model.clear();
d_main.diff_view.diff = null;
- var staged_header = model.begin_header(_("Staged"),
(uint)Sidebar.File.Type.STAGED);
+ var current_staged = new Sidebar.Item[0];
+ var current_unstaged = new Sidebar.Item[0];
+ var current_untracked = new Sidebar.Item[0];
+ var current_submodules = new Sidebar.Item[0];
+
+ // Populate staged items
+ var staged_header = model.begin_header(_("Staged"),
(uint)Sidebar.Item.Type.STAGED);
staged_header.activated.connect((numclick) => {
on_unstage_selected_items();
});
- var current_staged = new Sidebar.File[0];
- var current_unstaged = new Sidebar.File[0];
-
if (staged.length == 0)
{
model.append_dummy(_("No staged files"));
}
else
{
- current_staged = append_files(model,
+ current_staged = append_items(model,
staged,
- Sidebar.File.Type.STAGED,
+ Sidebar.Item.Type.STAGED,
selected_paths,
- (f) => {
- on_staged_activated(new
Gitg.StageStatusFile[] {f.file});
+ (item) => {
+ on_staged_activated(new
Gitg.StageStatusItem[] {item.item});
});
}
model.end_header();
- var unstaged_header = model.begin_header(_("Unstaged"),
(uint)Sidebar.File.Type.UNSTAGED);
+ // Populate unstaged items
+ var unstaged_header = model.begin_header(_("Unstaged"),
(uint)Sidebar.Item.Type.UNSTAGED);
unstaged_header.activated.connect((numclick) => {
on_stage_selected_items();
@@ -403,18 +495,19 @@ namespace GitgCommit
}
else
{
- current_unstaged = append_files(model,
+ current_unstaged = append_items(model,
unstaged,
- Sidebar.File.Type.UNSTAGED,
+ Sidebar.Item.Type.UNSTAGED,
selected_paths,
- (f) => {
- on_unstaged_activated(new
Gitg.StageStatusFile[] {f.file});
+ (item) => {
+ on_unstaged_activated(new
Gitg.StageStatusItem[] {item.item});
});
}
model.end_header();
- model.begin_header(_("Untracked"), (uint)Sidebar.File.Type.UNTRACKED);
+ // Populate untracked items
+ model.begin_header(_("Untracked"), (uint)Sidebar.Item.Type.UNTRACKED);
if (untracked.length == 0)
{
@@ -422,17 +515,31 @@ namespace GitgCommit
}
else
{
- append_files(model,
- untracked,
- Sidebar.File.Type.UNTRACKED,
- null,
- (f) => {
- on_unstaged_activated(new Gitg.StageStatusFile[]
{f.file});
- });
+ current_untracked = append_items(model,
+ untracked,
+ Sidebar.Item.Type.UNTRACKED,
+ selected_paths,
+ (item) => {
+
on_unstaged_activated(new Gitg.StageStatusItem[] {item.item});
+ });
}
model.end_header();
+ // Populate submodule items
+ if (hassub)
+ {
+ model.begin_header(_("Submodule"), (uint)Sidebar.Item.Type.SUBMODULE);
+ current_submodules = append_items(model,
+ dirty,
+ Sidebar.Item.Type.SUBMODULE,
+ selected_paths,
+ (item) => {
+ on_unstaged_activated(new
Gitg.StageStatusItem[] {item.item});
+ });
+ model.end_header();
+ }
+
d_main.sidebar.expand_all();
d_has_staged = staged.length != 0;
@@ -440,25 +547,52 @@ namespace GitgCommit
if (selected_paths.size != 0)
{
- Sidebar.File[] sel;
+ Sidebar.Item[] sel = null;
- if (selected_type == Sidebar.File.Type.STAGED)
+ switch (selected_type)
{
- sel = (current_staged.length != 0) ? current_staged :
current_unstaged;
+ case Sidebar.Item.Type.STAGED:
+ sel = current_staged;
+ break;
+ case Sidebar.Item.Type.UNSTAGED:
+ sel = current_unstaged;
+ break;
+ case Sidebar.Item.Type.UNTRACKED:
+ sel = current_untracked;
+ break;
+ case Sidebar.Item.Type.SUBMODULE:
+ sel = current_submodules;
+ break;
}
- else
+
+ if (sel == null || sel.length == 0)
+ {
+ sel = current_staged;
+ }
+
+ if (sel == null || sel.length == 0)
+ {
+ sel = current_unstaged;
+ }
+
+ if (sel == null || sel.length == 0)
+ {
+ sel = current_untracked;
+ }
+
+ if (sel == null || sel.length == 0)
{
- sel = (current_unstaged.length != 0) ? current_unstaged :
current_staged;
+ sel = current_submodules;
}
- if (sel.length != 0)
+ if (sel != null && sel.length != 0)
{
foreach (var item in sel)
{
d_main.sidebar.select(item);
}
}
- else if (selected_type == Sidebar.File.Type.STAGED)
+ else if (selected_type == Sidebar.Item.Type.STAGED)
{
d_main.sidebar.select(staged_header);
}
@@ -722,7 +856,7 @@ namespace GitgCommit
{
secmsg = _("Your email is not configured yet. Please go to the user
configuration and provide your email.");
}
-
+
// TODO: better to show user info dialog directly or something
application.show_infobar(_("Failed to pass pre-commit"),
secmsg,
@@ -872,15 +1006,15 @@ namespace GitgCommit
}
}
- private bool do_discard_files(GitgExt.UserQuery q, Gitg.StageStatusFile[] files)
+ private bool do_discard_items(GitgExt.UserQuery q, Gitg.StageStatusItem[] items)
{
application.busy = true;
- var paths = new string[files.length];
+ var paths = new string[items.length];
- for (var i = 0; i < files.length; i++)
+ for (var i = 0; i < items.length; i++)
{
- paths[i] = files[i].path;
+ paths[i] = items[i].path;
}
revert_paths.begin(paths, (o, ret) => {
@@ -904,25 +1038,25 @@ namespace GitgCommit
return false;
}
- private void on_discard_menu_activated(Gitg.StageStatusFile[] files)
+ private void on_discard_menu_activated(Gitg.StageStatusItem[] items)
{
var primary = _("Discard changes");
string secondary;
- if (files.length == 1)
+ if (items.length == 1)
{
- secondary = _("Are you sure you want to permanently discard all changes made
to the file `%s'?").printf(files[0].path);
+ secondary = _("Are you sure you want to permanently discard all changes made
to the file `%s'?").printf(items[0].path);
}
else
{
- var paths = new string[files.length - 1];
+ var paths = new string[items.length - 1];
- for (var i = 0; i < files.length - 1; i++)
+ for (var i = 0; i < items.length - 1; i++)
{
- paths[i] = @"`$(files[i].path)'";
+ paths[i] = @"`$(items[i].path)'";
}
- secondary = _("Are you sure you want to permanently discard all changes made
to the files %s and `%s'?").printf(string.joinv(", ", paths), files[files.length - 1].path);
+ secondary = _("Are you sure you want to permanently discard all changes made
to the files %s and `%s'?").printf(string.joinv(", ", paths), items[items.length - 1].path);
}
var q = new GitgExt.UserQuery();
@@ -941,7 +1075,7 @@ namespace GitgCommit
q.response.connect((w, r) => {
if (r == Gtk.ResponseType.OK)
{
- return do_discard_files(q, files);
+ return do_discard_items(q, items);
}
return true;
@@ -959,65 +1093,65 @@ namespace GitgCommit
return;
}
- Sidebar.File.Type type;
+ Sidebar.Item.Type type;
- var files = files_for_items(items, out type);
+ var sitems = items_for_items(items, out type);
- if (type == Sidebar.File.Type.UNSTAGED ||
- type == Sidebar.File.Type.UNTRACKED)
+ if (type == Sidebar.Item.Type.UNSTAGED ||
+ type == Sidebar.Item.Type.UNTRACKED)
{
var stage = new Gtk.MenuItem.with_mnemonic(_("_Stage changes"));
menu.append(stage);
stage.activate.connect(() => {
- on_unstaged_activated(files);
+ on_unstaged_activated(sitems);
});
}
- if (type == Sidebar.File.Type.STAGED)
+ if (type == Sidebar.Item.Type.STAGED)
{
var stage = new Gtk.MenuItem.with_mnemonic(_("_Unstage changes"));
menu.append(stage);
stage.activate.connect(() => {
- on_staged_activated(files);
+ on_staged_activated(sitems);
});
}
- if (type == Sidebar.File.Type.UNSTAGED)
+ if (type == Sidebar.Item.Type.UNSTAGED)
{
var discard = new Gtk.MenuItem.with_mnemonic(_("_Discard changes"));
menu.append(discard);
discard.activate.connect(() => {
- on_discard_menu_activated(files);
+ on_discard_menu_activated(sitems);
});
}
}
- private Gitg.StageStatusFile[] files_to_stage_files(Sidebar.File[] files)
+ private Gitg.StageStatusItem[] items_to_stage_items(Sidebar.Item[] items)
{
- var ret = new Gitg.StageStatusFile[files.length];
+ var ret = new Gitg.StageStatusItem[items.length];
for (var i = 0; i < ret.length; i++)
{
- ret[i] = files[i].file;
+ ret[i] = items[i].item;
}
return ret;
}
- private Gitg.StageStatusFile[] stage_status_files_of_type(Sidebar.File.Type type)
+ private Gitg.StageStatusItem[] stage_status_items_of_type(Sidebar.Item.Type type)
{
- return files_to_stage_files(d_main.sidebar.items_of_type(type));
+ return items_to_stage_items(d_main.sidebar.items_of_type(type));
}
- private Gitg.StageStatusFile[] files_for_items(Gitg.SidebarItem[] items, out
Sidebar.File.Type type)
+ private Gitg.StageStatusItem[] items_for_items(Gitg.SidebarItem[] items, out
Sidebar.Item.Type type)
{
- var files = new Gitg.StageStatusFile[items.length];
- files.length = 0;
+ var ret = new Gitg.StageStatusItem[items.length];
+ ret.length = 0;
- type = Sidebar.File.Type.NONE;
+ type = Sidebar.Item.Type.NONE;
foreach (var item in items)
{
@@ -1025,68 +1159,73 @@ namespace GitgCommit
if (header != null)
{
- type = (Sidebar.File.Type)header.id;
- return stage_status_files_of_type(type);
+ type = (Sidebar.Item.Type)header.id;
+ return stage_status_items_of_type(type);
}
- var file = item as Sidebar.File;
+ var sitem = item as Sidebar.Item;
- if (file != null)
+ if (sitem != null)
{
- files += file.file;
- type = file.stage_type;
+ ret += sitem.item;
+ type = sitem.stage_type;
}
}
- return files;
+ return ret;
}
private void sidebar_selection_changed(Gitg.SidebarItem[] items)
{
- Sidebar.File.Type type;
+ Sidebar.Item.Type type;
- var files = files_for_items(items, out type);
+ var sitems = items_for_items(items, out type);
- if (files.length == 0)
+ if (sitems.length == 0)
{
+ show_submodule_ui(false);
d_main.diff_view.diff = null;
return;
}
- if (type == Sidebar.File.Type.STAGED)
+ if (type == Sidebar.Item.Type.SUBMODULE)
{
- show_staged_diff(files);
+ show_submodule_diff((Gitg.StageStatusSubmodule)sitems[0]);
+ }
+ else if (type == Sidebar.Item.Type.STAGED)
+ {
+ show_staged_diff(sitems);
}
else
{
- show_unstaged_diff(files);
+ show_unstaged_diff(sitems);
}
}
private void on_stage_selected_items()
{
var sel = d_main.sidebar.get_selected_items<Gitg.SidebarItem>();
- Sidebar.File.Type type;
+ Sidebar.Item.Type type;
- var files = files_for_items(sel, out type);
+ var sitems = items_for_items(sel, out type);
- if (files.length != 0 && (type == Sidebar.File.Type.UNSTAGED ||
- type == Sidebar.File.Type.UNTRACKED))
+ if (sitems.length != 0 && (type == Sidebar.Item.Type.UNSTAGED ||
+ type == Sidebar.Item.Type.UNTRACKED))
{
- on_unstaged_activated(files);
+ on_unstaged_activated(sitems);
}
}
private void on_unstage_selected_items()
{
var sel = d_main.sidebar.get_selected_items<Gitg.SidebarItem>();
- Sidebar.File.Type type;
+ Sidebar.Item.Type type;
- var files = files_for_items(sel, out type);
+ var sitems = items_for_items(sel, out type);
- if (files.length != 0 && type == Sidebar.File.Type.STAGED)
+ if (sitems.length != 0 && type == Sidebar.Item.Type.STAGED)
{
- on_staged_activated(files);
+ on_staged_activated(sitems);
}
}
@@ -1110,13 +1249,13 @@ namespace GitgCommit
d_main.sidebar.discard_selection.connect(() => {
var sel = d_main.sidebar.get_selected_items<Gitg.SidebarItem>();
- Sidebar.File.Type type;
+ Sidebar.Item.Type type;
- var files = files_for_items(sel, out type);
+ var sitems = items_for_items(sel, out type);
- if (files.length != 0 && type == Sidebar.File.Type.UNSTAGED)
+ if (sitems.length != 0 && type == Sidebar.Item.Type.UNSTAGED)
{
- on_discard_menu_activated(files);
+ on_discard_menu_activated(sitems);
}
});
@@ -1134,6 +1273,23 @@ namespace GitgCommit
on_discard_clicked();
});
+ d_main.submodule_diff_view.info.request_open_repository.connect((submodule) => {
+ try
+ {
+ var app = application.open_new(submodule.open(), "commit");
+
+ ((Gtk.Window)app).delete_event.connect(() => {
+ reload();
+ return false;
+ });
+ }
+ catch (Error e)
+ {
+ // TODO: show error message
+ stderr.printf("Failed to open submodule repository: %s\n", e.message);
+ }
+ });
+
d_main.sidebar.populate_popup.connect(do_populate_menu);
var settings = new Settings("org.gnome.gitg.preferences.commit.diff");
diff --git a/gitg/resources/gitg-resources.xml b/gitg/resources/gitg-resources.xml
index f9e831d..e04c14e 100644
--- a/gitg/resources/gitg-resources.xml
+++ b/gitg/resources/gitg-resources.xml
@@ -14,6 +14,8 @@
<file compressed="true" preprocess="xml-stripblanks">ui/gitg-history-ref-row.ui</file>
<file compressed="true" preprocess="xml-stripblanks">ui/gitg-history-ref-header.ui</file>
<file compressed="true" preprocess="xml-stripblanks">ui/gitg-commit-paned.ui</file>
+ <file compressed="true" preprocess="xml-stripblanks">ui/gitg-commit-submodule-diff-view.ui</file>
+ <file compressed="true" preprocess="xml-stripblanks">ui/gitg-commit-submodule-info.ui</file>
<file compressed="true" preprocess="xml-stripblanks">ui/gitg-commit-dialog.ui</file>
<file compressed="true" preprocess="xml-stripblanks">ui/gitg-create-branch-dialog.ui</file>
<file compressed="true" preprocess="xml-stripblanks">ui/gitg-create-tag-dialog.ui</file>
diff --git a/gitg/resources/ui/gitg-commit-paned.ui b/gitg/resources/ui/gitg-commit-paned.ui
index f8bd7eb..902bf2e 100644
--- a/gitg/resources/ui/gitg-commit-paned.ui
+++ b/gitg/resources/ui/gitg-commit-paned.ui
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<!-- interface-requires gtk+ 3.3 -->
- <!-- interface-requires gitg 0.0 -->
- <!-- interface-requires gd 1.0 -->
+ <!-- interface-requires gitg 3.0 -->
<template class="GitgCommitPaned" parent="GtkPaned">
<property name="visible">True</property>
<property name="hexpand">True</property>
@@ -50,6 +49,21 @@
</object>
</child>
<child>
+ <object class="GitgCommitSubmoduleDiffView" id="submodule_diff_view">
+ <property name="visible">False</property>
+ <property name="can_focus">False</property>
+ <property name="margin_left">12</property>
+ <property name="margin_right">12</property>
+ <property name="margin_top">12</property>
+ <property name="margin_bottom">12</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
<object class="GtkFrame" id="frame_commit">
<property name="visible">True</property>
<style>
diff --git a/gitg/resources/ui/gitg-commit-submodule-diff-view.ui
b/gitg/resources/ui/gitg-commit-submodule-diff-view.ui
new file mode 100644
index 0000000..b843dae
--- /dev/null
+++ b/gitg/resources/ui/gitg-commit-submodule-diff-view.ui
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <requires lib="gtk+" version="3.3"/>
+ <requires lib="gitg" version="3.0"/>
+ <template class="GitgCommitSubmoduleDiffView" parent="GtkBox">
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GitgCommitSubmoduleInfo" id="info">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_staged">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="margin_top">12</property>
+ <property name="label" translatable="yes">Staged:</property>
+ <style>
+ <class name="title-label"/>
+ </style>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFrame" id="frame_staged">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <child>
+ <object class="GitgDiffView" id="diff_view_staged">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_nstaged">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="margin_top">12</property>
+ <property name="label" translatable="yes">Unstaged:</property>
+ <style>
+ <class name="title-label"/>
+ </style>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFrame" id="frame_unstaged">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <child>
+ <object class="GitgDiffView" id="diff_view_unstaged">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">4</property>
+ </packing>
+ </child>
+ </template>
+</interface>
\ No newline at end of file
diff --git a/gitg/resources/ui/gitg-commit-submodule-info.ui b/gitg/resources/ui/gitg-commit-submodule-info.ui
new file mode 100644
index 0000000..395f428
--- /dev/null
+++ b/gitg/resources/ui/gitg-commit-submodule-info.ui
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <requires lib="gtk+" version="3.3"/>
+ <requires lib="gitg" version="3.0"/>
+ <template class="GitgCommitSubmoduleInfo" parent="GtkGrid">
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">6</property>
+ <child>
+ <object class="GtkImage" id="image_folder">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="valign">start</property>
+ <property name="icon_name">folder-remote</property>
+ <property name="icon_size">6</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ <property name="height">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_path">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="selectable">True</property>
+ <property name="halign">start</property>
+ <property name="hexpand">True</property>
+ <style>
+ <class name="title-label"/>
+ </style>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_url">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="selectable">True</property>
+ <property name="halign">start</property>
+ <property name="hexpand">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_sha1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="selectable">True</property>
+ <property name="halign">end</property>
+ <property name="hexpand">True</property>
+ <style>
+ <class name="sha1-label"/>
+ </style>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">3</property>
+ <property name="width">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="button_open">
+ <property name="label" translatable="yes">Open</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="valign">start</property>
+ <signal name="clicked" handler="on_open_button_clicked"/>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="top_attach">0</property>
+ <property name="height">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_subject">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="selectable">True</property>
+ <property name="halign">start</property>
+ <property name="margin_left">12</property>
+ <property name="margin_top">12</property>
+ <property name="hexpand">True</property>
+ <style>
+ <class name="subject-label"/>
+ </style>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">2</property>
+ <property name="width">3</property>
+ </packing>
+ </child>
+ </template>
+</interface>
diff --git a/gitg/resources/ui/style.css b/gitg/resources/ui/style.css
index b0d8e1b..101caac 100644
--- a/gitg/resources/ui/style.css
+++ b/gitg/resources/ui/style.css
@@ -120,3 +120,17 @@ GitgHistoryRefRow {
border: 0;
-GtkWidget-focus-padding: 0;
}
+
+.title-label {
+ font-weight: bold;
+}
+
+.subject-label {
+ font-weight: bold;
+}
+
+.sha1-label {
+ font-size: 0.8em;
+ color: @insensitive_fg_color;
+ font-family: monospace;
+}
\ No newline at end of file
diff --git a/libgitg/gitg-stage-status-enumerator.vala b/libgitg/gitg-stage-status-enumerator.vala
index b767330..5b86f17 100644
--- a/libgitg/gitg-stage-status-enumerator.vala
+++ b/libgitg/gitg-stage-status-enumerator.vala
@@ -20,11 +20,37 @@
namespace Gitg
{
-public class StageStatusFile : Object
+public interface StageStatusItem : Object
+{
+ public abstract string path { owned get; }
+
+ public abstract bool is_staged { get; }
+ public abstract bool is_unstaged { get; }
+ public abstract bool is_untracked { get; }
+
+ public abstract string? icon_name { owned get; }
+}
+
+public class StageStatusFile : Object, StageStatusItem
{
private string d_path;
private Ggit.StatusFlags d_flags;
+ private static Ggit.StatusFlags s_index_flags =
+ Ggit.StatusFlags.INDEX_NEW
+ | Ggit.StatusFlags.INDEX_MODIFIED
+ | Ggit.StatusFlags.INDEX_DELETED
+ | Ggit.StatusFlags.INDEX_RENAMED
+ | Ggit.StatusFlags.INDEX_TYPECHANGE;
+
+ private static Ggit.StatusFlags s_work_flags =
+ Ggit.StatusFlags.WORKING_TREE_MODIFIED
+ | Ggit.StatusFlags.WORKING_TREE_DELETED
+ | Ggit.StatusFlags.WORKING_TREE_TYPECHANGE;
+
+ private static Ggit.StatusFlags s_untracked_flags =
+ Ggit.StatusFlags.WORKING_TREE_NEW;
+
public StageStatusFile(string path, Ggit.StatusFlags flags)
{
d_path = path;
@@ -36,17 +62,144 @@ public class StageStatusFile : Object
owned get { return d_path; }
}
+ public bool is_staged
+ {
+ get { return (d_flags & s_index_flags) != 0; }
+ }
+
+ public bool is_unstaged
+ {
+ get { return (d_flags & s_work_flags) != 0; }
+ }
+
+ public bool is_untracked
+ {
+ get { return (d_flags & s_untracked_flags) != 0; }
+ }
+
public Ggit.StatusFlags flags
{
get { return d_flags; }
}
+
+ private string? icon_for_status(Ggit.StatusFlags status)
+ {
+ if ((status & (Ggit.StatusFlags.INDEX_NEW |
+ Ggit.StatusFlags.WORKING_TREE_NEW)) != 0)
+ {
+ return "list-add-symbolic";
+ }
+ else if ((status & (Ggit.StatusFlags.INDEX_MODIFIED |
+ Ggit.StatusFlags.INDEX_RENAMED |
+ Ggit.StatusFlags.INDEX_TYPECHANGE |
+ Ggit.StatusFlags.WORKING_TREE_MODIFIED |
+ Ggit.StatusFlags.WORKING_TREE_TYPECHANGE)) != 0)
+ {
+ return "text-editor-symbolic";
+ }
+ else if ((status & (Ggit.StatusFlags.INDEX_DELETED |
+ Ggit.StatusFlags.WORKING_TREE_DELETED)) != 0)
+ {
+ return "edit-delete-symbolic";
+ }
+
+ return null;
+ }
+
+ public string? icon_name
+ {
+ owned get { return icon_for_status(d_flags); }
+ }
+}
+
+public class StageStatusSubmodule : Object, StageStatusItem
+{
+ private Ggit.Submodule d_submodule;
+ private string d_path;
+ private Ggit.SubmoduleStatus d_flags;
+
+ private static Ggit.SubmoduleStatus s_index_flags =
+ Ggit.SubmoduleStatus.INDEX_ADDED
+ | Ggit.SubmoduleStatus.INDEX_DELETED
+ | Ggit.SubmoduleStatus.INDEX_MODIFIED;
+
+ private static Ggit.SubmoduleStatus s_work_flags =
+ Ggit.SubmoduleStatus.WD_ADDED
+ | Ggit.SubmoduleStatus.WD_DELETED
+ | Ggit.SubmoduleStatus.WD_MODIFIED;
+
+ private static Ggit.SubmoduleStatus s_untracked_flags =
+ Ggit.SubmoduleStatus.IN_WD;
+
+ private static Ggit.SubmoduleStatus s_tracked_flags =
+ Ggit.SubmoduleStatus.IN_HEAD
+ | Ggit.SubmoduleStatus.IN_INDEX;
+
+ private static Ggit.SubmoduleStatus s_dirty_flags =
+ Ggit.SubmoduleStatus.WD_INDEX_MODIFIED
+ | Ggit.SubmoduleStatus.WD_WD_MODIFIED;
+
+ public StageStatusSubmodule(Ggit.Submodule submodule)
+ {
+ d_submodule = submodule;
+
+ d_path = submodule.get_path();
+
+ try
+ {
+ d_flags = submodule.get_status();
+ } catch {}
+ }
+
+ public Ggit.Submodule submodule
+ {
+ get { return d_submodule; }
+ }
+
+ public string path
+ {
+ owned get { return d_path; }
+ }
+
+ public bool is_staged
+ {
+ get { return (d_flags & s_index_flags) != 0; }
+ }
+
+ public bool is_unstaged
+ {
+ get { return (d_flags & s_work_flags) != 0; }
+ }
+
+ public bool is_untracked
+ {
+ get
+ {
+ return (d_flags & s_untracked_flags) != 0
+ && (d_flags & s_tracked_flags) == 0;
+ }
+ }
+
+ public bool is_dirty
+ {
+ get { return (d_flags & s_dirty_flags) != 0; }
+ }
+
+ public Ggit.SubmoduleStatus flags
+ {
+ get { return d_flags; }
+ }
+
+ public string? icon_name {
+ owned get { return "folder-remote-symbolic"; }
+ }
}
public class StageStatusEnumerator : Object
{
private Repository d_repository;
private Thread<void *> d_thread;
- private StageStatusFile[] d_files;
+ private StageStatusItem[] d_items;
private int d_offset;
private int d_callback_num;
private Cancellable d_cancellable;
@@ -59,8 +212,8 @@ public class StageStatusEnumerator : Object
d_repository = repository;
d_options = options;
- d_files = new StageStatusFile[100];
- d_files.length = 0;
+ d_items = new StageStatusItem[100];
+ d_items.length = 0;
d_cancellable = new Cancellable();
try
@@ -71,7 +224,7 @@ public class StageStatusEnumerator : Object
public void cancel()
{
- lock (d_files)
+ lock (d_items)
{
if (d_cancellable != null)
{
@@ -86,34 +239,45 @@ public class StageStatusEnumerator : Object
}
}
+ private delegate void AddItem(StageStatusItem item);
+
private void *run_status()
{
+ AddItem add = (item) => {
+ lock (d_items)
+ {
+ d_items += item;
+
+ if (d_callback != null && d_callback_num != -1 && d_items.length >=
d_callback_num)
+ {
+ var cb = (owned)d_callback;
+ d_callback = null;
+
+ Idle.add((owned)cb);
+ }
+ }
+ };
+
try
{
d_repository.file_status_foreach(d_options, (path, flags) => {
- lock (d_files)
- {
- d_files += new StageStatusFile(path, flags);
+ add(new StageStatusFile(path, flags));
- if (d_callback != null && d_callback_num != -1 && d_files.length >=
d_callback_num)
- {
- var cb = (owned)d_callback;
- d_callback = null;
-
- Idle.add((owned)cb);
- }
- }
+ return d_cancellable.is_cancelled() ? 1 : 0;
+ });
+ } catch {}
- if (d_cancellable.is_cancelled())
- {
- return 1;
- }
+ try
+ {
+ d_repository.submodule_foreach((submodule) => {
+ submodule.set_ignore(Ggit.SubmoduleIgnore.UNTRACKED);
+ add(new StageStatusSubmodule(submodule));
- return 0;
+ return d_cancellable.is_cancelled() ? 1 : 0;
});
} catch {}
- lock (d_files)
+ lock (d_items)
{
d_cancellable = null;
@@ -129,27 +293,27 @@ public class StageStatusEnumerator : Object
return null;
}
- private StageStatusFile[] fill_files(int num)
+ private StageStatusItem[] fill_items(int num)
{
int n = 0;
if (num == -1)
{
- num = d_files.length - d_offset;
+ num = d_items.length - d_offset;
}
- StageStatusFile[] ret = new StageStatusFile[int.min(num, d_files.length - d_offset)];
+ StageStatusItem[] ret = new StageStatusItem[int.min(num, d_items.length - d_offset)];
ret.length = 0;
- // d_files is already locked here, so it's safe to access
- while (d_offset < d_files.length)
+ // d_items is already locked here, so it's safe to access
+ while (d_offset < d_items.length)
{
if (n == num)
{
break;
}
- ret += d_files[d_offset];
+ ret += d_items[d_offset];
d_offset++;
++n;
@@ -158,17 +322,17 @@ public class StageStatusEnumerator : Object
return ret;
}
- public async StageStatusFile[] next_files(int num)
+ public async StageStatusItem[] next_items(int num)
{
- SourceFunc callback = next_files.callback;
- StageStatusFile[] ret;
+ SourceFunc callback = next_items.callback;
+ StageStatusItem[] ret;
- lock (d_files)
+ lock (d_items)
{
if (d_cancellable == null)
{
// Already finished
- return fill_files(num);
+ return fill_items(num);
}
else
{
@@ -179,9 +343,9 @@ public class StageStatusEnumerator : Object
yield;
- lock (d_files)
+ lock (d_items)
{
- ret = fill_files(num);
+ ret = fill_items(num);
}
if (ret.length != num)
diff --git a/libgitg/gitg-stage.vala b/libgitg/gitg-stage.vala
index fa4128d..687d879 100644
--- a/libgitg/gitg-stage.vala
+++ b/libgitg/gitg-stage.vala
@@ -904,8 +904,8 @@ public class Stage : Object
});
}
- public async Ggit.Diff? diff_index_all(StageStatusFile[] files,
- Ggit.DiffOptions? defopts = null) throws Error
+ public async Ggit.Diff? diff_index_all(StageStatusItem[]? files,
+ Ggit.DiffOptions? defopts = null) throws Error
{
var opts = new Ggit.DiffOptions();
@@ -913,14 +913,18 @@ public class Stage : Object
Ggit.DiffOption.DISABLE_PATHSPEC_MATCH |
Ggit.DiffOption.RECURSE_UNTRACKED_DIRS;
- var pspec = new string[files.length];
- for (var i = 0; i < files.length; i++)
+ if (files != null)
{
- pspec[i] = files[i].path;
- }
+ var pspec = new string[files.length];
+
+ for (var i = 0; i < files.length; i++)
+ {
+ pspec[i] = files[i].path;
+ }
- opts.pathspec = pspec;
+ opts.pathspec = pspec;
+ }
if (defopts != null)
{
@@ -941,13 +945,13 @@ public class Stage : Object
opts);
}
- public async Ggit.Diff? diff_index(StageStatusFile f,
+ public async Ggit.Diff? diff_index(StageStatusItem f,
Ggit.DiffOptions? defopts = null) throws Error
{
- return yield diff_index_all(new StageStatusFile[] {f}, defopts);
+ return yield diff_index_all(new StageStatusItem[] {f}, defopts);
}
- public async Ggit.Diff? diff_workdir_all(StageStatusFile[] files,
+ public async Ggit.Diff? diff_workdir_all(StageStatusItem[] files,
Ggit.DiffOptions? defopts = null) throws Error
{
var opts = new Ggit.DiffOptions();
@@ -956,14 +960,17 @@ public class Stage : Object
Ggit.DiffOption.DISABLE_PATHSPEC_MATCH |
Ggit.DiffOption.RECURSE_UNTRACKED_DIRS;
- var pspec = new string[files.length];
-
- for (var i = 0; i < files.length; i++)
+ if (files != null)
{
- pspec[i] = files[i].path;
- }
+ var pspec = new string[files.length];
- opts.pathspec = pspec;
+ for (var i = 0; i < files.length; i++)
+ {
+ pspec[i] = files[i].path;
+ }
+
+ opts.pathspec = pspec;
+ }
if (defopts != null)
{
@@ -981,10 +988,10 @@ public class Stage : Object
opts);
}
- public async Ggit.Diff? diff_workdir(StageStatusFile f,
+ public async Ggit.Diff? diff_workdir(StageStatusItem f,
Ggit.DiffOptions? defopts = null) throws Error
{
- return yield diff_workdir_all(new StageStatusFile[] {f}, defopts);
+ return yield diff_workdir_all(new StageStatusItem[] {f}, defopts);
}
}
diff --git a/tests/libgitg/test-stage.vala b/tests/libgitg/test-stage.vala
index 0e83cb8..9bd1175 100644
--- a/tests/libgitg/test-stage.vala
+++ b/tests/libgitg/test-stage.vala
@@ -52,13 +52,15 @@ class Gitg.Test.Stage : Gitg.Test.Repository
var stage = d_repository.stage;
var e = stage.file_status(null);
- e.next_files.begin(-1, (obj, res) => {
- var files = e.next_files.end(res);
+ e.next_items.begin(-1, (obj, res) => {
+ var items = e.next_items.end(res);
- assert(files.length == cfiles.size);
+ assert(items.length == cfiles.size);
- foreach (var f in files)
+ foreach (var item in items)
{
+ var f = item as Gitg.StageStatusFile;
+
assert(cfiles.has_key(f.path));
assert_inteq(cfiles[f.path], f.flags);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]