#
#
# patch "mtn-browse"
# from [e961b274ebebd3b84c9438a30ec320dafa6fbfb2]
# to [96ddbb57a8aecd5db92c1635b9627410b6402ae7]
#
# patch "mtn-browse.glade"
# from [db85aab77dba15a9926d2438b6cc20077013fdb9]
# to [32a19a669843c4ba9f45293d822899dd11c5b1fc]
#
============================================================
--- mtn-browse e961b274ebebd3b84c9438a30ec320dafa6fbfb2
+++ mtn-browse 96ddbb57a8aecd5db92c1635b9627410b6402ae7
@@ -49,13 +49,13 @@ use integer;
use strict;
use integer;
-use IPC::Open3;
use Glib qw(FALSE TRUE);
use Gnome2;
use Gtk2 -init;
set_locale Gtk2;
init Gtk2;
use Gtk2::GladeXML;
+use IPC::Open3;
use Monotone::AutomateStdio;
# Temporary debug stuff.
@@ -68,21 +68,30 @@ use constant DIRECTORY => 0x02;
use constant BRANCH => 0x01;
use constant DIRECTORY => 0x02;
-use constant DISPLAY_OF_FILE => 0x04;
-use constant FILE => 0x08;
-use constant REVISION => 0x10;
+use constant DIRECTORY_VIEW => 0x04;
+use constant DISPLAY_OF_FILE => 0x08;
+use constant FILE => 0x10;
+use constant REVISION => 0x20;
# Constants used to represent the different state changes. Read this as
# `what has just been changed' => `what needs to be updated'.
-use constant BRANCH_CHANGED => (REVISION | DIRECTORY | FILE
- | DISPLAY_OF_FILE);
+use constant BRANCH_CHANGED => (REVISION | DIRECTORY | DIRECTORY_VIEW
+ | FILE | DISPLAY_OF_FILE);
use constant DATABASE_CHANGED => 0xff;
-use constant DIRECTORY_CHANGED => (FILE | DISPLAY_OF_FILE);
+use constant DIRECTORY_CHANGED => (DIRECTORY_VIEW | FILE
+ | DISPLAY_OF_FILE);
use constant DISPLAY_OF_FILE_CHANGED => 0x00;
use constant FILE_CHANGED => (DISPLAY_OF_FILE);
-use constant REVISION_CHANGED => (DIRECTORY | FILE | DISPLAY_OF_FILE);
+use constant REVISION_CHANGED => (DIRECTORY | DIRECTORY_VIEW | FILE
+ | DISPLAY_OF_FILE);
+# Constants for the columns within the manifest ListStore widget.
+
+use constant RLS_ICON_COLUMN => 0;
+use constant RLS_NAME_COLUMN => 1;
+use constant RLS_DATE_COLUMN => 2;
+
# The Glade generated widgets object.
# ***** FUNCTIONAL PROTOTYPES FOR THIS FILE *****
@@ -94,6 +103,9 @@ sub get_completion(address@hidden;\%);
sub delete_event_cb($$$);
sub destroy_event_cb($$;$);
sub get_completion(address@hidden;\%);
+sub get_dir_contents(address@hidden@);
+sub manifest_treeview_cursor_changed_cb($$);
+sub manifest_treeview_row_activated_cb($$$$);
sub new_browser_instance();
sub update_browser_state($$);
#
@@ -148,12 +160,18 @@ sub new_browser_instance()
my(@branch_list,
$browser,
+ $renderer,
+ $tv_column,
$div);
$browser = {};
$browser->{mtn} = Monotone::AutomateStdio->new();
$browser->{glade} = Gtk2::GladeXML->new("../mtn-browse.glade");
+ # Flag to stop recursive calling of callbacks.
+
+ $browser->{in_cb} = 0;
+
# Connect Glade registered signal handlers.
$browser->{glade}->signal_autoconnect
@@ -176,13 +194,30 @@ sub new_browser_instance()
$browser->{glade}->get_widget("branch_comboboxentry");
$browser->{directory_combo} =
$browser->{glade}->get_widget("directory_comboboxentry");
+ $browser->{directory_up_button} =
+ $browser->{glade}->get_widget("directory_up_button");
$browser->{revision_combo} =
$browser->{glade}->get_widget("revision_comboboxentry");
- $browser->{revision_treeview} =
- $browser->{glade}->get_widget("revision_browser_treeview");
+ $browser->{manifest_treeview} =
+ $browser->{glade}->get_widget("manifest_browser_treeview");
$browser->{tagged_tick} =
$browser->{glade}->get_widget("tagged_only_checkbutton");
+ # Setup the comboboxentry key release signal handlers.
+
+ $browser->{branch_combo}->child()->
+ signal_connect("key_release_event",
+ \&combo_key_release_event_cb,
+ $browser);
+ $browser->{directory_combo}->child()->
+ signal_connect("key_release_event",
+ \&combo_key_release_event_cb,
+ $browser);
+ $browser->{revision_combo}->child()->
+ signal_connect("key_release_event",
+ \&combo_key_release_event_cb,
+ $browser);
+
# Move the pane separator to a sensible position.
$div = $browser->{glade}->get_widget("browser_hpaned");
@@ -196,7 +231,7 @@ sub new_browser_instance()
$browser->{directory_combo}->
set_model(Gtk2::ListStore->new("Glib::String"));
$browser->{directory_combo}->set_text_column(0);
- $browser->{directory_combo}->set_wrap_width(1);
+ $browser->{directory_combo}->set_wrap_width(2);
$browser->{revision_combo}->
set_model(Gtk2::ListStore->new("Glib::String"));
$browser->{revision_combo}->set_text_column(0);
@@ -204,8 +239,46 @@ sub new_browser_instance()
# Setup the tree view file browser.
-
+ $browser->{manifest_liststore} =
+ Gtk2::ListStore->new("Glib::String", "Glib::String", "Glib::String");
+ $browser->{manifest_treeview}->set_model($browser->{manifest_liststore});
+ $tv_column = Gtk2::TreeViewColumn->new();
+ $tv_column->set_resizable(FALSE);
+ $tv_column->set_sizing("fixed");
+ $tv_column->set_fixed_width(25);
+ $tv_column->set_sort_column_id(RLS_ICON_COLUMN);
+ $renderer = Gtk2::CellRendererPixbuf->new();
+ $tv_column->pack_start($renderer, TRUE);
+ $tv_column->set_attributes($renderer, "stock-id" => RLS_ICON_COLUMN);
+ $browser->{manifest_treeview}->append_column($tv_column);
+
+ $tv_column = Gtk2::TreeViewColumn->new();
+ $tv_column->set_title("File Name");
+ $tv_column->set_resizable(TRUE);
+ $tv_column->set_sizing("fixed");
+ $tv_column->set_fixed_width(180);
+ $tv_column->set_sort_column_id(RLS_NAME_COLUMN);
+ $renderer = Gtk2::CellRendererText->new();
+ $tv_column->pack_start($renderer, FALSE);
+ $tv_column->set_attributes($renderer, "text" => RLS_NAME_COLUMN);
+ $browser->{manifest_treeview}->append_column($tv_column);
+
+ $tv_column = Gtk2::TreeViewColumn->new();
+ $tv_column->set_title("Last Modified");
+ $tv_column->set_resizable(TRUE);
+ $tv_column->set_sizing("fixed");
+ $tv_column->set_sort_column_id(RLS_DATE_COLUMN);
+ $renderer = Gtk2::CellRendererText->new();
+ $tv_column->pack_start($renderer, FALSE);
+ $tv_column->set_attributes($renderer, "markup" => RLS_DATE_COLUMN);
+ $browser->{manifest_treeview}->append_column($tv_column);
+
+ # TODO $browser->{manifest_treeview}->set_enable_search(TRUE);
+ $browser->{manifest_treeview}->set_enable_search(FALSE);
+ $browser->{manifest_treeview}->set_search_equal_func
+ (sub { print "EQUAL\n"; });
+
# Update the browser'a internal state.
update_browser_state($browser, DATABASE_CHANGED);
@@ -236,8 +309,13 @@ sub combo_changed_cb($$)
my($widget, $browser) = @_;
my ($change_state,
- $combo_details);
+ $combo_details,
+ $item,
+ $value);
+ return if ($browser->{in_cb});
+ local $browser->{in_cb} = 1;
+
if ($widget == $browser->{branch_combo})
{
$change_state = BRANCH_CHANGED;
@@ -248,12 +326,36 @@ sub combo_changed_cb($$)
$change_state = REVISION_CHANGED;
$combo_details = $browser->{revision_combo_details};
}
+ elsif ($widget == $browser->{directory_combo})
+ {
+ $change_state = DIRECTORY_CHANGED;
+ $combo_details = $browser->{directory_combo_details};
+ }
+ else
+ {
+ return;
+ }
- $combo_details->{value} = $widget->child()->get_text();
- $combo_details->{completed} = 1;
- $browser->{main_appbar}->set_status("");
- update_browser_state($browser, $change_state);
+ # For some reason best known to itself, Gtk+ calls this callback when the
+ # user presses a key for the first time (but not subsequently) after a
+ # value is selected via the pulldown menu. So we have to guard against
+ # this. Under these circumstances the key release callback is also called.
+ # So, put simply, only do something inside this callback if the value is a
+ # direct match to one in our list.
+ $value = $widget->child()->get_text();
+ foreach $item (@{$combo_details->{list}})
+ {
+ if ($value eq $item)
+ {
+ $combo_details->{value} = $value;
+ $combo_details->{completed} = 1;
+ $browser->{main_appbar}->set_status("");
+ update_browser_state($browser, $change_state);
+ last;
+ }
+ }
+
}
#
##############################################################################
@@ -284,6 +386,7 @@ sub combo_key_release_event_cb($$$)
my($widget, $event, $browser) = @_;
my ($change_state,
+ $combo,
$combo_details,
$completed,
$completion,
@@ -294,25 +397,42 @@ sub combo_key_release_event_cb($$$)
$old_value,
$value);
- if ($widget == $browser->{branch_combo})
+ return FALSE if ($browser->{in_cb});
+ local $browser->{in_cb} = 1;
+
+ if ($widget == $browser->{branch_combo}->child())
{
+ $combo = $browser->{branch_combo};
$change_state = BRANCH_CHANGED;
$combo_details = $browser->{branch_combo_details};
$name = "branch";
}
- elsif ($widget == $browser->{revision_combo})
+ elsif ($widget == $browser->{revision_combo}->child())
{
+ $combo = $browser->{revision_combo};
$change_state = REVISION_CHANGED;
$combo_details = $browser->{revision_combo_details};
$name = "revision";
}
+ elsif ($widget == $browser->{directory_combo}->child())
+ {
+ $combo = $browser->{directory_combo};
+ $change_state = DIRECTORY_CHANGED;
+ $combo_details = $browser->{directory_combo_details};
+ $name = "directory";
+ }
+ else
+ {
+ return FALSE;
+ }
# The user has typed something in then validate it and auto-complete it if
# necessary.
$completed = 0;
$old_completed = $combo_details->{completed};
- $value = $old_value = $widget->child()->get_text();
+ $old_value = $combo_details->{value};
+ $value = $widget->get_text();
if ($value ne $combo_details->{value})
{
@@ -326,6 +446,7 @@ sub combo_key_release_event_cb($$$)
# So that the spacebar triggers auto-complete.
$value =~ s/\s+$//o;
+ $old_value = $value;
$len = length($value);
if (get_completion($value,
@@ -343,8 +464,8 @@ sub combo_key_release_event_cb($$$)
}
$value = $completion;
$len = length($value);
- $widget->child()->set_text($value);
- $widget->child()->set_position(-1);
+ $widget->set_text($value);
+ $widget->set_position(-1);
}
$combo_details->{value} = $value;
@@ -352,10 +473,10 @@ sub combo_key_release_event_cb($$$)
# Update the pulldown choices.
- $widget->get_model()->clear();
+ $combo->get_model()->clear();
foreach $item (@{$combo_details->{list}})
{
- $widget->append_text($item) if ($value eq substr($item, 0, $len));
+ $combo->append_text($item) if ($value eq substr($item, 0, $len));
$combo_details->{completed} = 1
if (! $completed && $value eq $item);
}
@@ -374,6 +495,163 @@ sub combo_key_release_event_cb($$$)
#
##############################################################################
#
+# Routine - directory_up_button_clicked_cb
+#
+# Description - Callback routine called when the user clicks on the up
+# directory button.
+#
+# Data - $widget : The widget object that received the signal.
+# $browser : The browser instance that is associated with
+# this widget.
+#
+##############################################################################
+
+
+
+sub directory_up_button_clicked_cb
+{
+
+ my($widget, $browser) = @_;
+
+ my $value;
+
+ return if ($browser->{in_cb});
+ local $browser->{in_cb} = 1;
+
+ # Simply go up one directory level in the manifest if we aren't already at
+ # the top.
+
+ $value = $browser->{directory_combo_details}->{value};
+ if ($value ne "")
+ {
+ if ($value =~ m/^.+\/.+/o)
+ {
+ ($value) = ($value =~ m/^(.+)\/[^\/]+$/o);
+ }
+ else
+ {
+ $value = "";
+ }
+ $browser->{directory_combo_details}->{value} = $value;
+ $browser->{directory_combo_details}->{completed} = 1;
+ $browser->{directory_combo}->child()->set_text($value);
+ $browser->{main_appbar}->set_status("");
+ update_browser_state($browser, DIRECTORY_CHANGED);
+ }
+
+}
+#
+##############################################################################
+#
+# Routine - manifest_treeview_cursor_changed_cb
+#
+# Description - Callback routine called when the user changes the value of
+# a ComboBoxEntry by entering a character (key release
+# event).
+#
+# Data - $widget : The widget object that received the signal.
+# $event : A Gtk2::Gdk::Event object describing the
+# event that has occurred.
+# $browser : The browser instance that is associated with
+# this widget.
+# Return Value : TRUE if the event has been handled and needs
+# no further handling, otherwise false if the
+# event should carry on through the remaining
+# event handling.
+#
+##############################################################################
+
+
+
+sub manifest_treeview_cursor_changed_cb($$)
+{
+
+ my($widget, $browser) = @_;
+
+ my $iter;
+
+ return if ($browser->{in_cb});
+ local $browser->{in_cb} = 1;
+
+ $iter = $browser->{manifest_liststore}->append();
+ $browser->{manifest_liststore}->set($iter,
+ RLS_ICON_COLUMN, "gtk-open",
+ RLS_NAME_COLUMN, "the-main-dir",
+ RLS_DATE_COLUMN, "2005-01-01");
+ $iter = $browser->{manifest_liststore}->append();
+ $browser->{manifest_liststore}->set($iter,
+ RLS_ICON_COLUMN, "gtk-open",
+ RLS_NAME_COLUMN, "another-main-dir",
+ RLS_DATE_COLUMN, "2005-02-01");
+ foreach (1..5)
+ {
+ $iter = $browser->{manifest_liststore}->append();
+ $browser->{manifest_liststore}->set($iter,
+ RLS_ICON_COLUMN, "gtk-file",
+ RLS_NAME_COLUMN, "filexxxxxxxxxxxxxxxxxxddddddddskjhdkshskjhdjshdjshdkshdkshdskjd",
+ RLS_DATE_COLUMN, "2005-02-01");
+ }
+
+
+
+ print "CC " . scalar(@_) . "\n";
+ return FALSE;
+ print "CC : " . Dumper address@hidden;
+ return FALSE;
+
+
+}
+#
+##############################################################################
+#
+# Routine - manifest_treeview_row_activated_cb
+#
+# Description - Callback routine called when the user changes the value of
+# a ComboBoxEntry by entering a character (key release
+# event).
+#
+# Data - $widget : The widget object that received the signal.
+# $event : A Gtk2::Gdk::Event object describing the
+# event that has occurred.
+# $browser : The browser instance that is associated with
+# this widget.
+# Return Value : TRUE if the event has been handled and needs
+# no further handling, otherwise false if the
+# event should carry on through the remaining
+# event handling.
+#
+##############################################################################
+
+
+
+sub manifest_treeview_row_activated_cb($$$$)
+{
+
+ my($widget, $tree_path, $tree_view_column, $browser) = @_;
+
+ my $iter;
+
+ return if ($browser->{in_cb});
+ local $browser->{in_cb} = 1;
+
+ $browser->{manifest_liststore}->clear();
+
+ $iter = $browser->{manifest_liststore}->append();
+ $browser->{manifest_liststore}->set($iter,
+ RLS_ICON_COLUMN, "gtk-open",
+ RLS_NAME_COLUMN, "the-main-dir",
+ RLS_DATE_COLUMN, "2005-01-01");
+ $iter = $browser->{manifest_liststore}->append();
+
+ print "RA " . scalar(@_) . "\n";
+ return FALSE;
+ print "RA : " . Dumper address@hidden;
+ return FALSE;
+
+}
+#
+##############################################################################
+#
# Routine - delete_event_cb
#
# Description - Callback routine called when the used has attempted to
@@ -455,6 +733,8 @@ sub update_browser_state($$)
my($browser, $changed) = @_;
+ # The list of available branches has changed.
+
if ($changed & BRANCH)
{
@@ -474,15 +754,17 @@ sub update_browser_state($$)
# Update the branch list combobox.
- $browser->{branch_combo}->child()->set_text("");
$browser->{branch_combo}->get_model()->clear();
foreach $branch (@branch_list)
{
$browser->{branch_combo}->append_text($branch);
}
+ $browser->{branch_combo}->child()->set_text("");
}
+ # The list of available revisions has changed.
+
if ($changed & REVISION)
{
@@ -510,20 +792,107 @@ sub update_browser_state($$)
# Update the revision list combobox.
- $browser->{revision_combo}->child()->set_text("");
$browser->{revision_combo}->get_model()->clear();
foreach $revision (@revision_list)
{
$revision = "i:" . $revision;
$browser->{revision_combo}->append_text($revision);
}
+ $browser->{revision_combo}->child()->set_text("");
}
+ # The list of available files and directories has changed.
+
if ($changed & DIRECTORY)
{
+
+ my(@directory_list,
+ $item,
+ @manifest_list,
+ $revision);
+
+ # Reset the directory combo.
+
+ $browser->{directory_combo_details}->{completion_cache} = {};
+ $browser->{directory_combo_details}->{completed} = 0;
+ $browser->{directory_combo_details}->{value} = "";
+
+ # Get the new manifest.
+
+ if ($browser->{revision_combo_details}->{completed})
+ {
+ $revision = $browser->{revision_combo_details}->{value};
+ $revision =~ s/^i://o;
+ $browser->{mtn}->get_manifest_of(address@hidden, $revision);
+ }
+ $browser->{manifest} = address@hidden;
+
+ # Generate a simple list of directories for auto completion.
+
+ foreach $item (@manifest_list)
+ {
+ push(@directory_list, $item->{name})
+ if ($item->{type} eq "directory");
+ }
+ $browser->{directory_combo_details}->{list} = address@hidden;
+
+ # Update the directory list combobox.
+
+ $browser->{directory_combo}->get_model()->clear();
+ foreach $item (@directory_list)
+ {
+ $browser->{directory_combo}->append_text($item);
+ }
+ $browser->{directory_combo}->child()->set_text("");
+
}
+ # The list of displayed files and directories has changed.
+
+ if ($changed & DIRECTORY_VIEW)
+ {
+
+ my(@directory_entry_list,
+ $item);
+
+ # Reset the manifest tree view.
+
+ $browser->{manifest_liststore}->clear();
+
+ # Get the contents of the new directory.
+
+ if ($browser->{directory_combo_details}->{completed}
+ || $browser->{directory_combo_details}->{value} eq "")
+ {
+ get_dir_contents($browser->{directory_combo_details}->{value},
+ @{$browser->{manifest}},
+ @directory_entry_list);
+ }
+ $browser->{directory_entry_list} = address@hidden;
+
+ # Disable the directory up button if we are already at the top level,
+ # otherwise make sure it is enabled.
+
+ $browser->{directory_up_button}->set_sensitive
+ (($browser->{directory_combo_details}->{value} eq "")
+ ? FALSE : TRUE);
+
+ # Update the directory tree view.
+
+ foreach $item (@directory_entry_list)
+ {
+ $browser->{manifest_liststore}->
+ set($browser->{manifest_liststore}->append(),
+ RLS_ICON_COLUMN,
+ ($item->{manifest_entry}->{type} eq "directory")
+ ? "gtk-open" : "gtk-file",
+ RLS_NAME_COLUMN, $item->{name},
+ RLS_DATE_COLUMN, "2005-01-01");
+ }
+
+ }
+
if ($changed & FILE)
{
}
@@ -647,3 +1016,58 @@ sub get_completion(address@hidden;\%)
return 1;
}
+#
+##############################################################################
+#
+# Routine - get_dir_contents
+#
+# Description - Given a path and a Monotone manifest, return a subset of
+# the manifest that represents the contents of just that
+# directory along with the directory entry names.
+#
+# Data - $path : The path to the directory from the top level of
+# the manifest.
+# $manifest : A reference to a Monotone manifest.
+# $result : A reference to a list that is to contain the
+# result (a list of records containing the short
+# directory entry name and a reference to the
+# related manifest entry).
+#
+##############################################################################
+
+
+
+sub get_dir_contents(address@hidden@)
+{
+
+ my($path, $manifest, $result) = @_;
+
+ my($entry,
+ $extract_re,
+ $i,
+ $match_re,
+ $name);
+
+ $i = 0;
+ if ($path eq "")
+ {
+ $match_re = qr/^[^\/]+$/;
+ $extract_re = qr/^([^\/]+)$/;
+ }
+ else
+ {
+ $match_re = qr/^${path}\/[^\/]+$/;
+ $extract_re = qr/^${path}\/([^\/]+)$/;
+ }
+ @$result = ();
+ foreach $entry (@$manifest)
+ {
+ if ($entry->{name} =~ m/$match_re/)
+ {
+ ($name) = ($entry->{name} =~ m/$extract_re/);
+ $$result[$i ++] = {manifest_entry => $entry,
+ name => $name};
+ }
+ }
+
+}
============================================================
--- mtn-browse.glade db85aab77dba15a9926d2438b6cc20077013fdb9
+++ mtn-browse.glade 32a19a669843c4ba9f45293d822899dd11c5b1fc
@@ -350,7 +350,6 @@
True
-
0
@@ -402,7 +401,6 @@
True
-
0
@@ -561,6 +559,7 @@ criteria for selecting a revision
True
+
0
@@ -587,6 +586,7 @@ criteria for selecting a revisionTrue
GTK_RELIEF_NORMAL
True
+
@@ -615,7 +615,7 @@ criteria for selecting a revision
-
+
True
True
GTK_POLICY_ALWAYS
@@ -624,13 +624,15 @@ criteria for selecting a revisionGTK_CORNER_TOP_LEFT
-
+
True
True
True
False
- False
+ True
True
+
+
@@ -750,7 +752,7 @@ criteria for selecting a revisionName of the file being displayed
1
1
- 0 0 277 10 249.3 277
+ 0 0 106 10 95.4 106
0 0 17 10 15.3 17
@@ -802,7 +804,7 @@ criteria for selecting a revisionDate of when file was last changed
1
1
- 0 0 277 10 249.3 277
+ 0 0 106 10 95.4 106
0 0 17 10 15.3 17
@@ -918,7 +920,7 @@ criteria for selecting a revisionFile's unique id in database
1
1
- 0 0 283 10 254.7 283
+ 0 0 112 10 100.8 112
0 0 17 10 15.3 17
@@ -971,7 +973,7 @@ file was last changed
file was last changed
1
1
- 0 0 283 10 254.7 283
+ 0 0 112 10 100.8 112
0 0 17 10 15.3 17