# Copyright 2008 Kevin Ryde
# This file is part of Gtk2-Ex-TreeModelFilter-DragDest.
#
# Gtk2-Ex-TreeModelFilter-DragDest 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-TreeModelFilter-DragDest 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-TreeModelFilter-DragDest. If not, see
# .
package Gtk2::Ex::TreeModelFilter::DragDest;
use strict;
use warnings;
use Gtk2;
use Carp;
our $VERSION = 1;
use constant DEBUG => 0;
# gtk_tree_drag_dest_row_drop_possible
# gtk_tree_drag_dest_drag_data_received
#
# The two funcs are delegated to the child model the same way, just the
# method used when found differs.
#
sub ROW_DROP_POSSIBLE {
push @_, 'row_drop_possible';
goto &_drop;
}
sub DRAG_DATA_RECEIVED {
push @_, 'drag_data_received';
goto &_drop;
}
sub _drop {
my ($self, $path, $sel, $method) = @_;
if (DEBUG) { print "Filter::DragDest ",uc($method)," to path=",
$path->to_string," type=",$sel->type->name,"\n";
if ($sel->type->name eq 'GTK_TREE_MODEL_ROW') {
my ($src_model, $src_path) = $sel->get_row_drag_data;
print " src_model=$src_model src_path=",
$src_path->to_string,", has DragDest=",
$src_model->isa('Gtk2::TreeDragDest')?"yes":"no", "\n";
}}
# See if there's a TreeDragDest capable child. Do this before building a
# child path, since path conversions can be expensive.
#
my $submodel = $self;
for (;;) {
$submodel = $submodel->get_model || do {
if (DEBUG) { print " no TreeDragDest child\n"; }
return;
};
if ($submodel->isa('Gtk2::TreeDragDest')) {
last;
}
if (! $submodel->isa('Gtk2::TreeModelFilter')) {
if (DEBUG) { print " no TreeDragDest child\n"; }
return;
}
}
# Same again, building $subpath.
#
$submodel = $self;
my $subpath = $path;
for (;;) {
$subpath = _path_to_child_path_or_end ($submodel, $subpath)
|| do { if (DEBUG) { print " no subpath\n"; }
return 0;
};
$submodel = $submodel->get_model
or return; # oops, wasn't this ok in the loop above!
if ($submodel->isa('Gtk2::TreeDragDest')) {
last;
}
if (! $submodel->isa('Gtk2::TreeModelFilter')) {
return; # oops, wasn't this ok in the loop above!
}
}
if (DEBUG) { print " drop on $submodel, path=",$subpath->to_string,"\n"; }
my $ret = $submodel->$method ($subpath, $sel);
if (DEBUG) { print " ", $ret?"yes":"no","\n"; }
return $ret;
}
sub _path_to_child_path_or_end {
my ($self, $path) = @_;
my $subpath = $self->convert_path_to_child_path ($path);
if (! $subpath) {
$path = $path->copy;
if ($path->up) {
$subpath = $self->convert_path_to_child_path ($path);
if ($subpath) {
my $model = $self->get_model;
my $subiter = ($subpath->get_depth == 0 ? undef
: $model->get_iter ($subpath));
my $n = $model->iter_n_children ($subiter);
if (DEBUG) { print " follow to end of subpath=",
$subpath->to_string||'none'," n=$n\n"; }
$subpath->append_index ($n);
}
}
}
return $subpath;
}
1;
__END__
=head1 NAME
Gtk2::Ex::TreeModelFilter::DragDest -- drag destination mix-in for TreeModelFilter subclasses
=head1 SYNOPSIS
package MyNewFilterModel;
use Gtk2;
use base 'Gtk2::Ex::TreeModelFilter::DragDest';
use Glib::Object::Subclass
Gtk2::TreeModelFilter::,
interfaces => [ 'Gtk2::TreeDragDest' ];
=head1 DESCRIPTION
C provides the following two functions
to implement the C interface in a sub-class of
C.
ROW_DROP_POSSIBLE
DRAG_DATA_RECEIVED
They're designed as a multiple-inheritance mix-in, so you put
C in your C<@ISA>, then add
C to the C in your C