# 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 AdminPanel::Shared; use AdminPanel::Shared::GUI; use AdminPanel::Shared::Locales; use File::ShareDir ':ALL'; use yui; #============================================================= =head2 new =head3 DESCRIPTION This method instanziates the MainWindo object, and setups the startup GUI. =cut #============================================================= sub new { my $self = { categories => 0, event => 0, factory => 0, mainWin => 0, mainLayout => 0, menuLayout => 0, menus => { file => 0, help => 0 }, layout => 0, leftPane => 0, rightPane => 0, currCategory => 0, confDir => 0, title => 0, settings => 0, exitButton => 0, loc => 0, replacePoint => 0, }; bless $self, 'AdminPanel::MainDisplay'; ## Default values $self->{name} = "Administration panel"; $self->{categories} = []; $self->{confDir} = "/etc/mpan", $self->{title} = "mpan", 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}"; } # TODO localize $self->{loc} = AdminPanel::Shared::Locales->new(domain_name => 'libDrakX-standalone'); $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(); my $menuLabel = $item->label(); if ($menuLabel eq $self->{menus}->{file}->{ quit }->label()) { ## quit menu item last; } elsif ($menuLabel eq $self->{menus}->{help}->{ about }->label()) { my $translators = $self->{loc}->N("_: Translator(s) name(s) & email(s)\n"); $translators =~ s/\/\>\;/g; my $sh_gui = AdminPanel::Shared::GUI->new(); $sh_gui->AboutDialog({ name => $self->{name}, version => $AdminPanel::MainDisplay::VERSION, credits => $self->{loc}->N("Copyright (C) %s Mageia community", '2013-2014'), license => $self->{loc}->N("GPLv2"), description => $self->{loc}->N("mpan is the administration panel that collects all the utilities."), authors => $self->{loc}->N("

Developers

Translators

", "Angelo Naselli <anaselli\@linux.it>", "Matteo Pasotti <matteo.pasotti\@gmail.com>", $translators ), }); } elsif ($menuLabel eq $self->{menus}->{help}->{ help }->label()) { # TODO Help } } 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}) if defined($self->{settings}->{log}); $self->{name} = $self->{settings}->{title}; yui::YUI::app()->setApplicationTitle($self->{name}); my $icon = defined($self->{settings}->{icon}) ? $self->{settings}->{icon} : File::ShareDir::dist_file(AdminPanel::Shared::distName(), 'images/mageia.png'); yui::YUI::app()->setApplicationIcon($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 my $align = $self->{factory}->createAlignment($self->{menuLayout}, 1, 0); $self->{menus}->{file} = { widget => $self->{factory}->createMenuButton($align, $self->{loc}->N("File")), quit => new yui::YMenuItem($self->{loc}->N("&Exit")), }; my @ordered_menu_lines = qw(quit); foreach (@ordered_menu_lines) { $self->{menus}->{file}->{ widget }->addItem($self->{menus}->{file}->{ $_ }); } $self->{menus}->{file}->{ widget }->rebuildMenuTree(); $align = $self->{factory}->createAlignment($self->{menuLayout}, 2, 0); $self->{menus}->{help} = { widget => $self->{factory}->createMenuButton($align, $self->{loc}->N("Help")), help => new yui::YMenuItem($self->{loc}->N("Help")), about => new yui::YMenuItem($self->{loc}->N("About")), }; ## Menu Help @ordered_menu_lines = qw(help about); foreach (@ordered_menu_lines) { $self->{menus}->{help}->{ widget }->addItem($self->{menus}->{help}->{ $_ }); } $self->{menus}->{help}->{ widget }->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 $logofile = defined($self->{settings}->{logo}) ? $self->{settings}->{logo} : File::ShareDir::dist_file(AdminPanel::Shared::distName(), 'images/logo_mageia.png'); my $logo = $self->{factory}->createImage($self->{leftPane}, $logofile); $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"); my $quitIcon = File::ShareDir::dist_file(AdminPanel::Shared::distName(), 'images/quit.png'); $self->{exitButton}->setIcon($quitIcon); $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