The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#!/usr/bin/perl -w

# Copyright 2008, 2009, 2010, 2011 Kevin Ryde

# This file is part of Gtk2-Ex-MenuView.
#
# Gtk2-Ex-MenuView 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 3, or (at your option) any later
# version.
#
# Gtk2-Ex-MenuView 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 Gtk2-Ex-MenuView.  If not, see <http://www.gnu.org/licenses/>.

use 5.010;
use strict;
use warnings;
use Glib 1.220;
use Gtk2 '-init';
use Gtk2::Ex::MenuView;
use Data::Dumper;

use FindBin;
my $progname = $FindBin::Script;

my $toplevel = Gtk2::Window->new('toplevel');
$toplevel->signal_connect (destroy => sub { Gtk2->main_quit });

my $hbox = Gtk2::HBox->new (0, 0);
$toplevel->add ($hbox);

my $left_vbox = Gtk2::VBox->new (0, 0);
$hbox->pack_start ($left_vbox, 0,0,0);

my $right_vbox = Gtk2::VBox->new (0, 0);
$hbox->pack_start ($right_vbox, 1,1,0);

my $treestore = Gtk2::TreeStore->new ('Glib::String');
foreach my $str ('Item one',
                 'Item two',
                 'Item three',
                 'Item four',
                 'Item five') {
  $treestore->set ($treestore->append(undef), 0 => $str);
}

my $menuview = Gtk2::Ex::MenuView->new (model => $treestore);

{
  my $tearoff = Gtk2::TearoffMenuItem->new;
  $tearoff->show;
  $menuview->prepend ($tearoff);
}

$menuview->signal_connect (item_create_or_update => \&do_item_create_or_update);
sub do_item_create_or_update {
  my ($menuview, $item, $model, $path, $iter) = @_;
  print "$progname: create/update\n";
  if (! $item) {
    $item = Gtk2::MenuItem->new_with_label ('');
  }
  my $label = $item->get_child;
  my $str = $model->get_value ($iter, 0);
  print "$progname: data $item path ",$path->to_string,
    " str \"", defined $str ? $str : 'undef', "\"\n";
  $label->set_text ($str);
  print "  return $item\n";
  return $item;
}

$menuview->signal_connect (activate => sub {
                             my ($menuview, $item, $model, $path, $iter) = @_;
                             print "$progname: activate ",Dumper(\@_);
                             print "  path ",$path->to_string,"\n";
                           });
my $treeview = Gtk2::TreeView->new_with_model ($treestore);
$treeview->set (reorderable => 1);
$right_vbox->pack_start ($treeview, 1,1,0);
{
  my $renderer = Gtk2::CellRendererText->new;
  $renderer->set (editable => 1);
  $renderer->signal_connect
    (edited => sub {
       print Dumper(\@_);
       my ($renderer, $pathstr, $newstr) = @_;
       my $path = Gtk2::TreePath->new_from_string ($pathstr);
       my $iter = $treestore->get_iter ($path);
       $treestore->set_value ($iter, 0 => $newstr);
     });

  my $column = Gtk2::TreeViewColumn->new_with_attributes
    ("TreeView:", $renderer, text => 0);
  $column->set (resizable => 1);
  $treeview->append_column ($column);
}

{
  my $menubar = Gtk2::MenuBar->new;
  $left_vbox->pack_start ($menubar, 0,0,0);
  my $item = Gtk2::MenuItem->new_with_label ('Menu');
  $item->set_submenu ($menuview);
  $menubar->add ($item);
}
{
  my $label = Gtk2::Label->new (' ');
  $left_vbox->add ($label);
}
{
  my $button = Gtk2::Button->new_with_label ('Append');
  $button->signal_connect
    (clicked => sub {
       $treestore->set ($treestore->append(undef), 0 =>  rand());
     });
  $left_vbox->pack_start ($button, 0,0,0);
}
{
  my $button = Gtk2::Button->new_with_label ('Insert Second');
  $button->signal_connect
    (clicked => sub {
       $treestore->insert_with_values (undef, 1, 0 => rand());
     });
  $left_vbox->pack_start ($button, 0,0,0);
}
{
  my $button = Gtk2::Button->new_with_label ('Insert Subrow');
  $button->signal_connect
    (clicked => sub {
       my $parent = $treestore->iter_nth_child (undef, 1);
       $treestore->insert_with_values ($parent, 0, 0 => rand());
     });
  $left_vbox->pack_start ($button, 0,0,0);
}
{
  my $button = Gtk2::Button->new_with_label ('Delete');
  $button->signal_connect
    (clicked => sub {
       my $iter = $treestore->get_iter (Gtk2::TreePath->new(2));
       if ($iter) { $treestore->remove ($iter); }
     });
  $left_vbox->pack_start ($button, 0,0,0);
}
{
  my $button = Gtk2::Button->new_with_label ('Reorder Up');
  $button->signal_connect
    (clicked => sub {
       my $len = $treestore->iter_n_children (undef);
       my $end = $len - 1;
       $treestore->reorder (1 .. $end, 0);
     });
  $left_vbox->pack_start ($button, 0,0,0);
}
{
  my $button = Gtk2::Button->new_with_label ('Reorder Down');
  $button->signal_connect
    (clicked => sub {
       my $len = $treestore->iter_n_children (undef);
       my $end = $len - 1;
       $treestore->reorder ($end, 0 .. $end-1);
     });
  $left_vbox->pack_start ($button, 0,0,0);
}
{
  my $button = Gtk2::Button->new_with_label ('New Model');
  $button->signal_connect
    (clicked => sub {
       print "$progname: new model in 3 seconds\n";
       Glib::Timeout->add
           (3_000, # 3 seconds
            sub {
              print "$progname: new model now\n";
              $treestore = treestore_copy_model($treestore);
              $menuview->set (model => $treestore);
              $treeview->set (model => $treestore);
              return Glib::SOURCE_REMOVE;
            });
     });
  $left_vbox->pack_start ($button, 0,0,0);
}
{
  my $combobox = Gtk2::ComboBox->new_with_model ($treestore);
  $combobox->set (add_tearoffs => 1);
  $left_vbox->pack_start ($combobox, 0,0,0);
  my $renderer = Gtk2::CellRendererText->new;
  $renderer->set (xalign => 1); # right align
  $combobox->pack_start ($renderer, 1);
  $combobox->add_attribute ($renderer, text => 0);
}

$menuview->popup (undef, undef, undef, undef, 0, 0);
print "$progname: children ",$menuview->get_children,"\n";

$toplevel->show_all;
Gtk2->main;
exit 0;


#------------------------------------------------------------------------------

# return a new Gtk2::TreeStore which is a copy of the $model contents
sub treestore_copy_model {
  my ($model) = @_;
  require Gtk2::Ex::TreeModelBits;
  my $treestore = Gtk2::TreeStore->new
    (Gtk2::Ex::TreeModelBits::all_column_types ($model));
  my @columns = (0 .. $model->get_n_columns - 1);
  $model->foreach
    (sub {
       my ($model, $path, $iter) = @_;
       my $treepath = $path->copy;
       $treepath->up;
       my $treeiter;
       if ($treepath->get_depth) {
         $treeiter = $treestore->get_iter($treepath);
       }
       print "$progname: copy ",$path->to_string," to append ",$treepath->to_string//'top',"\n";
       $treestore->insert_with_values ($treeiter, -1,
                                       map { ($_, $model->get($iter,$_)) }
                                       @columns);
       return 0; # keep traversing
     });
  return $treestore;
}