File Coverage

blib/lib/CPANPLUS/Shell/Wx/ModuleTree.pm
Criterion Covered Total %
statement 1 3 33.3
branch n/a
condition n/a
subroutine 1 1 100.0
pod n/a
total 2 4 50.0


line stmt bran cond sub pod time code
1              
2             package CPANPLUS::Shell::Wx::ModuleTree;
3              
4 0           use Wx qw/wxPD_APP_MODAL wxPD_APP_MODAL wxPD_CAN_ABORT
5             wxPD_ESTIMATED_TIME wxPD_REMAINING_TIME wxLIST_AUTOSIZE
6 1     1   2539 wxVSCROLL wxALWAYS_SHOW_SB wxUPDATE_UI_RECURSE /;
  0            
7             use Wx::Event qw(EVT_CONTEXT_MENU EVT_WINDOW_CREATE EVT_BUTTON
8             EVT_TREE_SEL_CHANGED EVT_TREE_ITEM_ACTIVATED EVT_RIGHT_DOWN
9             EVT_TREE_ITEM_RIGHT_CLICK);
10             use Wx::ArtProvider qw/:artid :clientid/;
11              
12             use Data::Dumper;
13             use YAML qw/LoadFile Load/;
14             use File::Spec;
15             use File::Path;
16             use Storable;
17              
18             use threads;
19             use LWP::Simple;
20             use Wx::Locale gettext => '_T';
21              
22             use CPANPLUS::Shell::Wx::util;
23              
24             #the base class
25             use base 'Wx::TreeCtrl';
26              
27             BEGIN {
28             use vars qw( @ISA $VERSION);
29             @ISA = qw( Wx::TreeCtrl);
30             $VERSION = '0.01';
31             }
32              
33             #use some constants to better identify what's going on,
34             #so we can do stuff like:
35             # $self->{'sort'}=(SORTBY)[CATEGORY]; #sort by category
36              
37             use constant SORTBY => (_T("Author"), _T("Name"), _T("Category"));
38             use constant {AUTHOR=>0,NAME=>1,CATEGORY=>2};
39             use constant SHOW => (_T("Installed"),_T("Updated"),_T("New"),_T("All")) ;
40             use constant {INSTALLED=>0,UPDATES=>1,NEW=>2,ALL=>3};
41             use constant MAX_PROGRESS_VALUE => 100000; #the max value of the progressdialogs
42              
43              
44             sub new {
45             my $class = shift;
46             my $self = $class->SUPER::new(); # create an 'empty' TreeCtrl object
47              
48             #set default behavior
49             $self->{'sort'}=(SORTBY)[CATEGORY]; #DEFAULT: sort by category
50             # $self->{'sort'}=(SORTBY)[AUTHOR]; #sort by author
51             # $self->{'sort'}=(SORTBY)[NAME]; #sort by module name
52             $self->{'show'}=(SHOW)[INSTALLED];
53             # $self->{'show'}=(SHOW)[UPDATES]; #DEFAULT: List Updated Modules
54             # $self->{'show'}=(SHOW)[NEW];
55             # $self->{'show'}=(SHOW)[ALL];
56              
57             #this is the thread reference to the info gathering method
58             #this is started ad stopped when the listbox's selection is changed
59             #threads may be removed in the future or not used at all.
60             $self->{_threads}=();
61              
62             #setup category names for further use.
63             #(they will be used to create hashes)
64             $self->{catNames}=[
65             _T("Not In Modulelist"), _T("Perl Core Modules"),
66             _T("Language Extensions"), _T("Development Support"),
67             _T("Operating System Interfaces"), _T("Networking Devices, IPC"),
68             _T("Data Type Utilities"), _T("Database Interfaces"),
69             _T("User Interfaces"), _T("Language Interfaces"),
70             _T("File Names, Systems Locking"), _T("String/Language/Text Processing"),
71             _T("Options/Arguments/Parameters Processing"), _T("Internationalization, Locale"),
72             _T("Security and Encryption"), _T("World Wide Web, HTML, HTTP, CGI"),
73             _T("Server and Daemon Utilities"), _T("Archiving and Compression"),
74             _T("Images, Pixmaps, Bitmaps"), _T("Mail and Usenet News"),
75             _T("Control Flow Utilities"), _T("File Handle Input/Output"),
76             _T("Microsoft Windows Modules"), _T("Miscellaneous Modules"),
77             _T("Commercial Software Interfaces"), _T("Bundles"),
78             _T("Documentation"), _T("Pragma"),
79             _T("Perl6")];
80              
81             #add the root item.It is hidden.
82             $self->AddRoot(_T('Modules'));
83              
84             #create links to events
85             # EVT_WINDOW_CREATE( $self, $self, \&OnCreate ); #when the tree is created
86             EVT_TREE_SEL_CHANGED( $self, $self, \&OnSelChanged); #when a user changes the selection
87             EVT_TREE_ITEM_ACTIVATED($self, $self, \&OnDblClick); #When the user double-clicks an item
88             EVT_TREE_ITEM_RIGHT_CLICK( $self, $self, \&ShowPopupMenu );#when the user wants a pop-up menu
89             $self->SetWindowStyleFlag($self->GetWindowStyleFlag()|wxVSCROLL);
90              
91             return $self;
92             }
93              
94             #this is called when the control is created.
95             #sub OnCreate {
96             sub Init {
97             my $self = shift;
98             my ($event)=@_;
99              
100             #get references so we can access them easier
101             # $self->{parent}=Wx::Window::FindWindowByName('main_window');
102             # $self->{parent}=$self->GetParent();
103             # $self->{cpan}=$self->{parent}->{cpan};
104             # $self->{config}=$self->{cpan}->configure_object();
105              
106             #$self->AssignImageList($imgList);
107              
108             # Wx::Window::FindWindowByName('info_prereqs')->AssignImageList($imgList);
109             #show info on what we are doing
110             Wx::LogMessage _T("Showing "),$self->{'show'},_T(" by "),$self->{'sort'};
111              
112             #go ahead and get the list of categories
113             $self->{category_list}=$self->_get_categories();
114              
115             #$self->{statusBar}=Wx::Window::FindWindowByName('main_window_status');
116              
117             #populate tree with default values
118             #$self->Populate();
119              
120             #$self->{podReader}=$self->{parent}->{podReader} || CPANPLUS::Shell::Wx::PODReader::Frame->new($self);
121              
122             $self->SetWindowStyle($self->GetWindowStyleFlag()|wxVSCROLL|wxALWAYS_SHOW_SB);
123             _uShowErr;
124             }
125              
126             ###############################
127             ####### PUBLIC METHODS ########
128             ###############################
129             #these methods are called from outside to display the relevant modules
130             sub ShowInstalled{shift->_switch_show(INSTALLED)}
131             sub ShowUpdated{shift->_switch_show(UPDATES)}
132             sub ShowNew{shift->_switch_show(NEW)}
133             sub ShowAll{shift->_switch_show(ALL)}
134             sub SortByAuthor{shift->_switch_sort(AUTHOR)}
135             sub SortByName{shift->_switch_sort(NAME)}
136             sub SortByCategory{shift->_switch_sort(CATEGORY)}
137              
138             #the following methods are for setting the event handlers for the various
139             # menu items in the context menu. They all take one parameter:a code ref
140             #The code ref is then executed with three parameters:
141             # the menu [Wx::Menu], the event [Wx::CommandEvent], and the name of the selected module
142             sub SetInfoHandler{$_[0]->{_minfoHandler}=$_[1];}
143             sub SetInstallMenuHandler{print "Install: ",@_;$_[0]->{_minstallHandler}=$_[1];}
144             sub SetUpdateMenuHandler{$_[0]->{_mupdateHandler}=$_[1];}
145             sub SetUninstallMenuHandler{$_[0]->{_muninstallHandler}=$_[1];}
146             sub SetFetchMenuHandler{$_[0]->{_mfetchHandler}=$_[1];}
147             sub SetPrepareMenuHandler{$_[0]->{_mprepareHandler}=$_[1];}
148             sub SetBuildMenuHandler{$_[0]->{_mbuildHandler}=$_[1];}
149             sub SetTestMenuHandler{$_[0]->{_mtestHandler}=$_[1];}
150             sub SetExtractMenuHandler{$_[0]->{_mextractHandler}=$_[1];}
151             sub SetClickHandler{$_[0]->{_clickHandler}=$_[1];}
152             sub SetDblClickHandler{print "DblClick:",@_,"\n";$_[0]->{_dblClickHandler}=$_[1];}
153             sub SetStatusBar{$_[0]->{statusBar}=$_[1];}
154             sub SetMenu{$_[0]->{menu}=$_[1];}
155             sub GetName{return $_[0]->{thisName}}
156             sub GetMod{return $_[0]->{thisMod}}
157             sub SetCPP{$_[0]->{cpan}=$_[1];$_[0]->{config}=$_[1]->configure_object();}
158              
159             #this is called when the user right-clicks on an item in the tree
160             sub ShowPopupMenu{
161             my $self = shift;
162             my ($event)=@_;
163              
164             #we can't do any actions on unknown modules
165             return if $self->GetItemImage($event->GetItem()) == 4;
166             #create the menu
167             $menu = CPANPLUS::Shell::Wx::ModuleTree::Menu->new($self,$event->GetItem());
168             #show the menu
169             $self->PopupMenu($menu,$event->GetPoint());
170             }
171              
172              
173             #this is called when the user double-clicks on an item in the tree
174             sub OnDblClick{
175             my $self = shift;
176             my ($event)=@_;
177             #we can't do any actions on unknown modules
178             my $img=$self->GetItemImage($event->GetItem());
179             print "Double Click!:".$self->{_dblClickHandler}." img = $img\n";
180             return if $img == 4;
181             &{$self->{_dblClickHandler}}(@_) if $self->{_dblClickHandler};
182             }
183             #this method calls the other methods to populate the tree
184             sub Populate{
185             my $self = shift;
186              
187             $self->OnSelChanged(); #clear all values in Info pane
188             $self->DeleteAllItems(); #clear all items in tree
189              
190             #add the root item with the name of what we are showing
191             my $root=$self->AddRoot($self->{'show'});
192              
193             #tell the user we are populating the list
194             $self->{statusBar}->SetStatusText(_T("Populating List..").$self->{'show'}._T(" By ").$self->{'sort'});
195              
196             #call the appropriate method for displaying the modules
197             if ($self->{'sort'} eq (SORTBY)[AUTHOR]){
198             $self->_show_installed_by_author() if ( $self->{'show'} eq (SHOW)[INSTALLED]);
199             $self->_show_updates_by_author() if ( $self->{'show'} eq (SHOW)[UPDATES]);
200             $self->_show_new_by_author() if ( $self->{'show'} eq (SHOW)[NEW]);
201             $self->_show_all_by_author() if ( $self->{'show'} eq (SHOW)[ALL]);
202             }
203             if ($self->{'sort'} eq (SORTBY)[NAME]){
204             $self->_show_installed_by_name() if ( $self->{'show'} eq (SHOW)[INSTALLED]);
205             $self->_show_updates_by_name() if ( $self->{'show'} eq (SHOW)[UPDATES]);
206             $self->_show_new_by_name() if ( $self->{'show'} eq (SHOW)[NEW]);
207             $self->_show_all_by_name() if ( $self->{'show'} eq (SHOW)[ALL]);
208             }
209             if ($self->{'sort'} eq (SORTBY)[CATEGORY]){
210             $self->_show_installed_by_category() if ( $self->{'show'} eq (SHOW)[INSTALLED]);
211             $self->_show_updates_by_category() if ( $self->{'show'} eq (SHOW)[UPDATES]);
212             $self->_show_new_by_category() if ( $self->{'show'} eq (SHOW)[NEW]);
213             $self->_show_all_by_category() if ( $self->{'show'} eq (SHOW)[ALL]);
214             }
215              
216             #show any errors generated by CPANPLUS
217             _uShowErr;
218             }
219              
220             #update only info tab in the lower notebook and clear other items
221             sub OnSelChanged{
222             my ($self,$event)=@_;
223              
224             #set global variable for name of what the user selected
225             $self->{thisName}=$self->GetItemText($self->GetSelection());
226             #set global variable for CPANPLUS::Module object of what the user selected
227             $self->{thisMod}=$self->_get_mod($self->{thisName});
228             #return if we can't get an object reference
229             return unless $self->{thisMod};
230             &{$self->{_clickHandler}}($self,$event) if $self->{_clickHandler};
231             }
232              
233             #this method check to see which prerequisites have not been met
234             # We only want recursion when a prereq is NOT installed.
235             #returns a list of prerequisites, in reverse install order
236             # i.e. $list[-1] needs to be installed first
237             sub CheckPrerequisites{
238             my $self=shift;
239             my $modName=shift;
240             my $version=shift||'';
241             my $pre=$self->GetPrereqs($modName,$version);
242             # print Dumper $pre;
243             # return;
244             my @updates=();
245             foreach $name (@$pre){
246             my $mod=$self->_get_mod($name);
247             next unless $mod;
248             if ($mod->installed_version && $mod->installed_version >= $mod->version){
249             $self->{statusBar}->SetStatusText($mod->name." v".$mod->installed_version._T(" is sufficient."));
250             }else{
251             $self->{statusBar}->SetStatusText($mod->name." v".$mod->installed_version._T(" needs to be updated to ").$name);
252             push (@updates,$name);
253             push (@updates,$self->CheckPrerequisites($name));
254             }
255             }
256             $self->{statusBar}->SetStatusText('');
257             return @updates;
258             }
259              
260             #this method fetches the META.yml file from
261             #search.cpan.org and parses it using YAML.
262             #It returns the Prerequisites for the given module name
263             # or the currently selected module, if none given.
264             # It stores the yml data in the same hierarchy as CPANPLUS
265             #stores its readme files and other data.
266             #returns: a list of modules that can be parsed by parse_module()
267             sub GetPrereqs{
268             my $self=shift;
269             my $modName=shift || $self->{thisName};
270             my $version=shift||'';
271             # print "GetPrereqs($modName) \n ";
272             my $mod=$self->_get_mod($modName,$version);
273             # print $modName.(($version)?"-$version":'')."\n";
274             # print Dumper $mod;
275             return unless $mod; #if we can't get a module from the name, return
276              
277             #set up the directory structure fro storing the yml file
278             my $storedDir=_uGetPath($self->{config},'cpp_mod_dir'); #the top-level directory for storing files
279             my $author=$mod->author->cpanid; #get the cpanid of the author
280             my @split=split('',$author); #split the author into an array so we can:
281             my $dest=File::Spec->catdir($storedDir,$split[0],$split[0].$split[1],$author); #extract the first letters
282             my $package=$mod->package_name.'-'.$mod->package_version; #name the file appropriately
283             $dest=File::Spec->catfile($dest,"$package.yml");
284             my $src="http://search.cpan.org/src/$author/$package/META.yml"; #where we are getting the file from
285              
286             my $ymldata=''; #the yaml data
287             #if we already have this file, read it. Otherwise, get it from web
288             if (-e $dest){
289             $ymldata=LoadFile($dest);
290             }else{
291             mkpath($dest,0,0775) unless (-d $dest); #create the path
292             my $yml=getstore($src,$dest) ; #get and store the yaml file
293             $yml=get($src); #get the file. TODO add test for existence of yaml file
294             $ymldata=Load($yml); #load the data
295             }
296              
297             #return the prequisites
298             my $reqs=$ymldata->{'requires'}||{};
299             my @ret=();
300             foreach $modName (keys(%$reqs)){
301             $name=$self->_get_modname($modName,$reqs->{$modName});
302             # print "$name-".$reqs->{$key}."\n";
303             push(@ret,"$name");
304             }
305              
306             return \@ret;
307             }
308              
309             #appends prequisites the given tree.
310             #parameters:
311             # $module_name, $treeCtrl, $parentNodeInTree = $treeCtrl->GetRootItem
312             sub _append_prereq{
313             my $self=shift;
314             my $modName=shift;
315             my $preTree=shift||$self;
316             my $parentNode=shift || $preTree->GetRootItem();
317              
318             # print "_append_prereq($modName)\n";
319              
320             my $pre=$self->GetPrereqs($modName);
321             #print Dumper $pre;
322             foreach $mod (@$pre){
323             push (@{$self->{thisPrereq}},$mod) unless ( grep($mod,@{$self->{thisPrereq}}) );
324             my $icon=$self->_get_status_icon($mod);
325             #print "$mod icon: $icon\n";
326             my $pNode=$preTree->AppendItem($parentNode,$mod,$icon);
327             $self->_append_prereq($mod,$preTree,$pNode);
328             }
329             }
330              
331             #this method returns a module for the given name.
332             # it is OK to pass an existing module ref, as it will
333             # simply return the ref. You can use this to validate
334             # all modules and names. You can pass an optional
335             # boolean denoting whether you would like to return the name
336             # so parse_module can understand it.
337             sub _get_modname{
338             my ($self,$mod,$version)=@_;
339             $version=$version?"-".$version:''; #the version we want
340              
341             if (ref($mod) && ($mod->isa('CPANPLUS::Module') or $mod->isa('CPANPLUS::Module::Fake'))){
342             if ($version){
343             my $name=$mod->name;
344             $name =~ s/::/-/g; #parse out the colons in the name
345             $mod=$self->{cpan}->parse_module(module=>$name.$version );
346             }
347             return $mod->package_name;
348             }
349             $mod =~ s/::/-/g; #parse out the colons in the name
350             $mod=$self->{cpan}->parse_module(module=>$mod.$version); #get the module
351             return $mod->package_name if $mod; #return the name if we want to
352             return '';
353             }
354              
355             sub _get_mod{
356             my ($self,$mod,$version)=@_;
357              
358             $version=$version?"-".$version:''; #add dash so parse_module can understand
359              
360             # print "_get_mod($name,$version,$onlyName)\n";
361             #if a module ref is passed, return the ref or the package_name
362             if (ref($mod) && ($mod->isa('CPANPLUS::Module') or $mod->isa('CPANPLUS::Module::Fake'))){
363             #get new module for $version
364             if ($version){
365             my $modname=$mod->name;
366             $modname =~ s/::/-/g; #parse out the colons in the name
367             $mod=$self->{cpan}->parse_module(module=>$modname.$version );
368             #return $newMod;
369             }
370             return $mod;
371             }
372             $mod =~ s/::/-/g; #parse out the colons in the name
373             $mod=$self->{cpan}->parse_module(module=>$mod.$version); #get the module
374             return $mod; #return the module object
375             }
376             ###############################
377             ####### PRIVATE METHODS #######
378             ###############################
379             #switch the type to show and populate list
380             #NOTE: These 2 methods are put here to eliminate repetative code
381             sub _switch_show{
382             my ($self,$type) = @_;
383             $self->{'show'}=(SHOW)[$type];
384             Wx::LogMessage _T("Showing ").$self->{'show'}._T(" Modules");
385             $self->Populate();
386             _uShowErr;
387             }
388             sub _switch_sort{
389             my ($self,$type) = @_;
390             $self->{'sort'}=(SORTBY)[$type];
391             Wx::LogMessage _T("Sorting by ").$self->{'sort'};
392             $self->Populate();
393             _uShowErr;
394             }
395              
396              
397              
398              
399              
400             ###############################
401             ######## Module Actions #######
402             ###############################
403             sub _install_module{
404             my $self=shift;
405             my $mod=shift||$self->{thisMod};
406             my $version=shift||'';
407             return unless $mod;
408              
409             #if no version supplied, check version list in Actions tab
410             unless ($version){
411             my $versionList=Wx::Window::FindWindowByName('info_distributions');
412             $version=$versionList->GetValue() || '';
413             }
414             my $fullname=$mod->name.'-'.$version;
415             $self->{statusBar}->SetStatusText(_T("Installing ").$fullname."...");
416              
417             #$mod=$self->{cpan}->parse_module(module => $mod->name.'-'.$version) if $version;
418             # print Dumper $mod;
419             $self->_install_with_prereqs($mod->name,$version);
420              
421             _uShowErr;
422             }
423              
424             sub _install_with_prereqs{
425             my $self=shift;
426             my $modName=shift;
427             return unless $modName;
428             my $version=shift||'';
429             my @prereqs=$self->CheckPrerequisites($modName,$version);
430             #print Dumper @prereqs;
431             unshift (@prereqs,$modName.($version?"-$version":''));
432             my @mods=(); #$self->{cpan}->module_tree(reverse(@prereqs));
433             foreach $n (reverse(@prereqs)){
434             push @mods, $self->{cpan}->parse_module(module=>$n);
435             }
436              
437             #print Dumper @mods;
438             my $curMod;
439             my $isSuccess=1;
440             foreach $mod (@mods){
441             $curMod=$mod;
442             unless ($self->_fetch_module($mod)){$isSuccess=0;last;}
443             unless ($self->_extract_module($mod)){$isSuccess=0;last;}
444             unless ($self->_prepare_module($mod)){$isSuccess=0;last;}
445             unless ($self->_create_module($mod)){$isSuccess=0;last;}
446             unless ($self->_test_module($mod)){$isSuccess=0;last;}
447             $self->{statusBar}->SetStatusText(_T('Installing ').$mod->name);
448             unless ($mod->install){$isSuccess=0;last;}
449             $self->{statusBar}->SetStatusText(_T('Successfully installed ').$mod->name);
450             }
451             #store status info and populate status tab
452             $self->_store_status(@mods);
453             #$self->_info_get_status();
454              
455             unless ($isSuccess){
456             $self->{statusBar}->SetStatusText(_T('Failed to install ').$curMod->name._T(". Please Check Log."));
457             Wx::MessageBox(_T("Failed to install ").$curMod->name._T("\nCheck Log for more information."));
458             return 0;
459             }
460              
461             _uShowErr;
462             return 1;
463             }
464              
465             sub _store_status{
466             my $self=shift;
467             my @mods=@_;
468             my $status={};
469             my $file=_uGetPath($self->{config},'cpp_stat_file');
470             $status=retrieve($file) if (-e $file);
471             foreach $mod (@mods){
472             $status->{$mod->name}=$mod->status();
473             }
474             store $status, $file;
475             }
476             sub _fetch_module{
477             my $self=shift;
478             my $mod=shift || $self->{thisMod};
479             $mod = $self->{cpan}->parse_module(module=>$mod) unless ($mod->isa('CPANPLUS::Module') || $mod->isa('CPANPLUS::Module::Fake'));
480             return unless $mod;
481             #print Dumper $mod;
482             $self->{statusBar}->SetStatusText(_T('Fetching ').$mod->{'package'});
483             my $path=$mod->fetch();
484             return 0 unless $path;
485             _uShowErr;
486             return 1;
487             }
488              
489             sub _extract_module{
490             my $self=shift;
491             my $mod=shift || $self->{thisMod};
492             $mod = $self->{cpan}->parse_module(module=>$mod) unless ($mod->isa('CPANPLUS::Module') || $mod->isa('CPANPLUS::Module::Fake'));
493             return unless $mod;
494             $self->{statusBar}->SetStatusText(_T('Extracting ').$mod->name);
495             my $path=$mod->extract();
496             return 0 unless $path;
497             _uShowErr;
498             return 1;
499             }
500             sub _prepare_module{
501             my $self=shift;
502             my $mod=shift || $self->{thisMod};
503             $mod = $self->{cpan}->parse_module(module=>$mod) unless ($mod->isa('CPANPLUS::Module') || $mod->isa('CPANPLUS::Module::Fake'));
504             return unless $mod;
505             $self->{statusBar}->SetStatusText(_T('Preparing ').$mod->name);
506             my $path=$mod->prepare();
507             return 0 unless $path;
508             _uShowErr;
509             return 1;
510             }
511              
512             sub _create_module{
513             my $self=shift;
514             my $mod=shift || $self->{thisMod};
515             $mod = $self->{cpan}->parse_module(module=>$mod) unless ($mod->isa('CPANPLUS::Module') || $mod->isa('CPANPLUS::Module::Fake'));
516             return unless $mod;
517             $self->{statusBar}->SetStatusText(_T('Building ').$mod->name);
518             my $path=$mod->create();
519             return 0 unless $path;
520             _uShowErr;
521             return 1;
522             }
523             sub _test_module{
524             my $self=shift;
525             my $mod=shift || $self->{thisMod};
526             $mod = $self->{cpan}->parse_module(module=>$mod) unless ($mod->isa('CPANPLUS::Module') || $mod->isa('CPANPLUS::Module::Fake'));
527             return unless $mod;
528             $self->{statusBar}->SetStatusText(_T('Testing ').$mod->name);
529             my $path=$mod->test();
530             return 0 unless $path;
531             _uShowErr;
532             return 1;
533             }
534             #populates the list with the tree items
535             #This function takes a tree hash, and optionally a progressdialog or bar
536             # and the max value of the progress bar
537             #return 1 on success, or 0 if the user cancelled
538             # call like:
539             #$user_has_cancelled = $self->PopulateWithHash(\%tree,[$progress],[$max_pval]);
540             sub PopulateWithHash{
541             #get parameters
542             my $self=shift;
543             my $tree=shift;
544             my $progress=shift;
545             my $max_progress=shift;
546              
547             #print "Window Height: ".$self->GetClientSize()->GetWidth." , ".$self->GetClientSize()->GetHeight."\n";
548              
549             #set defaults.
550             #Use half the number of items in the hash as a total items count, if none given
551             my $numFound=$tree->{'_items_in_tree_'} || %$tree/2;
552             $max_progress=($numFound || 10000) unless $max_progress;
553              
554             #create a progressdialog if none specified in params
555             $progress=Wx::ProgressDialog->new(_T("Setting Up List..."),
556             _T("Inserting ").$numFound._T(" Items Into Tree..."),
557             $numFound,$self,wxPD_APP_MODAL|wxPD_CAN_ABORT|wxPD_ESTIMATED_TIME|wxPD_REMAINING_TIME
558             ) unless $progress;
559              
560             #start timing
561             $begin=time();
562              
563             #restart count if another progressdialog is passeed in
564             $progress->Update(0,_T("Inserting ").$numFound._T(" Items Into Tree..."));
565             my $percent=$max_progress/$numFound;
566             $cnt=0;
567              
568             foreach $top_level ( sort( keys(%$tree) ) ){
569             next if $top_level eq '_items_in_tree_';
570             my $display=$top_level;
571             my $curParent=$self->AppendItem(
572             $self->GetRootItem(),
573             $top_level,$self->_get_status_icon($top_level));
574             foreach $item (sort(@{$tree->{$top_level}})){
575             $self->AppendItem($curParent,$top_level."::".$item,$self->_get_status_icon($item)) if ($curParent && $item);
576             last unless $progress->Update($cnt*$percent);
577             $cnt++;
578             }
579             }
580             # my $dummy=$self->AppendItem($self->GetRootItem(),'end');
581             # my $subDummy=$self->AppendItem($dummy,'end');
582              
583             # $progress->Update($numFound+1);
584             $progress->Destroy();
585             my $inserted_time=time()-$begin;
586             Wx::LogMessage _T("Finished Inserting in ").sprintf("%d",($inserted_time/60)).":".($inserted_time % 60)."\n";
587              
588             # print "Window Height: ".$self->GetClientSize()->GetWidth." , ".$self->GetClientSize()->GetHeight."\n";
589             _uShowErr;
590             return 1;
591             }
592              
593             ###############################
594             ######## New By Name ##########
595             ###############################
596             sub _show_new_by_name{
597             my $self=shift;
598             if ($self->{'tree_NewByName'}){
599             return 0 unless $self->PopulateWithHash($self->{'tree_NewByName'});
600             Wx::LogMessage _T("[Done]");
601             return 1;
602             }
603             my %tree=();
604             my $max_pval=10000; #the maximum value of the progress bar
605             my $progress=Wx::ProgressDialog->new(_T("Setting Up List..."),
606             _T("CPANPLUS is getting information..."),
607             $max_pval,
608             $self,
609             wxPD_APP_MODAL|wxPD_CAN_ABORT|wxPD_ESTIMATED_TIME|wxPD_REMAINING_TIME);
610             my %allMods=%{$self->{cpan}->module_tree()}; #get all modules
611             my $total=keys(%allMods);
612             my $percent=$max_pval/($total||1); #number to increment progress by
613             my $begin=time(); #for timing loops
614             my $cnt=0; #the count of current index of @allMods - for progressbar
615             my $numFound=0;
616              
617             $progress->Update(0,_T("Step 1 of 2: Sorting All ").$total._T(" Modules...")); #start actual progress
618              
619             #search through installed modules and insert them into the correct category
620             foreach $thisName (keys(%allMods)){
621             my $i=$allMods{$thisName};
622             if (!($i->is_uptodate || $i->installed_version)){
623             my ($top_level)=split('::',$thisName);
624             push (@{$tree{$top_level}}, ($thisName eq $top_level)?():$thisName); #add the item to the tree
625             $numFound++;
626             }
627             unless ($progress->Update($cnt*$percent)){
628             $progress->Destroy();
629             return 0;
630             }
631             $cnt++; #increment current index in @installed
632             }
633             #end timing method
634             my $end=time();
635             Wx::LogMessage _T("Finished Sorting in ").sprintf("%d",(($end-$begin)/60)).":".(($end-$begin) % 60)."\n";
636              
637             #store tree for later use
638             $tree{'_items_in_tree_'}=$numFound;
639             $self->{'tree_NewByName'}=\%tree;
640              
641             #populate the TreeCtrl
642             return 0 unless $self->PopulateWithHash(\%tree,$progress,$max_pval);
643              
644             Wx::LogMessage _T("[Done]");
645             _uShowErr;
646             return 1;
647             }
648             ###############################
649             ######## New By Author ########
650             ###############################
651             sub _show_new_by_author{
652             my $self=shift;
653             if ($self->{'tree_NewByAuthor'}){
654             return 0 unless $self->PopulateWithHash($self->{'tree_NewByAuthor'});
655             Wx::LogMessage _T("[Done]");
656             return 1;
657             }
658             my %tree=();
659             my $max_pval=10000; #the maximum value of the progress bar
660             my $progress=Wx::ProgressDialog->new(_T("Setting Up List..."),
661             _T("CPANPLUS is getting information..."),
662             $max_pval,
663             $self,
664             wxPD_APP_MODAL|wxPD_CAN_ABORT|wxPD_ESTIMATED_TIME|wxPD_REMAINING_TIME);
665             my %allMods=%{$self->{cpan}->module_tree()}; #get all modules
666             my $total=keys(%allMods);
667             my $percent=$max_pval/($total||1); #number to increment progress by
668             my $begin=time(); #for timing loops
669             my $cnt=0; #the count of current index of @allMods - for progressbar
670             $numFound=0;
671              
672             $progress->Update(0,_T("Step 1 of 2: Categorizing All ").$total._T(" Modules...")); #start actual progress
673              
674             #search through installed modules and insert them into the correct category
675             foreach $thisName (keys(%allMods)){
676             my $i=$allMods{$thisName};
677             if (!($i->is_uptodate || $i->installed_version)){
678             my $thisAuthor=$i->author()->cpanid." [".$i->author()->author."]";
679             my $cat_num=$self->{category_list}->{$thisName};
680             push (@{$tree{$thisAuthor}}, $thisName); #add the item to the tree
681             $numFound++;
682             }
683             unless ($progress->Update($cnt*$percent)){
684             $progress->Destroy();
685             return 0;
686             }
687             $cnt++; #increment current index in @installed
688             }
689             #end timing method
690             my $end=time();
691             Wx::LogMessage _T("Finished Sorting in ").sprintf("%d",(($end-$begin)/60)).":".(($end-$begin) % 60)."\n";
692              
693             #store tree for later use
694             $tree{'_items_in_tree_'}=$numFound;
695             $self->{'tree_NewByAuthor'}=\%tree;
696              
697             #populate the TreeCtrl
698             return 0 unless $self->PopulateWithHash(\%tree,$progress,$max_pval);
699              
700             Wx::LogMessage _T("[Done]");
701             _uShowErr;
702             return 1;
703             }
704              
705             ###############################
706             ######## New By Category ######
707             ###############################
708             sub _show_new_by_category{
709             my $self=shift;
710             if ($self->{'tree_NewByCategory'}){
711             return 0 unless $self->PopulateWithHash($self->{'tree_NewByCategory'});
712             Wx::LogMessage _T("[Done]");
713             return 1;
714             }
715             my $max_pval=10000; #the maximum value of the progress bar
716             my $progress=Wx::ProgressDialog->new(_T("Setting Up List..."),
717             _T("CPANPLUS is getting information..."),$max_pval,$self,
718             wxPD_APP_MODAL|wxPD_CAN_ABORT|wxPD_ESTIMATED_TIME|wxPD_REMAINING_TIME);
719              
720             my %allMods=%{$self->{cpan}->module_tree()}; #get all modules
721             my $total=keys(%allMods);
722             my $percent=$max_pval/($total||1); #number to increment progress by
723             my $begin=time(); #for timing loops
724             my $cnt=0; #the count of current index of @allMods - for progressbar
725             $numFound=0;
726              
727             $progress->Update(0,_T("Step 1 of 2: Categorizing All ").$total.(" Modules...")); #start actual progress
728              
729             #search through installed modules and insert them into the correct category
730             foreach $thisName (keys(%allMods)){
731             my $i=$allMods{$thisName};
732             my $cat_num=$self->{category_list}->{$thisName};
733             if (defined($cat_num) && !($i->is_uptodate || $i->installed_version)){
734             $cat_num=0 if ($cat_num==99); #don't use index 99, it make array too large
735             $cat_num=1 if ($i->module_is_supplied_with_perl_core() && $cat_num==2);
736             push (@{$tree{$self->{catNames}->[$cat_num]}}, $thisName); #add the item to the tree
737             $numFound++;
738             }
739             unless ($progress->Update($cnt*$percent)){
740             $progress->Destroy();
741             return 0;
742             }
743             $cnt++; #increment current index in @installed
744             }
745              
746             #end timing method
747             my $end=time();
748             Wx::LogMessage _T("Finished Sorting in ").sprintf("%d",(($end-$begin)/60)).":".(($end-$begin) % 60)."\n";
749              
750             #store tree for later use
751             $tree{'_items_in_tree_'}=$numFound;
752             $self->{'tree_NewByCategory'}=\%tree;
753              
754             #populate the TreeCtrl
755             return 0 unless $self->PopulateWithHash(\%tree,$progress,$max_pval);
756              
757             Wx::LogMessage _T("[Done]");
758             _uShowErr;
759             return 1;
760             }
761              
762             ###############################
763             ######## All By Name ##########
764             ###############################
765             sub _show_all_by_name{
766             my $self=shift;
767             if ($self->{'tree_AllByName'}){
768             return 0 unless $self->PopulateWithHash($self->{'tree_AllByName'});
769             Wx::LogMessage _T("[Done]");
770             return 1;
771             }
772             my %tree=();
773             my $max_pval=10000; #the maximum value of the progress bar
774             my $progress=Wx::ProgressDialog->new(_T("Setting Up List..."),
775             _T("CPANPLUS is getting information..."),
776             $max_pval,
777             $self,
778             wxPD_APP_MODAL|wxPD_CAN_ABORT|wxPD_ESTIMATED_TIME|wxPD_REMAINING_TIME);
779             my %allMods=%{$self->{cpan}->module_tree()}; #get all modules
780             my $total=keys(%allMods);
781             my $percent=$max_pval/($total||1); #number to increment progress by
782             my $begin=time(); #for timing loops
783             my $cnt=0; #the count of current index of @allMods - for progressbar
784              
785             $progress->Update(0,_T("Step 1 of 2: Sorting All ").$total._T(" Modules...")); #start actual progress
786              
787             #search through installed modules and insert them into the correct category
788             foreach $thisName (keys(%allMods)){
789             my $i=$allMods{$thisName};
790             my ($top_level)=split('::',$thisName);
791             push (@{$tree{$top_level}}, ($thisName eq $top_level)?():$thisName); #add the item to the tree
792             unless ($progress->Update($cnt*$percent)){
793             $progress->Destroy();
794             return 0;
795             }
796             $cnt++; #increment current index in @installed
797             }
798             #end timing method
799             my $end=time();
800             Wx::LogMessage _T("Finished Sorting in ").sprintf("%d",(($end-$begin)/60)).":".(($end-$begin) % 60)."\n";
801              
802             #store tree for later use
803             $tree{'_items_in_tree_'}=$total;
804             $self->{'tree_AllByName'}=\%tree;
805              
806             #populate the TreeCtrl
807             return 0 unless $self->PopulateWithHash(\%tree,$progress,$max_pval);
808              
809             Wx::LogMessage _T("[Done]");
810             _uShowErr;
811             return 1;
812             }
813              
814             ###############################
815             ######## All By Author ########
816             ###############################
817             sub _show_all_by_author{
818             my $self=shift;
819             if ($self->{'tree_AllByAuthor'}){
820             return 0 unless $self->PopulateWithHash($self->{'tree_AllByAuthor'});
821             Wx::LogMessage _T("[Done]");
822             return 1;
823             }
824             my %tree=();
825             my $max_pval=10000; #the maximum value of the progress bar
826             my $progress=Wx::ProgressDialog->new(_T("Setting Up List..."),
827             _T("CPANPLUS is getting information..."),
828             $max_pval,
829             $self,
830             wxPD_APP_MODAL|wxPD_CAN_ABORT|wxPD_ESTIMATED_TIME|wxPD_REMAINING_TIME);
831             my %allMods=%{$self->{cpan}->module_tree()}; #get all modules
832             my $total=keys(%allMods);
833             my $percent=$max_pval/($total||1); #number to increment progress by
834             my $begin=time(); #for timing loops
835             my $cnt=0; #the count of current index of @allMods - for progressbar
836              
837             $progress->Update(0,_T("Step 1 of 2: Categorizing All ").$total._T(" Modules...")); #start actual progress
838              
839             #search through installed modules and insert them into the correct category
840             foreach $thisName (keys(%allMods)){
841             my $i=$allMods{$thisName};
842             my $thisAuthor=$i->author()->cpanid." [".$i->author()->author."]";
843             my $cat_num=$self->{category_list}->{$thisName};
844             push (@{$tree{$thisAuthor}}, $thisName); #add the item to the tree
845             unless ($progress->Update($cnt*$percent)){
846             $progress->Destroy();
847             return 0;
848             }
849             $cnt++; #increment current index in @installed
850             }
851             #end timing method
852             my $end=time();
853             Wx::LogMessage _T("Finished Sorting in ").sprintf("%d",(($end-$begin)/60)).":".(($end-$begin) % 60)."\n";
854              
855             #store tree for later use
856             $tree{'_items_in_tree_'}=$total;
857             $self->{'tree_AllByAuthor'}=\%tree;
858              
859             #populate the TreeCtrl
860             return 0 unless $self->PopulateWithHash(\%tree,$progress,$max_pval);
861              
862             Wx::LogMessage _T("[Done]");
863             _uShowErr;
864             return 1;
865             }
866              
867             ###############################
868             ###### All By Category ########
869             ###############################
870             sub _show_all_by_category{
871             my $self=shift;
872             if ($self->{'tree_AllByCategory'}){
873             return 0 unless $self->PopulateWithHash($self->{'tree_AllByCategory'});
874             Wx::LogMessage _T("[Done]");
875             return 1;
876             }
877             my $max_pval=10000; #the maximum value of the progress bar
878             my $progress=Wx::ProgressDialog->new(_T("Setting Up List..."),
879             _T("CPANPLUS is getting information..."),$max_pval,$self,
880             wxPD_APP_MODAL|wxPD_CAN_ABORT|wxPD_ESTIMATED_TIME|wxPD_REMAINING_TIME);
881              
882             my %allMods=%{$self->{cpan}->module_tree()}; #get all modules
883             my $total=keys(%allMods);
884             my $percent=$max_pval/($total||1); #number to increment progress by
885             my $begin=time(); #for timing loops
886             my $cnt=0; #the count of current index of @allMods - for progressbar
887              
888             $progress->Update(0,_T("Step 1 of 2: Categorizing All ").$total._T(" Modules...")); #start actual progress
889              
890             #search through installed modules and insert them into the correct category
891             foreach $thisName (keys(%allMods)){
892             my $i=$allMods{$thisName};
893             my $cat_num=$self->{category_list}->{$thisName};
894             if (defined($cat_num)){
895             $cat_num=0 if ($cat_num==99); #don't use index 99, it make array too large
896             $cat_num=1 if ($i->module_is_supplied_with_perl_core() && $cat_num==2);
897             push (@{$tree{$self->{catNames}->[$cat_num]}}, $thisName); #add the item to the tree
898             }
899             unless ($progress->Update($cnt*$percent)){
900             $progress->Destroy();
901             return 0;
902             }
903             $cnt++; #increment current index in @installed
904             }
905              
906             #end timing method
907             my $end=time();
908             Wx::LogMessage _T("Finished Sorting in ").sprintf("%d",(($end-$begin)/60)).":".(($end-$begin) % 60)."\n";
909              
910             #store tree for later use
911             $tree{'_items_in_tree_'}=$total;
912             $self->{'tree_AllByCategory'}=\%tree;
913              
914             #populate the TreeCtrl
915             return 0 unless $self->PopulateWithHash(\%tree,$progress,$max_pval);
916              
917             Wx::LogMessage _T("[Done]");
918             $progress->Destroy();
919             _uShowErr;
920             return 1;
921             }
922              
923              
924             sub _show_updates_by_category{
925             my $self=shift;
926             if ($self->{'tree_UpdatesByCategory'}){
927             return 0 unless $self->PopulateWithHash($self->{'tree_UpdatesByCategory'});
928             Wx::LogMessage _T("[Done]");
929             return 1;
930             }
931             my $max_pval=10000; #the maximum value of the progress bar
932             my $progress=Wx::ProgressDialog->new(_T("Setting Up List..."),
933             _T("CPANPLUS is getting information..."),$max_pval,$self,
934             wxPD_APP_MODAL|wxPD_CAN_ABORT|wxPD_ESTIMATED_TIME|wxPD_REMAINING_TIME);
935              
936             my @installed=$self->{cpan}->installed(); #get installed modules
937             my $percent=$max_pval/@installed; #number to increment progress by
938             my $begin=time(); #for timing loops
939             my $cnt=0; #the count of current index of @installed - for progressbar
940             my $numFound=0; #the number of modules that match CPAN to CPANPLUS::Installed
941             $progress->Update(0,_T("Step 1 of 2: Categorizing ").@installed._T(" Installed Modules...")); #start actual progress
942              
943             #search through installed modules and insert them into the correct category
944             foreach $i (@installed){
945             unless ($i->is_uptodate()){
946             my $thisName=$i->name;
947             my $cat_num=$self->{category_list}->{$thisName};
948             if (defined($cat_num)){
949             $cat_num=0 if ($cat_num==99); #don't use index 99, it make array too large
950             $cat_num=1 if ($i->module_is_supplied_with_perl_core() && $cat_num==2);
951             push (@{$tree{$self->{catNames}->[$cat_num]}}, $thisName); #add the item to the tree
952             $numFound++; #increment the number of items that matched
953             }
954             }
955             unless ($progress->Update($cnt*$percent)){
956             $progress->Destroy();
957             return 0;
958             }
959             $cnt++; #increment current index in @installed
960             }
961              
962             #end timing method
963             my $end=time();
964             Wx::LogMessage _T("Finished Sorting in ").sprintf("%d",(($end-$begin)/60)).":".(($end-$begin) % 60)."\n";
965              
966             #store tree for later use
967             $tree{'_items_in_tree_'}=$numFound;
968             $self->{'tree_UpdatesByCategory'}=\%tree;
969              
970             #populate the TreeCtrl
971             return 0 unless $self->PopulateWithHash(\%tree,$progress,$max_pval);
972              
973             Wx::LogMessage _T("[Done]");
974             $progress->Destroy();
975             _uShowErr;
976             return 1;
977             }
978              
979             sub _show_updates_by_author{
980             my $self=shift;
981             if ($self->{'tree_UpdatesByAuthor'}){
982             return 0 unless $self->PopulateWithHash($self->{'tree_UpdatesByAuthor'});
983             Wx::LogMessage _T("[Done]");
984             return 1;
985             }
986             my %tree=();
987             my $max_pval=10000; #the maximum value of the progress bar
988             my $progress=Wx::ProgressDialog->new(_T("Setting Up List..."),
989             _T("CPANPLUS is getting information..."),
990             $max_pval,
991             $self,
992             wxPD_APP_MODAL|wxPD_CAN_ABORT|wxPD_ESTIMATED_TIME|wxPD_REMAINING_TIME);
993             my @installed=$self->{cpan}->installed(); #get installed modules
994             my $percent=$max_pval/@installed; #number to increment progress by
995             my $begin=time(); #for timing loops
996             my $cnt=0; #the count of current index of @installed - for progressbar
997             my $numFound=0; #the number of modules that match CPAN to CPANPLUS::Installed
998             $progress->Update(0,_T("Step 1 of 2: Sorting ").@installed." Installed Modules..."); #start actual progress
999              
1000             #search through installed modules and insert them into the correct category
1001             foreach $i (@installed){
1002             unless ($i->is_uptodate()){
1003             my $thisName=$i->name;
1004             my $thisAuthor=$i->author()->cpanid." [".$i->author()->author."]";
1005             my $cat_num=$self->{category_list}->{$thisName};
1006             push (@{$tree{$thisAuthor}}, $thisName); #add the item to the tree
1007             }
1008             unless ($progress->Update($cnt*$percent)){
1009             $progress->Destroy();
1010             return 0;
1011             }
1012             $cnt++; #increment current index in @installed
1013             }
1014             #end timing method
1015             my $end=time();
1016             Wx::LogMessage _T("Finished Sorting in ").sprintf("%d",(($end-$begin)/60)).":".(($end-$begin) % 60)."\n";
1017              
1018             #store tree for later use
1019             $tree{'_items_in_tree_'}=$numFound;
1020             $self->{'tree_UpdatesByAuthor'}=\%tree;
1021              
1022             #populate the TreeCtrl
1023             return 0 unless $self->PopulateWithHash(\%tree,$progress,$max_pval);
1024              
1025             Wx::LogMessage _T("[Done]");
1026             $progress->Destroy();
1027             _uShowErr;
1028             return 1;
1029             }
1030              
1031              
1032             sub _show_updates_by_name{
1033             my $self=shift;
1034             if ($self->{'tree_UpdatesByName'}){
1035             return 0 unless $self->PopulateWithHash($self->{'tree_UpdatesByName'});
1036             Wx::LogMessage _T("[Done]");
1037             return 1;
1038             }
1039             my %tree=();
1040             my $max_pval=10000; #the maximum value of the progress bar
1041             my $progress=Wx::ProgressDialog->new(_T("Setting Up List..."),
1042             _T("CPANPLUS is getting information..."),
1043             $max_pval,
1044             $self,
1045             wxPD_APP_MODAL|wxPD_CAN_ABORT|wxPD_ESTIMATED_TIME|wxPD_REMAINING_TIME);
1046             my @installed=$self->{cpan}->installed(); #get installed modules
1047             my $percent=$max_pval/@installed; #number to increment progress by
1048             my $begin=time(); #for timing loops
1049             my $cnt=0; #the count of current index of @installed - for progressbar
1050             my $numFound=0; #the number of modules that match CPAN to CPANPLUS::Installed
1051             $progress->Update(0,_T("Step 1 of 2: Sorting ").@installed." Installed Modules..."); #start actual progress
1052              
1053             #search through installed modules and insert them into the correct category
1054             foreach $i (@installed){
1055             unless ($i->is_uptodate()){
1056             my $thisName=$i->name;
1057             my ($top_level)=split('::',$thisName);
1058             push (@{$tree{$top_level}}, ($thisName eq $top_level)?():$thisName); #add the item to the tree
1059             }
1060             unless ($progress->Update($cnt*$percent)){
1061             $progress->Destroy();
1062             return 0;
1063             }
1064             $cnt++; #increment current index in @installed
1065             }
1066             #end timing method
1067             my $end=time();
1068             Wx::LogMessage _T("Finished Sorting in ").sprintf("%d",(($end-$begin)/60)).":".(($end-$begin) % 60)."\n";
1069              
1070             #store tree for later use
1071             $tree{'_items_in_tree_'}=$numFound;
1072             $self->{'tree_UpdatesByName'}=\%tree;
1073              
1074             #populate the TreeCtrl
1075             return 0 unless $self->PopulateWithHash(\%tree,$progress,$max_pval);
1076              
1077             Wx::LogMessage _T("[Done]");
1078             $progress->Destroy();
1079             _uShowErr;
1080             return 1;
1081             }
1082              
1083              
1084             sub _show_installed_by_name{
1085             my $self=shift;
1086             if ($self->{'tree_InstalledByName'}){
1087             return 0 unless $self->PopulateWithHash($self->{'tree_InstalledByName'});
1088             Wx::LogMessage _T("[Done]");
1089             return 1;
1090             }
1091             my %tree=();
1092             my $max_pval=10000; #the maximum value of the progress bar
1093             my $progress=Wx::ProgressDialog->new(_T("Setting Up List..."),
1094             _T("CPANPLUS is getting information..."),
1095             $max_pval,
1096             $self,
1097             wxPD_APP_MODAL|wxPD_CAN_ABORT|wxPD_ESTIMATED_TIME|wxPD_REMAINING_TIME);
1098             my @installed=$self->{cpan}->installed(); #get installed modules
1099             my $percent=$max_pval/@installed; #number to increment progress by
1100             my $begin=time(); #for timing loops
1101             my $cnt=0; #the count of current index of @installed - for progressbar
1102             my $numFound=0; #the number of modules that match CPAN to CPANPLUS::Installed
1103             $progress->Update(0,_T("Step 1 of 2: Sorting ").@installed._T(" Installed Modules...")); #start actual progress
1104              
1105             #search through installed modules and insert them into the correct category
1106             foreach $i (@installed){
1107             my $thisName=$i->name;
1108             my ($top_level)=split('::',$thisName);
1109             push (@{$tree{$top_level}}, ($thisName eq $top_level)?():$thisName); #add the item to the tree
1110             unless ($progress->Update($cnt*$percent)){
1111             $progress->Destroy();
1112             return 0;
1113             }
1114             $cnt++; #increment current index in @installed
1115             }
1116             #end timing method
1117             my $end=time();
1118             Wx::LogMessage _T("Finished Sorting in ").sprintf("%d",(($end-$begin)/60)).":".(($end-$begin) % 60)."\n";
1119              
1120             #store tree for later use
1121             $tree{'_items_in_tree_'}=keys(%tree); #@installed; #$numFound;
1122             $self->{'tree_InstalledByName'}=\%tree;
1123              
1124             #populate the TreeCtrl
1125             return 0 unless $self->PopulateWithHash(\%tree,$progress,$max_pval);
1126              
1127             Wx::LogMessage _T("[Done]");
1128             $progress->Destroy();
1129             _uShowErr;
1130             return 1;
1131             }
1132              
1133             #populate tree with installed modules sorted by author id
1134             sub _show_installed_by_author{
1135             my $self=shift;
1136             if ($self->{'tree_InstalledByAuthor'}){
1137             return 0 unless $self->PopulateWithHash($self->{'tree_InstalledByAuthor'});
1138             Wx::LogMessage _T("[Done]");
1139             return 1;
1140             }
1141             my %tree=();
1142             my $max_pval=10000; #the maximum value of the progress bar
1143             my $progress=Wx::ProgressDialog->new("Setting Up List...",
1144             "CPANPLUS is getting information...",
1145             $max_pval,
1146             $self,
1147             wxPD_APP_MODAL|wxPD_CAN_ABORT|wxPD_ESTIMATED_TIME|wxPD_REMAINING_TIME);
1148             my @installed=$self->{cpan}->installed(); #get installed modules
1149             my $percent=$max_pval/@installed; #number to increment progress by
1150             my $begin=time(); #for timing loops
1151             my $cnt=0; #the count of current index of @installed - for progressbar
1152             my $numFound=0; #the number of modules that match CPAN to CPANPLUS::Installed
1153             $progress->Update(0,_T("Step 1 of 2: Sorting ").@installed._T(" Installed Modules...")); #start actual progress
1154              
1155             #search through installed modules and insert them into the correct category
1156             foreach $i (@installed){
1157             my $thisName=$i->name;
1158             my $thisAuthor=$i->author()->cpanid." [".$i->author()->author."]";
1159             my $cat_num=$self->{category_list}->{$thisName};
1160             push (@{$tree{$thisAuthor}}, $thisName); #add the item to the tree
1161             unless ($progress->Update($cnt*$percent)){
1162             $progress->Destroy();
1163             return 0;
1164             }
1165             $cnt++; #increment current index in @installed
1166             }
1167             #end timing method
1168             my $end=time();
1169             Wx::LogMessage _T("Finished Sorting in ").sprintf("%d",(($end-$begin)/60)).":".(($end-$begin) % 60)."\n";
1170              
1171             #store tree for later use
1172             $tree{'_items_in_tree_'}=$numFound;
1173             $self->{'tree_InstalledByAuthor'}=\%tree;
1174              
1175             #populate the TreeCtrl
1176             return 0 unless $self->PopulateWithHash(\%tree,$progress,$max_pval);
1177              
1178             Wx::LogMessage _T("[Done]");
1179             $progress->Destroy();
1180             _uShowErr;
1181             return 1;
1182             }
1183              
1184             #populate tree with installed modules sorted by category
1185             sub _show_installed_by_category{
1186             my $self=shift;
1187             if ($self->{'tree_InstalledByCategory'}){
1188             return 0 unless $self->PopulateWithHash($self->{'tree_InstalledByCategory'});
1189             Wx::LogMessage _T("[Done]");
1190             return 1;
1191             }
1192             my %tree=();
1193             my $max_pval=10000; #the maximum value of the progress bar
1194             my $progress=Wx::ProgressDialog->new(_T("Setting Up List..."),
1195             _T("CPANPLUS is getting information..."),
1196             10000,
1197             $self,
1198             wxPD_APP_MODAL|wxPD_CAN_ABORT|wxPD_ESTIMATED_TIME|wxPD_REMAINING_TIME);
1199              
1200             my @installed=$self->{cpan}->installed(); #get installed modules
1201             my $percent=$max_pval/@installed; #number to increment progress by
1202             my $begin=time(); #for timing loops
1203             my $cnt=0; #the count of current index of @installed - for progressbar
1204             my $numFound=0; #the number of modules that match CPAN to CPANPLUS::Installed
1205             $progress->Update(0,_T("Step 1 of 2: Categorizing ").@installed._T(" Installed Modules...")); #start actual progress
1206              
1207             #search through installed modules and insert them into the correct category
1208             foreach $i (@installed){
1209             my $thisName=$i->name;
1210             my $cat_num=$self->{category_list}->{$thisName};
1211             $progress->Update($cnt*$percent);
1212             # "Step 1 of 2: Categorizing ".@installed." Installed Modules...#$cnt : ".$i->name);
1213             if (defined($cat_num)){
1214             $cat_num=0 if ($cat_num==99); #don't use index 99, it make array too large
1215             $cat_num=1 if ($i->module_is_supplied_with_perl_core() && $cat_num==2);
1216             push (@{$tree{$self->{catNames}->[$cat_num]}}, $thisName); #add the item to the tree
1217             $numFound++; #increment the number of items that matched
1218             }
1219             unless ($progress->Update($cnt*$percent)){
1220             $progress->Destroy();
1221             return 0;
1222             }
1223             $cnt++; #increment current index in @installed
1224             }
1225             #end timing method
1226             my $end=time();
1227             Wx::LogMessage _T("Finished Sorting in ").sprintf("%d",(($end-$begin)/60)).":".(($end-$begin) % 60)."\n";
1228              
1229             #store tree for later use
1230             $tree{'_items_in_tree_'}=$numFound;
1231             $self->{'tree_InstalledByCategory'}=\%tree;
1232              
1233             #populate the TreeCtrl
1234             return 0 unless $self->PopulateWithHash(\%tree,$progress,$max_pval);
1235              
1236             Wx::LogMessage _T("[Done]");
1237             $progress->Destroy();
1238             _uShowErr;
1239             return 1;
1240              
1241             }
1242              
1243             #this returns a referece to a hash, (module_name=>category_number), of all modules
1244             sub _get_categories{
1245             my $self = shift;
1246              
1247             my $moduleFile= _uGetPath($self->{config},'cpp_modlist');
1248             my $modlistEval; #the string to evaluate == 03modlist.data.gz
1249              
1250             #inflate file into $modlistEval
1251             Wx::LogMessage _T("Getting Category List...Inflating...");
1252             use IO::Uncompress::AnyInflate qw(anyinflate $AnyInflateError) ;
1253             anyinflate $moduleFile => \$modlistEval
1254             or Wx::LogMessage _T("anyinflate failed: ").$AnyInflateError."\n";
1255             return unless $modlistEval;
1256             Wx::LogMessage _T("Successfully Inflated Module Info File!");
1257              
1258             #get rid of file info in header
1259             $modlistEval=~s/(.*)package CPAN\:\:Modulelist/package CPAN\:\:Modulelist/si ;#get rid of file info
1260              
1261             #create List of Categories
1262             my $cat_hash=(); #the hash that is stored in the file
1263             my %categories=(); #the return value of this function
1264             eval $modlistEval.'$cat_hash=(CPAN::Modulelist->data)[0];';Wx::LogMessage($@) if $@;
1265             $categories{$_}=$cat_hash->{$_}->{'chapterid'} foreach (keys(%$cat_hash));
1266              
1267             #return list
1268             Wx::LogMessage _T("Successfully read Category List!");
1269             return \%categories;
1270             _uShowErr;
1271             }
1272              
1273             #this method displays the search results.
1274             #use: $self->search($type,@list_of_searches)
1275             #TODO add support for multiple searches, using ',' as delimiter
1276             #TODO show scrollbars
1277             sub search{
1278             my $self=shift;
1279             my ($type,@search)=@_;
1280             $self->{statusBar}->SetStatusText(_T("Searching. Please Wait..."));
1281              
1282             my $progress=Wx::ProgressDialog->new(_T("Setting Up List..."),
1283             _T("CPANPLUS is getting information..."),
1284             MAX_PROGRESS_VALUE,
1285             $self,
1286             wxPD_APP_MODAL|wxPD_CAN_ABORT|wxPD_ESTIMATED_TIME|wxPD_REMAINING_TIME);
1287              
1288             $self->DeleteChildren($self->GetRootItem());
1289             foreach $s (@search){
1290             Wx::LogMessage _T("Searching for: ").$search[0]._T(" by $type\n");
1291             if ($s=~m|/(.*)/(.*)|){
1292             #print "Matching Regex...\n";
1293             eval "\$s=qr/$1/".($2||'');
1294             }else{
1295             $s=qr/$s/i;
1296             }
1297             }
1298             $type= lc($type);
1299              
1300             my $mparent=$self->GetRootItem();
1301             my @names=();
1302             my $numFound=0;
1303             my $tmpCnt=1;
1304             $modules={};
1305             if ($type eq 'any' || $type eq 'all'){
1306             my @modterms=CPANPLUS::Module::accessors(); #('name','version','path','comment','package','description','dslip','status');
1307             my @authterms=CPANPLUS::Module::Author::accessors(); #('author','cpanid','email');
1308             my $percent = MAX_PROGRESS_VALUE/(@modterms+@authterms);
1309             my $count=0;
1310             foreach $term (@modterms){
1311             if ($progress->Update($percent*($count++),_T("Searching in $term: Found ").keys(%$modules)._T(" items"))){
1312             foreach $m ($self->{cpan}->search(type => $term, allow => \@search)){
1313             if ($m->isa(CPANPLUS::Module)){
1314             #print "module: ".$m->name." [".($percent*($count++)/MAX_PROGRESS_VALUE)."]\n";
1315             $modules->{$m->name} = $m;
1316             }
1317             if ($m->isa(CPANPLUS::Module::Author)){
1318             foreach $amod ($m->modules()){
1319             #print "amodule: ".$m->name." [".($percent*($count++)/MAX_PROGRESS_VALUE)."]\n";
1320             $modules->{$amod->name} = $amod;
1321             }
1322             }
1323             }
1324             }else{$progress->Destroy();return;}
1325             }
1326             }else{
1327             foreach $m ($self->{cpan}->search(type => $type, allow => \@search)){
1328             return unless $progress->Update(MAX_PROGRESS_VALUE-1,_T("Found ").keys(%$modules)._T(" items"));
1329             $modules->{$m->name}=$m;
1330             }
1331             }
1332              
1333             $self->PopulateWithModuleHash($progress,$modules);
1334             $progress->Destroy;
1335              
1336              
1337             #Wx::Window::FindWindowByName('module_splitter')->FitInside();
1338             #Wx::Window::FindWindowByName('module_splitter')->UpdateWindowUI(wxUPDATE_UI_RECURSE );
1339              
1340             _uShowErr;
1341             print "Window Height: ".$self->GetClientSize()->GetWidth." , ".$self->GetClientSize()->GetHeight."\n";
1342             # print Dumper $self->GetClientSize();
1343             $self->{statusBar}->SetStatusText('');
1344             my $curStyle=$self->GetWindowStyleFlag();
1345             $self->SetWindowStyleFlag($self->GetWindowStyleFlag()|wxVSCROLL);
1346             $self->GetParent()->SetWindowStyleFlag($self->GetParent()->GetWindowStyleFlag()|wxVSCROLL);
1347             }
1348              
1349             sub PopulateWithModuleHash{
1350             my $self=shift;
1351             my $progress=shift || Wx::ProgressDialog->new(_T("Please Wait..."),
1352             _T("Displaying List..."),
1353             MAX_PROGRESS_VALUE,
1354             $self,
1355             wxPD_APP_MODAL|wxPD_CAN_ABORT|wxPD_ESTIMATED_TIME|wxPD_REMAINING_TIME);
1356             my $modules=shift;
1357             my @names=();
1358             my $count=0;
1359             my $numFound=keys(%$modules);
1360             return unless $numFound>0;
1361             my $percent=MAX_PROGRESS_VALUE / $numFound;
1362             return unless $progress->Update(0,_T("Getting info for $numFound items."));
1363              
1364             my $newTree={};
1365             #get information from modules
1366             foreach $modname (keys(%$modules)){
1367             last unless $progress->Update($percent*$count);
1368             if ($modules->{$modname}->isa('CPANPLUS::Module')){
1369             my @names=split('::',$modname);
1370             my $ref=$newTree;
1371             foreach $n (@names){
1372             $ref=$ref->{$n}='';
1373             # push(@names,$modname);
1374             }
1375             }
1376             if ($modules->{$modname}->isa('CPANPLUS::Module::Author')){
1377             foreach $m ($modules->{$modname}->modules()){
1378             my @names=split('::',$m->name);
1379             my $ref=$newTree;
1380             foreach $n (@names){
1381             $ref=$ref->{$n}='';
1382             # push(@names,$m->name);
1383             }
1384             }
1385             }
1386             $count++;
1387             }
1388              
1389             #populate the tree ctrl
1390             return unless $progress->Update(0,_T("Populating tree with ").$numFound._T(" items.") );
1391             $count=0;
1392             # my $dummy=$self->AppendItem($self->GetRootItem(),'Modules');
1393             # foreach $item (sort {lc($a) cmp lc($b)} @names){
1394             # $self->AppendItem($dummy,$item,$self->_get_status_icon($item));
1395             # $count++;
1396             # }
1397             foreach $k (sort(keys(%$newTree))){
1398             return unless $progress->Update($percent*$count);
1399             my $parent=$self->AppendItem($self->GetRootItem(),$item,$self->_get_status_icon($item));
1400             my $ref=$newTree->{$k};
1401             while($ref){
1402            
1403             }
1404             $count++;
1405             }
1406             # my $dummy=$self->AppendItem($self->GetRootItem(),'end');
1407             # my $subDummy=$self->AppendItem($dummy,'end');
1408             # $self->EnsureVisible($dummy);
1409             return 1;
1410             }
1411              
1412             #this method populates the list with the given module objects.
1413             #if the object is an Author, then get the module names he/she has written
1414             sub PopulateWithModuleList{
1415             my $self=shift;
1416             my $progress=shift || Wx::ProgressDialog->new(_T("Please Wait..."),
1417             _T("Displaying List..."),
1418             MAX_PROGRESS_VALUE,
1419             $self,
1420             wxPD_APP_MODAL|wxPD_CAN_ABORT|wxPD_ESTIMATED_TIME|wxPD_REMAINING_TIME);
1421             my $totalFound=shift;
1422             return unless $totalFound;
1423             my $numFound=$totalFound;
1424             my @modules=@_;
1425             my @names=();
1426             my $count=0;
1427             my $percent=MAX_PROGRESS_VALUE/$totalFound;
1428             return unless $progress->Update(0,_T("Getting info for $numFound items."));
1429              
1430             #get information from modules
1431             foreach $mod (@modules){
1432             last unless $progress->Update($percent*$count);
1433             if ($mod->isa('CPANPLUS::Module')){
1434             push(@names,$mod->name);
1435             }
1436             if ($mod->isa('CPANPLUS::Module::Author')){
1437             foreach $m ($mod->modules()){
1438             push(@names,$m->name);
1439             }
1440             }
1441             $count++;
1442             }
1443              
1444             #populate the tree ctrl
1445             return unless $progress->Update(0,_T("Populating tree with").$totalFound._T(" items.") );
1446             $count=0;
1447             foreach $item (sort {lc($a) cmp lc($b)} @names){
1448             return unless $progress->Update($percent*$count);
1449             $self->AppendItem($self->GetRootItem(),$item,$self->_get_status_icon($item));
1450             $count++;
1451             }
1452             return 1;
1453             }
1454              
1455             #this method returns the index in the imageList for the status of the passed name
1456             sub _get_status_icon{
1457             my $self=shift;
1458             my ($name)=@_;
1459             my $mod=$self->_get_mod($name);
1460             return $self->{iconList}->unknown->idx unless $mod;
1461             return $self->{iconList}->installed->idx if $mod->is_uptodate();
1462             return $self->{iconList}->not_installed->idx if !$mod->installed_version();
1463             return $self->{iconList}->update->idx;
1464              
1465             _uShowErr;
1466              
1467             }
1468             sub SetImageList{ #must be a Wx::ImageList
1469             my ($self,$list)=@_;
1470             $self->{iconList}=$list;
1471             $self->AssignImageList($list->imageList);
1472             }
1473              
1474             ########################################
1475             ########### Context Menu ##############
1476             ########################################
1477              
1478              
1479              
1480             package CPANPLUS::Shell::Wx::ModuleTree::Menu;
1481             use base 'Wx::Menu';
1482             use Wx::Event qw/EVT_WINDOW_CREATE EVT_MENU/;
1483             use Data::Dumper;
1484             use Wx::Locale gettext => '_T';
1485              
1486             sub new {
1487             my $class = shift;
1488             my $parent=shift;
1489             my $item=shift;
1490             my $self = $class->SUPER::new(); # create an 'empty' menu object
1491             #get image so we can determine what the status is
1492             $img=$parent->GetItemImage($item);
1493             $actions=new Wx::Menu();
1494             $install=$actions->Append(1000,_T("Install")) if $img == 3;
1495             $update=$actions->Append(1001,_T("Update")) if $img == 1;
1496             $uninstall=$actions->Append(1002,_T("Uninstall")) if ($img==0 or $img==1);
1497             $actions->AppendSeparator();
1498             $fetch=$actions->Append(1003,_T("Fetch"));
1499             $extract=$actions->Append(1004,_T("Extract"));
1500             $prepare=$actions->Append(1005,_T("Prepare"));
1501             $build=$actions->Append(1006,_T("Build"));
1502             $test=$actions->Append(1007,_T("Test"));
1503              
1504             $self->AppendSubMenu($actions,_T("Actions"));
1505              
1506             $info=$self->Append(1008,_T("Get All Information"));
1507              
1508             my $modName=$parent->GetItemText($item);
1509              
1510             EVT_MENU( $self, $info, sub{&{$parent->{_minfoHandler}}(@_,$modName)} ) if $parent->{_minfoHandler};
1511             EVT_MENU( $actions, $install, sub{&{$parent->{_minstallHandler}}(@_,$modName)} ) if ($img == 3 && $parent->{_minstallHandler});
1512             EVT_MENU( $actions, $update, sub{&{$parent->{_mupdateHandler}}(@_,$modName)} ) if ($img == 1 && $parent->{_mupdateHandler});
1513             EVT_MENU( $actions, $uninstall, sub{&{$parent->{_muninstallHandler}}(@_,$modName)} )if (($img==0 or $img==1) && $parent->{_muninstallHandler});
1514             EVT_MENU( $actions, $fetch, sub{&{$parent->{_mfetchHandler}}(@_,$modName)} ) if $parent->{_mfetchHandler};
1515             EVT_MENU( $actions, $prepare, sub{&{$parent->{_mprepareHandler}}(@_,$modName)} ) if $parent->{_mprepareHandler};
1516             EVT_MENU( $actions, $build, sub{&{$parent->{_mbuildHandler}}(@_,$modName)} ) if $parent->{_mbuildHandler};
1517             EVT_MENU( $actions, $test,sub{&{$parent->{_mtestHandler}}(@_,$modName)} ) if $parent->{_mtestHandler};
1518             EVT_MENU( $actions, $extract, sub{&{$parent->{_mextractHandler}}(@_,$modName)} ) if $parent->{_mextractHandler};
1519             # print "Ending ";
1520             return $self;
1521             }
1522              
1523              
1524              
1525             1;