From 126bb8cb6b93240bb4d3a2b816b74c286c3d422b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Frings-F=C3=BCrst?= Date: Sun, 6 Jul 2014 15:20:38 +0200 Subject: Imported Upstream version 1.7.0 --- lib/gcstar/GCPanel.pm | 1540 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1540 insertions(+) create mode 100644 lib/gcstar/GCPanel.pm (limited to 'lib/gcstar/GCPanel.pm') diff --git a/lib/gcstar/GCPanel.pm b/lib/gcstar/GCPanel.pm new file mode 100644 index 0000000..756ee65 --- /dev/null +++ b/lib/gcstar/GCPanel.pm @@ -0,0 +1,1540 @@ +package GCPanel; + +################################################### +# +# Copyright 2005-2010 Christian Jodar +# +# This file is part of GCstar. +# +# GCstar 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. +# +# GCstar 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 GCstar; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA +# +################################################### +use utf8; +use Gtk2; +use GCBorrowings; +use GCGraphicComponents::GCBaseWidgets; + +use strict; + +{ + package GCItemPanel; + @GCItemPanel::ISA = ('Gtk2::Frame'); + + sub new + { + my ($proto, $parent, $options, $layout) = @_; + my $class = ref($proto) || $proto; + my $self = $class->SUPER::new(); + + bless ($self, $class); + + $self->{disableBorrowerChange} = 0; + $self->{autoUpdate} = 1; + $self->{previouslyHidden} = 0; + + $self->{expanders} = []; + $self->{dateFields} = []; + $self->{longTextFields} = []; + $self->{formatted} = []; + #Stores for each fields the widgets which depends on it + # (used for formatted and launcher) + $self->{dependencies} = {}; + + $self->{parent} = $parent; + $self->{lang} = $parent->{lang}; + $self->{options} = $options; + $self->{layout} = $layout; + $self->set_shadow_type('none'); + + #$self->{defaultImage} = $parent->getDefaultImage; + $self->{tooltips} = $parent->{tooltips}; + + $self->{infoBox} = new Gtk2::VBox(1,0); + $self->{viewAllBox} = new Gtk2::EventBox; + $self->{viewAllVBox} = new Gtk2::VBox(0,0); + $self->{viewAll} = new Gtk2::HBox(0,0); + $self->{viewAllButton} = new Gtk2::Button->new_from_stock('gtk-refresh'); + $self->{viewAll}->pack_start($self->{viewAllButton},1,0,50); + $self->{viewAllVBox}->pack_start($self->{viewAll},0,0,0); + $self->{viewAllBox}->add($self->{viewAllVBox}); + $self->{viewAllButton}->signal_connect('clicked' => sub { + $self->{parent}->viewAllItems; + }); + + $self->{margin} = $GCUtils::margin; + $self->{halfMargin} = $GCUtils::halfMargin; + $self->{quarterMargin} = $GCUtils::quarterMargin; + + return $self; + } + + sub loadStyles + { + my ($self, $style) = @_; + } + + + sub setExpandersMode + { + my ($self, $mode) = @_; + $_->setMode($mode) + foreach (@{$self->{expanders}}); + } + + sub setDateFormat + { + my ($self, $format) = @_; + foreach (@{$self->{dateFields}}) + { + $_->setFormat($format); + $_->resetChanged; + } + } + + sub setSpellChecking + { + my ($self, $activate, $lang) = @_; + foreach (@{$self->{longTextFields}}) + { + $_->setSpellChecking($activate, $lang); + } + } + + sub createContent + { + my ($self, $model) = @_; + return if $self->{model} + && ($self->{model}->getName eq $model->getName); + + if ($self->{model}) + { + my @children = $self->{mainBox}->get_children; + $self->{mainBox}->remove($_) foreach (@children); + foreach (@{$self->{toDestroy}}) + { + $_->destroy if $_; + } + } + + $self->{model} = $model; + $self->{fieldsInfo} = $self->{model}->{fieldsInfo}; + $self->{toDestroy} = []; + foreach (@{$model->{fieldsNames}}) + { + $self->{$_} = $self->createItem($self->{model}->{fieldsInfo}->{$_}); + push @{$self->{toDestroy}}, $self->{$_}; + $self->{$_.'Label'} = $self->createLabel($self->{model}->{fieldsInfo}->{$_}, $self->{withSeparator}); + push @{$self->{toDestroy}}, $self->{$_.'Label'}; + } + $self->createSpecial; + + $self->{displayedValues} = {}; + $self->createLayout($self->{layout}, $self->{layoutBox}); + + $self->show_all; + } + + sub initShow + { + my ($self, $show, $hasToShow) = @_; + + $self->{show} = $show; + + if ($hasToShow) + { + $self->show_all; + $self->{infoBox}->hide; + return 1; + } + else + { + $self->hide(0); + $self->{previouslyHidden} = 1; + return 0; + } + } + + sub show + { + my $self = shift; + $self->{mainBox}->show; + $self->{infoBox}->hide; + $self->setShowOption($self->{show}, 1) if $self->{previouslyHidden}; + $self->{previouslyHidden} = 0; + } + + sub setShowOption + { + my ($self, $show, $hasToShow) = @_; + return if ! $self->initShow($show, $hasToShow); + my %parentsToHide; + foreach (keys %{$show}) + { + $self->{$_.'Label'}->hide if (! $show->{$_}) && ($self->{$_.'Label'}); + my $widget = $self->{$_}; + if ($widget) + { + if ($show->{$_}) + { + # Useful for GCLinkedComponent + $widget->show if !$widget->isa('Gtk2::Widget'); + #$parentsToHide{$widget->{realParent}} = 0; + my $parent = $widget->{realParent}; + while ($parent) + { + $parentsToHide{$parent} = 0; + $parent = $parent->{realParent}; + } + foreach my $dependency(@{$self->{dependencies}->{$_}}) + { + $parentsToHide{$dependency->{realParent}} = 0; + } + } + else + { + $widget->hide; + $parentsToHide{$widget->{realParent}} = $widget->{realParent} if ! exists $parentsToHide{$widget->{realParent}}; + foreach my $dependency(@{$self->{dependencies}->{$_}}) + { + $dependency->hide; + } + } + } + } + + foreach (keys %parentsToHide) + { + if ($parentsToHide{$_}) + { + $parentsToHide{$_}->hide; + $parentsToHide{$_}->{realParent}->hide + if ($parentsToHide{$_}->{realParent}) + && ($parentsToHide{$_}->{realParent}->isa('GCExpander')); + } + } + + $self->setShowOptionForSpecials($show, $hasToShow); + } + + sub setShowOptionForSpecials + { + my ($self, $show, $hasToShow) = @_; + } + + sub hide + { + my ($self, $filtering) = @_; + $self->{infoBox}->show_all; + if ($filtering) + { + $self->{warning}->set_markup(''.$self->{lang}->{AllItemsFiltered}.''); + } + else + { + $self->{warning}->set_markup($self->{lang}->{Warning}) if !$filtering; + $self->{viewAllBox}->hide; + } + $self->{mainBox}->hide; + } + + sub showMe + { + my $self = shift; + my $parent = $self->parent; + while ($parent) + { + last if ($parent->isa('Gtk2::Window')); + $parent = $parent->parent; + } + $parent->present if $parent; + } + + sub isReadOnly + { + return 1; + } + + sub getAsHash + { + my $self = shift; + my $hash = {}; + $hash->{$_} = $self->$_ foreach(@{$self->{parent}->{model}->{fieldsNames}}); + return $hash; + } + + sub getValue + { + my ($self, $field) = @_; + + return $self->$field; + } + + sub disableBorrowerChange + { + my $self = shift; + $self->{disableBorrowerChange} = 1; + } + + sub disableAutoUpdate + { + my $self = shift; + $self->{autoUpdate} = 0; + } + + sub dataChanged + { + my ($self, $info, $withoutPanel) = @_; + + if (!$withoutPanel) + { + foreach (@{$self->{expanders}}) + { + $self->setExpanderLabel($_, 1); + } + } + foreach (@{$self->{formatted}}) + { + $self->setFormattedLabel($_, 1, $info, $withoutPanel); + } + } + + sub createLabel + { + my ($self, $info, $withSeparator) = @_; + + my $label = $self->{model}->getDisplayedText($info->{label}); + $label .= $self->{parent}->{lang}->{Separator} if $withSeparator; + my $widget = new Gtk2::Label($label); + $widget->set_alignment(0, 0.5); + return $widget; + } + + sub createExpander + { + my ($self, $label) = @_; + + return new GCExpander($label); + } + + sub formatLabel + { + my ($self, $format, $info) = @_; + + my $label = $format; + + # Remove from format conditional part using this format: + # =field.....= + $label =~ s/\=(\w*)([^\=]*)\=/($self->{show}->{$1}) ? $2 : ''/eg; + + # Allow formatting using %fields[format]% + if ($info) + { + $label =~ s/%(.*?)(\[(.*?)\])*%/$3 ? sprintf($3,$info->{$1}) : $info->{$1}/eg; + } + else + { + $label =~ s/%(.*?)(\[(.*?)\])*%/$3 ? sprintf($3,$self->{$1}->getValue(1)) : $self->{$1}->getValue(1)/eg; + } + if ($label =~ /^=(.*)$/) + { + $label = eval $1; + } + + $label =~ s/@(.*?)@/$self->{model}->getDisplayedText($1)/eg; + + # Strings between ^ cannot be on the end or on the beginning. + # Typically used for separators + $label =~ s/^\^([^\^]*)\^//; + $label =~ s/\^([^\^]*)\^$//; + $label =~ s/\^//g; + + return $label; + } + + sub setExpanderLabel + { + my ($self, $expander, $init) = @_; + + if ($expander->{collapsedTemplate} + && ($expander->get_expanded xor $init)) + { + my $label = $self->formatLabel($expander->{collapsedTemplate}); + $expander->setValue($expander->{originalLabel}.($label ? $self->{parent}->{lang}->{Separator} : ""), + $self->formatLabel($expander->{collapsedTemplate})); + } + else + { + $expander->setValue($expander->{originalLabel}); + } + } + + sub setAsFormatted + { + my ($self, $widget, $name, $format) = @_; + $widget->{format} = $format; + $widget->{name} = $name; + push @{$self->{formatted}}, $widget; + while ($format =~ /%(.*?)%/g) + { + push @{$self->{dependencies}->{$1}}, $widget; + } + } + + sub setFormattedLabel + { + my ($self, $label, $init, $info, $withoutPanel) = @_; + + my $name = $label->{name}; + if ($withoutPanel) + { + $info->{$name} = $self->formatLabel($label->{format}, $info); + } + else + { + $self->$name($self->formatLabel($label->{format})); + # We store here the value so it could be used by caller if needed + # The user is GCData::updateSelectedItemInfoFromPanel + $info->{$name} = $self->$name if defined $info; + } + } + + sub prepareDate + { + my ($self, $value) = @_; + + return GCUtils::timeToStr($value, $self->{parent}->{options}->dateFormat) + } + + sub addToContainer + { + my ($self, $container, $widget, $info) = @_; + $info->{expand} = 'default' if !exists $info->{expand}; + if ($container->isa('Gtk2::Notebook')) + { + $container->append_page($widget, + $self->{model}->getDisplayedText($info->{title})); + } + elsif ($container->isa('Gtk2::Table')) + { + my $left = $info->{col}; + my $right = $left + ($info->{colspan} ? $info->{colspan} : 1); + my $top = $info->{row}; + my $bottom = $top + ($info->{rowspan} ? $info->{rowspan} : 1); + my $fill = []; + push @$fill, 'fill' if $info->{expand} ne 'false'; + push @$fill, 'expand' if $info->{expand} eq 'true'; + if ($info->{expand} eq 'shrink') + { + $fill = ['expand', 'fill']; + my $hbox = new Gtk2::HBox(0,0); + $hbox->pack_start($widget,0,0,0); + $widget = $hbox; + } + if ($info->{expand} eq 'horizontal') + { + $container->attach($widget, + $left, $right, $top, $bottom, + ['expand', 'fill'], [], + 0, 0); + } + else + { + $container->attach($widget, + $left, $right, $top, $bottom, + $fill, $fill, + 0, 0); + } + } + else + { + my $expand = ($info->{expand} eq 'true') ? 1 : 0; + if ($container->isa('Gtk2::VBox')) + { + my $margin = $self->{halfMargin}; + $margin = 0 if (exists $info->{nomargin}) && ($info->{nomargin} eq 'true'); + if ((exists $info->{place}) && ($info->{place} eq 'end')) + { + $container->pack_end($widget, $expand, $expand, $margin); + } + else + { + $container->pack_start($widget, $expand, $expand, $margin); + } + } + else + { + my $margin = $self->{halfMargin}; + $margin = 0 if (exists $info->{nomargin}) && ($info->{nomargin} eq 'true'); + if (($container->get_children) && (!$container->get_homogeneous) && ($margin > 0)) + { + my $marginBox = new Gtk2::HBox(0,0); + $container->pack_start($marginBox, 0, 0, $margin); + } + $container->pack_start($widget, $expand, $expand, 0) + if ref($widget) ne 'HASH'; + } + } + } + + sub setWidgetStyle + { + my ($self, $widget, $name, $style) = @_; + } + + sub getWidget + { + my ($self, $field, $info) = @_; + return $self->{$field}; + } + + sub createLayout + { + my ($self, $xml, $container, $parent, $noTab) = @_; + # + foreach (@{$xml->{item}}) + { + my $widget; + my $box; + my $isContainer = 0; + + # TODO We should return an error here + $_->{type} = 'default' if ! exists $_->{type}; + + if ($_->{type} eq 'formatted') + { + my $info = {}; + $info->{type} = 'short text'; + $info->{value} = $_->{name}; + $widget = $self->createItem($info); + $self->{$_->{name}} = $widget; + $self->setAsFormatted($widget, $_->{name}, $_->{value}); + $_->{for} = $widget->{name}; + } + elsif ($_->{type} eq 'value') + { + $widget = $self->getWidget($_->{for}, $_); + if ($widget) + { + $widget->setWidth($_->{width}) if $_->{width}; + $widget->setHeight($_->{height}) if $_->{height}; + $widget->expand if (exists $_->{expand}) && ($_->{expand} eq 'true'); + if ($_->{values} || $self->{model}->{fieldsInfo}->{$_->{for}}->{values}) + { + $self->{displayedValues}->{$_->{for}} = + $_->{values} + || $self->{model}->{fieldsInfo}->{$_->{for}}->{values}; + } + # If the item is related to another, it has to be hidden with it + if (exists $self->{model}->{fieldsInfo}->{$_->{for}}->{relatedto}) + { + my $relatedTo = $self->{model}->{fieldsInfo}->{$_->{for}}->{relatedto}; + push @{$self->{dependencies}->{$relatedTo}}, $widget; + } + } + } + elsif ($_->{type} eq 'label') + { + if ($_->{for}) + { + $widget = $self->{$_->{for}.'Label'}; + } + else + { + $widget = $self->createLabel($_, $self->{withSeparator}); + } + if ((exists $_->{align}) && ($_->{align} eq 'center')) + { + $widget->set_alignment(0.5, 0.5); + if ($self->{withSeparator}) + { + my $label = $widget->get_label; + my $sep = $self->{parent}->{lang}->{Separator}; + $label =~ s/$sep$//; + $widget->set_label($label); + } + } + $widget->set_alignment(0, 0) if (exists $_->{align}) && ($_->{align} eq 'top'); + } + elsif ($_->{type} eq 'special') + { + $widget = $self->{$_->{for}}; + $widget->{param} = $_->{param}; + } + elsif ($_->{type} eq 'launcher') + { + my $valueWidget = $self->{$_->{for}}; + my $format = $self->{model}->{fieldsInfo}->{$_->{for}}->{format}; + + # If the launcher is for a video or music file, label the button 'play' + if (($format eq 'video') || ($format eq 'audio')) + { + $widget = Gtk2::Button->new_from_stock('gtk-media-play'); + } + elsif ($format eq 'program') + { + # For program launchers, label the button 'launch' + $widget = Gtk2::Button->new($self->{parent}->{lang}->{PanelLaunch}); + } + else + { + # Label the button 'open' + $widget = Gtk2::Button->new_from_stock('gtk-open'); + } + + $widget->signal_connect('clicked' => sub { + $self->{parent}->launch($valueWidget->getValue, $format); + }); + push @{$self->{dependencies}->{$_->{for}}}, $widget; + } + elsif ($_->{type} eq 'extractor') + { + $widget = Gtk2::Button->new($self->{parent}->{lang}->{ExtractButton}); + my $valueWidget = $self->{$_->{for}}; + $widget->signal_connect('clicked' => sub { + $self->{parent}->extractInfo($valueWidget->getValue, $self); + }); + push @{$self->{dependencies}->{$_->{for}}}, $widget; + } + elsif ($_->{type} eq 'line') + { + my $homogeneous = (exists $_->{homogeneous} && ($_->{homogeneous} eq 'true')) + ? 1 : 0; + $widget = new Gtk2::HBox($homogeneous, $self->{margin}); + #$widget->set_border_width($self->{halfMargin}); + $widget->set_size_request(-1, $_->{height}) if $_->{height}; + $box = $widget; + $isContainer = 1; + } + elsif ($_->{type} eq 'box') + { + $widget = new Gtk2::VBox(0,0); + #$widget->set_border_width($self->{halfMargin}); + $box = $widget; + if ($_->{width}) + { +# $widget = new Gtk2::EventBox; +# $widget->add($box); + $widget->set_size_request($_->{width}, -1); + } + $isContainer = 1; + } + elsif ($_->{type} eq 'notebook') + { + if ($noTab) + { + $widget = new Gtk2::VBox(0,0); + } + else + { + $widget = new Gtk2::Notebook; + } + #$widget->set_border_width($self->{margin}); + $box = $widget; + $isContainer = 1; + } + elsif ($_->{type} eq 'tab') + { + $widget = new Gtk2::VBox(0,0); + if ($noTab) + { + my $label = new Gtk2::Label; + $label->set_markup(''.$self->{model}->getDisplayedText($_->{title}).''); + $label->set_alignment(0,0); + $widget->pack_start($label, 0, 0, 0); + $widget->set_border_width(0); + $box = new Gtk2::VBox(0,0); + $box->set_border_width($self->{margin}); + $widget->pack_start($box, 1, 1, 0); + } + else + { + $widget->set_border_width($self->{margin}); + $box = $widget; + } + $isContainer = 1; + } + elsif ($_->{type} eq 'table') + { + $widget = new Gtk2::Table($_->{rows},$_->{cols}); + #$widget->set_border_width($self->{margin}); + $widget->set_col_spacings($self->{colSpacing}); + $widget->set_row_spacings($self->{rowSpacing}); + $box = $widget; + $isContainer = 1; + } + elsif ($_->{type} eq 'frame') + { + $widget = new GCGroup($self->{model}->getDisplayedText($_->{title})); + $widget->set_border_width(0); + $widget->setPadding(0); + $box = new Gtk2::Table($_->{rows},$_->{cols}); + $box->set_border_width($self->{halfMargin}); + $box->set_col_spacings($self->{margin}); + $box->set_row_spacings($self->{halfMargin}); + $widget->addWidget($box); + $isContainer = 1; + } + elsif ($_->{type} eq 'expander') + { + #$widget = new GCExpander($self->{model}->getDisplayedText($_->{title})); + $widget = $self->createExpander($self->{model}->getDisplayedText($_->{title})); + $widget->setMode($self->{parent}->{options}->expandersMode); + $widget->{originalLabel} = $self->{model}->getDisplayedText($_->{title}); + $widget->{collapsedTemplate} = $_->{collapsed}; + $self->setExpanderLabel($widget, 1); + $widget->signal_connect('activate' => sub { + $self->setExpanderLabel($widget, 0); + }); + $widget->set_expanded(1) if (defined $_->{expanded}) && ($_->{expanded} eq 'true'); + push @{$self->{expanders}}, $widget; + $box = new Gtk2::VBox(0,0); + $box->set_border_width($self->{halfMargin}); + $widget->add($box); + $isContainer = 1; + $_->{style} = 'expander' if !exists $_->{style}; + } + + if (exists $_->{border}) + { + $widget->set_border_width($_->{border}); + } + + if (exists $_->{collapse}) + { + $widget->{collapse} = $_->{collapse}; + } + + if ($isContainer) + { + $self->createLayout($_, $box, $widget, $noTab); + } + push @{$self->{toDestroy}}, $widget; + $widget->{realParent} = $parent if $parent; + $self->setWidgetStyle($widget, $_->{for}, $_->{style}) if $_->{style}; + $self->addToContainer($container, $widget, $_) if $widget; + } + } +} + +{ + package GCReadOnlyPanel; + + use Glib::Object::Subclass + Gtk2::Frame:: + ; + + @GCReadOnlyPanel::ISA = ('GCItemPanel'); + + use File::Basename; + + sub new + { + my ($proto, $parent, $options, $layout) = @_; + my $class = ref($proto) || $proto; + my $self = $class->SUPER::new($parent, $options, $layout); + + bless ($self, $class); + + $self->{withSeparator} = 0; + $self->{colSpacing} = $self->{quarterMargin}; + $self->{rowSpacing} = $self->{quarterMargin}; + $self->loadStyles($options->panelStyle); + + $self->{inBox} = new Gtk2::VBox(0, 0); + $self->{inBox}->set_border_width($self->{margin}); + + $self->set_name('GCItemFrame'); + + $self->{inBox} = new Gtk2::VBox(0, 0); + my $hboxMargins = new Gtk2::HBox(0,0); + $hboxMargins->pack_start($self->{inBox}, 1, 1, 50); + $self->{mainBox} = new Gtk2::EventBox; + $self->{mainBox}->modify_bg('normal', $self->{styles}->{page}->{bgColor}); + $self->{mainBox}->add($hboxMargins); + + my $realMain = new Gtk2::VBox(0,0); + +# GCUtils::setWidgetPixmap($self->{mainBox},$ENV{GCS_SHARE_DIR}.'/logos/splash.png'); + +# $self->{backgroundPixbuf} = Gtk2::Gdk::Pixbuf->new_from_file($ENV{GCS_SHARE_DIR}.'/logos/splash.png'); +# $self->{mainBox}->signal_connect('expose-event' => sub { +# $self->paintBg; +# }); + + $realMain->pack_start($self->{mainBox},1,1,0); + + $self->{layoutBox} = $self->{inBox}; + + $self->add($realMain); + $self->show_all; + + + $self->{warning} = new Gtk2::Label; + + $self->{infoBox}->pack_start($self->{warning},1,1,0); + $self->{infoBox}->pack_start($self->{viewAllBox},1,1,0); + $realMain->pack_start($self->{infoBox},1,1,0); + + return $self; + } + + sub loadStyles + { + my ($self, $style) = @_; + + $self->{styles} = {}; + my $styleFile = $ENV{GCS_SHARE_DIR}.'/panels/'.$style; + + open STYLE, $styleFile; + while (