# vim: set et ts=4 sw=4: # Copyright 2012 Steven Tucker # # This file is part of AdminPanel # # AdminPanel 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 2 of the License, or # (at your option) any later version. # # AdminPanel 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 AdminPanel. If not, see . package AdminPanel::MainDisplay; #============================================================= -*-perl-*- =head1 NAME AdminPanel::MainDisplay - class for AdminPaneol main window =head1 SYNOPSIS $mainDisplay = new AdminPanel::MainDisplay(); $mainDisplay->start(); $mainDisplay->destroy(); =head1 METHODS =head1 DESCRIPTION Long_description =head1 EXPORT exported =head1 SUPPORT You can find documentation for this module with the perldoc command: perldoc AdminPanel::MainDisplay =head1 SEE ALSO SEE_ALSO =head1 AUTHOR Steven Tucker =head1 COPYRIGHT and LICENSE Copyright (C) 2012, Steven Tucker Copyright (C) 2014, Angelo Naselli. AdminPanel 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 2 of the License, or (at your option) any later version. AdminPanel 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 AdminPanel. If not, see . =head1 FUNCTIONS =cut =head1 VERSION Version 0.01 =cut our $VERSION = '1.0.0'; use strict; use warnings; use diagnostics; use AdminPanel::SettingsReader; use AdminPanel::ConfigReader; use AdminPanel::Category; use AdminPanel::Module; use Data::Dumper; use yui; #============================================================= =head2 new =head3 DESCRIPTION This method instanziates the MainWindo object, and setups the startup GUI. =cut #============================================================= sub new { my $self = { my $categories = 0, my $event = 0, my $factory = 0, my $mainWin = 0, my $mainLayout = 0, my $menuLayout = 0, my $menus = { my $file = 0, my $help = 0 }, my $layout = 0, my $leftPane = 0, my $rightPane = 0, my $currCategory = 0, my $confDir = 0, my $title = 0, my $settings = 0, my $exitButton = 0, # my $justToGetRidOfERROR = 0, my $replacePoint = 0 }; bless $self, 'AdminPanel::MainDisplay'; ## Default values $self->{name} = "Administration panel"; $self->{categories} = []; $self->{confDir} = "/etc/apanel", $self->{title} = "apanel", my $cmdline = new yui::YCommandLine; ## TODO add parameter check my $pos = $cmdline->find("--name"); if ($pos > 0) { $self->{title} = $cmdline->arg($pos+1); } $pos = $cmdline->find("--conf_dir"); if ($pos > 0) { $self->{confDir} = $cmdline->arg($pos+1); } else { $self->{confDir} = "/etc/$self->{title}"; } $self->setupGui(); return $self; } ## Begin the program event loop sub start { my ($self) = shift; my $reqExit = 0; ##Default category selection if (!$self->{currCategory}) { $self->{currCategory} = @{$self->{categories}}[0]; } $self->{currCategory}->addButtons($self->{rightPane}, $self->{factory}); $self->{rightPaneFrame}->setLabel($self->{currCategory}->{name}); $self->{factory}->createSpacing($self->{rightPane}, 1, 1, 1.0 ); my $launch = 0; while(!$launch) { ## Grab Event $self->{event} = $self->{mainWin}->waitForEvent(); my $eventType = $self->{event}->eventType(); ## Check for window close if ($eventType == $yui::YEvent::CancelEvent) { last; } elsif ($eventType == $yui::YEvent::MenuEvent) { ### MENU ### my $item = $self->{event}->item(); if ($item->label() eq $self->{menus}->{file}[0]->label()) { ## quit menu item last; } } elsif ($eventType == $yui::YEvent::WidgetEvent) { my $widget = $self->{event}->widget(); ## Check for Exit button push or menu if($widget == $self->{exitButton}) { last; } else { # category button selected? my $isCat = $self->_categorySelected($widget); if (!$isCat) { # module button selected? $launch = $self->_moduleSelected($widget); } } } } return $launch; } #============================================================= =head2 destroy =head3 INPUT $self: this object =head3 DESCRIPTION This method destroyes the main window and all the relevanto bojects (category and modules buttons). =cut #============================================================= sub destroy { my ($self) = shift; $self->{mainWin}->destroy(); for (my $cat=0; $cat < scalar(@{$self->{categories}}); $cat++ ) { @{$self->{categories}}[$cat]->{button} = 0; @{$self->{categories}}[$cat]->removeButtons(); } } #============================================================= =head2 setupGui =head3 INPUT $self: this object =head3 DESCRIPTION This method load configuration and build the GUI layout. =cut #============================================================= sub setupGui { my ($self) = shift; $self->_loadSettings(); yui::YUILog::setLogFileName($self->{settings}->{log}); $self->{name} = $self->{settings}->{title}; yui::YUI::app()->setApplicationTitle($self->{name}); yui::YUI::app()->setApplicationIcon($self->{settings}->{icon}); $self->{factory} = yui::YUI::widgetFactory; $self->{mainWin} = $self->{factory}->createMainDialog; $self->{mainLayout} = $self->{factory}->createVBox($self->{mainWin}); $self->{menuLayout} = $self->{factory}->createHBox($self->{mainLayout}); ## Menu file ## TODO i8n my $align = $self->{factory}->createAlignment($self->{menuLayout}, 1, 0); my $menu = $self->{factory}->createMenuButton($align, "File"); my $item = new yui::YMenuItem("Exit"); push(@{$self->{menus}->{file}}, $item); $menu->addItem($item); $menu->rebuildMenuTree(); $align = $self->{factory}->createAlignment($self->{menuLayout}, 2, 0); $menu = $self->{factory}->createMenuButton($align, "Help"); $item = new yui::YMenuItem("Help"); $menu->addItem($item); push(@{$self->{menus}->{help}}, $item); $item = new yui::YMenuItem("About"); $menu->addItem($item); push(@{$self->{menus}->{help}}, $item); $menu->rebuildMenuTree(); $self->{layout} = $self->{factory}->createHBox($self->{mainLayout}); #create left Panel Frame no need to add a label for title $self->{leftPaneFrame} = $self->{factory}->createFrame($self->{layout}, $self->{settings}->{category_title}); #create right Panel Frame no need to add a label for title (use setLabel when module changes) $self->{rightPaneFrame} = $self->{factory}->createFrame($self->{layout}, ""); #create replace point for dynamically created widgets $self->{replacePoint} = $self->{factory}->createReplacePoint($self->{rightPaneFrame}); $self->{rightPane} = $self->{factory}->createVBox($self->{replacePoint}); $self->{leftPane} = $self->{factory}->createVBox($self->{leftPaneFrame}); #logo from settings my $logo = $self->{factory}->createImage($self->{leftPane}, $self->{settings}->{logo}); $logo->setAutoScale(1); # $self->{leftPaneFrame}->setWeight(0, 1); $self->{rightPaneFrame}->setWeight(0, 2); $self->_loadCategories(); $self->{factory}->createVStretch($self->{leftPane}); $self->{exitButton} = $self->{factory}->createPushButton($self->{leftPane}, "Exit"); $self->{exitButton}->setIcon("$self->{settings}->{images_dir}/quit.png"); $self->{exitButton}->setStretchable(0, 1); } ## internal methods ## Check if event is from current Category View ## If icon click, returns the module to be launched sub _moduleSelected { my ($self, $selectedWidget) = @_; for(@{$self->{currCategory}->{modules}}) { if( $_->{button} == $selectedWidget ){ return $_; } } return 0; } ## Discover if a category button was selected. ## If category button is selected, sets right panel to display ## the selected Category Modules ## returns 1 if category button is selected sub _categorySelected { my ($self, $selectedWidget) = @_; for (@{$self->{categories}}) { if( $_->{button} == $selectedWidget ) { #if current is already set then skips if ($self->{currCategory} == $_) { ## returns 1 to skip any other checks on ## the selected widget return 1; } ## Menu item selected, set right pane $self->{mainWin}->startMultipleChanges(); ## Remove existing modules $self->{replacePoint}->deleteChildren(); $self->{rightPane} = $self->{factory}->createVBox($self->{replacePoint}); ## Change Current Category to the selected one $self->{currCategory} = $_; ## Add new Module Buttons to Right Pane $self->{currCategory}->addButtons($self->{rightPane}, $self->{factory}); $self->{rightPaneFrame}->setLabel($self->{currCategory}->{name}); $self->{factory}->createSpacing($self->{rightPane}, 1, 1, 1.0 ); $self->{replacePoint}->showChild(); $self->{mainWin}->recalcLayout(); $self->{mainWin}->doneMultipleChanges(); return 1; } } return 0; } ## adpanel settings sub _loadSettings { my ($self, $force_load) = @_; # configuration file name my $fileName = "$self->{confDir}/settings.conf"; die "Configuration file missing" if (! -e $fileName); if (!$self->{settings} || $force_load) { $self->{settings} = new AdminPanel::SettingsReader($fileName); } } #============================================================= # _categoryLoaded # # INPUT # # $self: this object # $category: category to look for # # OUTPUT # # $present: category is present or not # # DESCRIPTION # # This method looks for the given category and if already in # returns true. # #============================================================= sub _categoryLoaded { my ($self, $category) = @_; my $present = 0; if (!$category) { return $present; } foreach my $cat (@{$self->{categories}}) { if ($cat->{name} eq $category->{name}) { $present = 1; last; } } return $present; } #============================================================= # _getCategory # # INPUT # # $self: this object # $name: category name # # OUTPUT # # $category: category object if exists # # DESCRIPTION # # This method looks for the given category name and returns # the realte object. #============================================================= sub _getCategory { my ($self, $name) = @_; my $category = undef; foreach $category (@{$self->{categories}}) { if ($category->{name} eq $name) { return $category; } } return $category; } # _loadCategory # # creates a new button representing a category # sub _loadCategory { my ($self, $category) = @_; if (!$self->_categoryLoaded($category)) { push ( @{$self->{categories}}, $category ); @{$self->{categories}}[-1]->{button} = $self->{factory}->createPushButton( $self->{leftPane}, $self->{categories}[-1]->{name} ); @{$self->{categories}}[-1]->setIcon(); @{$self->{categories}}[-1]->{button}->setStretchable(0, 1); } else { for (my $cat=0; $cat < scalar(@{$self->{categories}}); $cat++ ) { if( @{$self->{categories}}[$cat]->{name} eq $category->{name} && !@{$self->{categories}}[$cat]->{button}) { @{$self->{categories}}[$cat]->{button} = $self->{factory}->createPushButton( $self->{leftPane}, $self->{categories}[$cat]->{name} ); @{$self->{categories}}[$cat]->setIcon(); @{$self->{categories}}[$cat]->{button}->setStretchable(0, 1); last; } } } } sub _loadCategories { my ($self) = @_; # category files my @categoryFiles; my $fileName = "$self->{confDir}/categories.conf"; # configuration file dir my $directory = "$self->{confDir}/categories.conf.d"; push(@categoryFiles, $fileName); push(@categoryFiles, <$directory/*.conf>); my $currCategory; foreach $fileName (@categoryFiles) { my $inFile = new AdminPanel::ConfigReader($fileName); my $tmpCat; my $tmp; my $hasNextCat = $inFile->hasNextCat(); while( $hasNextCat ) { $tmp = $inFile->getNextCat(); $tmpCat = $self->_getCategory($tmp->{title}); if (!$tmpCat) { $tmpCat = new AdminPanel::Category($tmp->{title}, $tmp->{icon}); } $self->_loadCategory($tmpCat); $hasNextCat = $inFile->hasNextCat(); $currCategory = $tmpCat; my $hasNextMod = $inFile->hasNextMod(); while( $hasNextMod ) { $tmp = $inFile->getNextMod(); my $tmpMod; my $loaded = 0; if (exists $tmp->{title}) { if (not $currCategory->moduleLoaded($tmp->{title})) { $tmpMod = AdminPanel::Module->create(name => $tmp->{title}, icon => $tmp->{icon}, launch => $tmp->{launcher} ); } } elsif (exists $tmp->{class}) { if (not $currCategory->moduleLoaded(-CLASS => $tmp->{class})) { $tmpMod = AdminPanel::Module->create(-CLASS => $tmp->{class}); } } if ($tmpMod) { $loaded = $currCategory->loadModule($tmpMod); undef $tmpMod if !$loaded; } $hasNextMod = $inFile->hasNextMod(); } } } } 1; =pod =head2 start contains the main loop of the application where we can check for events =head2 setupGui creates a popupDialog using a YUI::WidgetFactory and then populate this dialog with some components =cut