OK, so here is one for you wxPerl whizzes out there. I really need to figure 
this out. I have a derived class which has the following override function for 
AutoSizeColumn(). There is also one for AutoSizeRow(), but I’m going to focus 
on this one as I believe this is where my issue is occurring.  I have a program 
which shows a grid which updates every 10 seconds, which includes AutoSize’ing 
the grid. Over a period of time, (like say 1 hour),  something is happening 
which includes a small memory leak, but something more profound with X11. When 
the program is quit, it will hang for a while, but only if SMART_AUTOSIZE is 
set to 2. If it is zero, or 1 it works fine, but when set to 2 it causes 
something to happen that is either a strict memory leak or some excess 
chattiness with the X11 server.  If used with Exceed on OSX, it will cause it 
to lock up the server altogether, to the point it requires to be killed (-9).

The only thing I can see materially different here is that when SMART_AUTOSIZE 
is 2, then the current column label is split into words, and the maximum word 
width is determined, then WrapColLabelValue() is called which ultimately wraps 
the column label value to the width of the column. Any clues?

I’m using WxWidgets 2.8.10

Here is the code:

sub AutoSizeColumn
{
        my $self = shift;
        my $col = shift;
        my $setAsMin = shift;
        return if $self->IsColHidden($col);
        return $self->SUPER::AutoSizeColumn($col,$setAsMin) unless 
$self->{SMART_AUTOSIZE};
        my $cwc = defined $self->{COLUMN_WRAP}{$col}{MODE} ? $col : 'ALL';
        if ($self->{COL_SIZE}{$col}) {
                Debug("fixed col size.. wrapping");
                $self->SetColSize($col,$self->{COL_SIZE}{$col});
                $self->WrapColumnValues($col) if 
$self->{COLUMN_WRAP}{$cwc}{MODE};
                return;
        }
        my $nr = $self->GetNumberRows() - 1;
        my $clv = $self->SUPER::GetColLabelValue($col);
        my @hdr = $self->{SMART_AUTOSIZE} == 2 ? split(/\s+/,$clv) : ($clv);
        if ($hdr[-1] eq '/\\' or $hdr [-1] eq '\\/') {
                $hdr[-2] .= ' ' . $hdr[-1];
                pop @hdr;
        }
        my $lfont = $self->GetLabelFont();
        my $w = $self->{HIDE_COLUMN_LABEL} ? 0 : Max(map { 
($self->GetTextExtent($_,$lfont))[0] } @hdr);
        Debug("$col. $clv: w=$w");
        for my $r (0..$nr) {
                next if $self->IsRowHidden($r);
                my $v = $self->{COLUMN_WRAP}{$cwc}{MODE} ? 
($self->{COLUMN_WRAP}{$cwc}{WIDTH}
                        ? $self->WrapCellValue($r,$col) : 
$self->UnwrapCellValue($r,$col)) : $self->GetCellValue($r,$col);
                next unless $v;
                $w = 
Max($w,($self->GetTextExtent($v,$self->GetCellFont($r,$col)))[0]);
                Debug("v='$v' w=$w");
        }
        if ($w) {
                $self->SetColSize($col,$w + GRID_SIZE_PAD);
                $self->WrapColLabelValue($col) if $self->{SMART_AUTOSIZE} == 2;
        } else {
                $self->SUPER::AutoSizeColumn($col,$setAsMin);
        }
}

#       WrapColLabelValue( <col> )
#       If the column has a fixed width, then wrap the Column label contents at 
space boundaries to fit.
sub WrapColLabelValue
{
        my $self = shift;
        my $col = shift;
        my $w = $self->GetColSize($col);
        my $val = units::unWrapString($self->SUPER::GetColLabelValue($col),1);
        return unless $val;
        my $font = $self->GetLabelFont();
        my ($sx,$sy,$descent,$el) = new 
Wx::Window($self,-1)->GetTextExtent($val,$font);
        my $nw = int(length($val)/$sx*$w) - 2;
        my $sw = units::wrapString($val,'\s+',$nw,1);
        $sw =~ s/\n([\/\\]+)$/ $1/;
        $self->SUPER::SetColLabelValue($col,$sw);
        return 0;
}

#       wrapString( <string>, <delimiter>, <width> [, <mode> ] )
#       <string>        string to be wrapped
#       <delimiter> regex expression for delimiter
#       <width>         max width of the output in characters (string will be 
wrapped to not exceed this value)
#       <mode>          If set, then space delimiters will be compressed (IE: ' 
  ' --> ' ').
#
#       Returns the wrapped string.
sub wrapString
{
        my $str = shift;
        my $d = shift;
        my $w = shift;
        my $mode = shift;
        
        return '' unless defined $str;
        my @tok = split /$d/,$str;
        my @del = $str =~ /($d)/g;
        my $nstr = '';
        my $sw = 0;
        my $s = $mode ? '\s*' : '';
        for my $t (@tok) {
                my $d = pop @del;
                $d = '' if not defined $d;
                $nstr =~ s/$s$/\n/,$sw=0 if $sw and ($sw + length($t.$d)) > $w;
                $nstr .= $t.$d;
                $sw += length($t.$d);
        }
        return $nstr;
}


#       unWrapString( <string> [, <mode> ] )
#       Unwrap the string. If <mode> is set, then add space 
#       character in place of line feed
sub unWrapString
{
        my $str = shift;
        my $mode = shift;
        my $d = $mode ? ' ' : '';
        $str =~ s/\n/$d/g;
        return $str;
}

---------------------------------
Jim Clark
Senior Software Engineer, EES
Apple, Inc 
408-974-9906 (office)
408-781-1425 (cell)

** Converting pizza into code for over 20 years **

Reply via email to