App-Chart

 view release on metacpan or  search on metacpan

lib/App/Chart/Gtk2/Main.pm  view on Meta::CPAN

     },
   },
   
   { name        => 'Centre',
     label       => __('_Centre'),
     accelerator => __p('Main-accelerator-key','<Ctrl>C'),
     callback    => sub { my ($action, $self) = @_;
                          $self->{'view'}->centre; }
   },
   { name        => 'ZoomInX',
     label       => __('Zoom Wider'),
     accelerator => __p('Main-accelerator-key','W'),
     callback    => sub { my ($action, $self) = @_;
                          $self->{'view'}->zoom (1.5, 1) }
   },
   { name        => 'ZoomOutX',
     label       => __('Zoom Narrower'),
     accelerator => __p('Main-accelerator-key','<Shift>W'),
     callback    => sub { my ($action, $self) = @_;
                          $self->{'view'}->zoom (0.75, 1) }
   },
   { name        => 'ZoomInY',
     stock_id    => 'gtk-zoom-in',
     accelerator => __p('Main-accelerator-key','Z'),
     callback    => sub { my ($action, $self) = @_;
                          $self->{'view'}->zoom (1, 1.5) }
   },
   { name        => 'ZoomOutY',
     stock_id    => 'gtk-zoom-out',
     accelerator => __p('Main-accelerator-key','<Shift>Z'),
     callback    => sub { my ($action, $self) = @_;
                          $self->{'view'}->zoom (1, 1/1.5) }
   },
   { name        => 'Redraw',
     label       => __('_Redraw'),
     accelerator => __p('Main-accelerator-key','<Ctrl>L'),
     tooltip     => __('Force a redraw of the entire Chart display.'),
     callback    => sub { my ($action, $self) = @_;
                          $self->queue_draw; }
   },
   { name     => 'Intraday',
     label    => __('_Intraday'),
     tooltip  => __p('Main-accelerator-key','<Ctrl>I'),
     callback => sub {
       my ($action, $self) = @_;
       require App::Chart::Gtk2::IntradayDialog;
       App::Chart::Gtk2::IntradayDialog->popup ($self->get_symbol, $self);
     },
   },
   { name     => 'Annotations',
     label    => __('_Annotations'),
     callback => sub {
       my ($action, $self) = @_;
       require App::Chart::Gtk2::AnnotationsDialog;
       App::Chart::Gtk2::AnnotationsDialog->popup ($self->get_symbol, $self);
     },
   },
   { name     => 'ViewStyle',
     label    => __('_View Style'),
     callback => sub { my ($action, $self) = @_;
                       Gtk2::Ex::WidgetCursor->busy;
                       require App::Chart::Gtk2::ViewStyleDialog;
                       my $vs = App::Chart::Gtk2::ViewStyleDialog->instance_for_screen($self);
                       $vs->present;
                       my $view = $self->{'view'};
                       $vs->set (view => $view,
                                 viewstyle => $view->get('viewstyle'));
                     }
   },
   { name     => 'Raw',
     label    => __('_Raw data'),
     callback => sub { my ($action, $self) = @_;
                       require App::Chart::Gtk2::RawDialog;
                       App::Chart::Gtk2::RawDialog->popup ($self->get_symbol, $self); }
   },
   { name  => "WebMenuItem",
     label => __('_Web')
   },
   
   # Tools menu
   
   { name     => 'Watchlist',
     label    => __('_Watchlist'),
     callback => sub {
       my ($action, $self) = @_;
       App::Chart::Gtk2::Ex::ToplevelBits::popup
           ('App::Chart::Gtk2::WatchlistDialog',
            screen => $self,
            hide_on_delete => 1);
     },
   },
   { name     => 'Download',
     label    => __('_Download'),
     callback => sub { my ($action, $self) = @_;
                       require App::Chart::Gtk2::DownloadDialog;
                       App::Chart::Gtk2::DownloadDialog->popup ($self->get_symbol, $self); }
   },
   { name        => 'DownloadUpdate',
     label       => __('Download _Update'),
     accelerator => __p('Main-accelerator-key','<Ctrl>U'),
     callback    => sub {
       my ($action, $self) = @_;
       # meant to be sensitive only with a symbol, but check anyway
       my $symbol = $self->get_symbol || return;
       require App::Chart::Gtk2::DownloadDialog;
       my $dialog = App::Chart::Gtk2::DownloadDialog->instance_for_screen($self);
       my $job = $dialog->start ($symbol, undef);
       my $jobmsg = ($self->{'jobmsg'} ||= do {
         require App::Chart::Gtk2::JobStatusbarMessage;
         App::Chart::Gtk2::JobStatusbarMessage->new
             (statusbar => $self->{'statusbar'});
       });
       $jobmsg->add_job ($job);
     } },
   { name        => 'History',
     label       => __('_History'),
     tooltip     => __('Dialog of back/forward symbols.'),
     callback    => sub {
       my ($action, $self) = @_;
       App::Chart::Gtk2::Ex::ToplevelBits::popup
           ('Gtk2::Ex::History::Dialog',

lib/App/Chart/Gtk2/Main.pm  view on Meta::CPAN

  #   my $actiongroup = shift;
  #   my $self = $class->new (@_);
  #   $actiongroup->add_action_with_accel ($self, $self->accelerator);
  # }
  # sub accelerator {
  #   my ($self) = @_;
  #   return ($self->get('way') eq 'back'
  #           ? __p('accelerator-key','B')
  #           : __p('accelerator-key','F'));
  # }
  $actiongroup->add_action_with_accel
    (Gtk2::Ex::History::Action->new (name    => 'Back',
                                     way     => 'back',
                                     history => $history),
     __p('accelerator-key-back','B'));
  $actiongroup->add_action_with_accel
    (Gtk2::Ex::History::Action->new (name    => 'Forward',
                                     way     => 'forward',
                                     history => $history),
     __p('accelerator-key-forward','F'));

  # initially nothing
  $actiongroup->get_action('AddFavourite')->set_sensitive (0);
  $actiongroup->get_action('RemoveFavourite')->set_sensitive (0);

  # these actions only sensitive when there's a symbol displayed
  $self->{'symbol_sensitive_actions'} = ['AddFavourite', 'RemoveFavourite',
                                         'Delete', 'Centre', 'DownloadUpdate',
                                         'Annotations'];
  _do_symbol_changed ($self, '');  # hack for initial insensitive

  Gtk2::Ex::ActionTooltips::action_tooltips_to_menuitems_dynamic
    ($actiongroup->get_action('ManualDataSource'),
     $actiongroup->get_action('ManualMovingAverage'),
     $actiongroup->get_action('ManualIndicator'));

  $actiongroup->add_toggle_actions
    # name, stock id, label, accel, tooltip, subr, is_active
    ([{ name        => 'Cross',
        label       => __('_Cross'),
        accelerator => __p('Main-accelerator-key','C'),
        tooltip     => __('Show a crosshair of horizontal and vertical lines following the mouse pointer.'),
        is_active   => 0,
        callback    => sub {
          my ($action, $self) = @_;
          $self->{'crosshair_connect'} ||= do {
            my $cross = $self->{'view'}->crosshair;
            Glib::Ex::ConnectProperties->new ([$action,'active'],
                                              [$cross,'active']);
          };
        },
      },
      { name      => 'Ticker',
        label     => __('_Ticker'),
        is_active => 0,
        tooltip   => __('Show a stock ticker of share prices at the bottom of the window.

Mouse button-1 there drags it back or forward.  Button-3 pops up a menu of options, including which symbol list it shows.'),
        callback  => sub {
          my ($action, $self) = @_;
          Gtk2::Ex::WidgetCursor->busy; # can take a moment to load
          $self->get_or_create_ticker;
        },
      },
      { name      => 'Toolbar',
        label     => __('T_oolbar'),
        tooltip   => __('Show (or not) the toolbar.'),
        is_active => 1,
      },
     ],
     $self);

  my @timebases = qw(App::Chart::Timebase::Days
                     App::Chart::Timebase::Weeks
                     App::Chart::Timebase::Months);
  $actiongroup->add_radio_actions
    ([{ name        => 'Daily',
        label       => __('_Daily'),
        accelerator => __p('Main-accelerator-key','<Ctrl>D'),
        tooltip     => __('Display daily data.'),
        value       => 0,
      },
      { name        => 'Weekly',
        label       =>__('_Weekly'),
        accelerator => __p('Main-accelerator-key','<Ctrl>W'),
        tooltip     => __('Display weekly data.'),
        value       => 1,
      },
      { name        => 'Monthly',
        label       =>__('_Monthly'),
        accelerator => __p('Main-accelerator-key','<Ctrl>M'),
        tooltip     => __('Display monthly data.'),
        value       => 2,
      }],
     0, # initial
     sub { my ($action, $current_action, $self) = @_;
           Gtk2::Ex::WidgetCursor->busy;
           $self->{'view'}->set (timebase_class =>
                                 $timebases[$action->get_current_value]);
         },
     $self);

  my $ui = $self->{'ui'} = Gtk2::UIManager->new;
  $ui->insert_action_group ($actiongroup, 0);
  $self->add_accel_group ($ui->get_accel_group);
  $ui->add_ui_from_string (<<'HERE');
<ui>
  <menubar name='MenuBar'>
    <menu action='FileMenu'>
      <menuitem action='Open'/>
      <menuitem action='Delete'/>
      <menuitem action='AddFavourite'/>
      <menuitem action='RemoveFavourite'/>
      <separator/>
      <menuitem action='Prev'/>
      <menuitem action='Next'/>
      <menuitem action='Back'/>
      <menuitem action='Forward'/>
      <separator/>
      <menuitem action='Quit'/>
    </menu>
    <menu action='EditMenu'>
      <menuitem action='Annotations'/>
      <menuitem action='ViewStyle'/>
      <menuitem action='Preferences'/>
      <menuitem action='Raw'/>
    </menu>
    <menu action='ViewMenu'>
      <menuitem action='Daily'/>
      <menuitem action='Weekly'/>
      <menuitem action='Monthly'/>
      <separator/>
      <menuitem action='ZoomInY'/>
      <menuitem action='ZoomOutY'/>
      <menuitem action='ZoomInX'/>
      <menuitem action='ZoomOutX'/>
      <menuitem action='Centre'/>
      <menuitem action='Redraw'/>
      <separator/>
      <menuitem action='Intraday'/>
      <menuitem action='WebMenuItem'/>
    </menu>
    <menu action='ToolsMenu'>
      <menuitem action='Download'/>
      <menuitem action='DownloadUpdate'/>
      <menuitem action='Watchlist'/>
      <menuitem action='Cross'/>
      <menuitem action='Ticker'/>
      <menuitem action='Toolbar'/>
      <menuitem action='History'/>
      <separator/>
      <menuitem action='Vacuum'/>
      <menuitem action='Errors'/>
      <menuitem action='Diagnostics'/>
    </menu>
    <menu action='HelpMenu'>
      <menuitem action='About'/>

lib/App/Chart/Gtk2/Main.pm  view on Meta::CPAN

  delete $self->{'history'};
  delete $self->{'ui'};
  delete $self->{'actiongroup'};
  return shift->signal_chain_from_overridden(@_);

  #   delete $self->{'statusbar'};
  #   delete $self->{'view'};
  #   delete $self->{'symbol_sensitive_actions'};
  #   if (DEBUG) { print "  keys left: ", join(',', keys %$self), "\n"; }
  #   %$self = ();
  # print "children ",$self->get_children,"\n";

}

sub shrink_to_aspect_ratio {
  my ($width, $height, $ratio) = @_;
  $width  = min ($width,  $ratio * $height);
  $height = min ($height, (1.0/$ratio) * $width);
  return ($width, $height);
}
sub x_mm_to_pixels {
  my ($widget, $x) = @_;
  my $screen = $widget->get_screen
    || croak 'x_mm_to_pixels(): widget not on a screen yet';
  return $x * $screen->get_width / $screen->get_width_mm;
}
sub y_mm_to_pixels {
  my ($widget, $y) = @_;
  my $screen = $widget->get_screen
    || croak 'y_mm_to_pixels(): widget not on a screen yet';
  return $y * $screen->get_height / $screen->get_height_mm;
}

sub _webmenuitem_submenu {
  my ($webitem, $self) = @_;
  ### _webmenuitem_submenu() have: $webitem->get_submenu
  unless ($webitem->get_submenu) {
    require App::Chart::Gtk2::WeblinkMenu;
    my $webmenu = $self->{'webmenu'} = App::Chart::Gtk2::WeblinkMenu->new
      (symbol => $self->{'symbol'});
    $webitem->set_submenu ($webmenu);

    # gtk 2.18 bug -- set_submenu doesn't notify attach-widget
    $webmenu->notify ('attach-widget');
  }
}

#------------------------------------------------------------------------------
# broadcast handlers

# 'delete-symbol' broadcast handler
sub _do_delete_symbol {
  my ($self, $symbol) = @_;
  my $self_symbol = $self->{'symbol'};
  ### Main delete-symbol: $symbol
  ### showing: $self_symbol

  # when currently displayed symbol is deleted goto next, or if no next
  # then previous, or if no previous then go to displaying nothing
  if (defined $self_symbol && $self_symbol eq $symbol) {
    Gtk2::Ex::WidgetCursor->busy;
     ($symbol, my $symlist) = $self->smarker->next ('database');
    if (! defined $symbol) {
      ### next is undef
      ($symbol, $symlist) = $self->smarker->prev ('database');
      ### prev: $symbol
    }
    _goto_with_history ($self, $symbol, $symlist);
  }
}

#------------------------------------------------------------------------------
# misc

sub get_or_create_ticker {
  my ($self) = @_;
  return ($self->{'ticker'} ||= do {
    require App::Chart::Gtk2::Ticker;
    my $ticker = App::Chart::Gtk2::Ticker->new;
    $self->{'vbox'}->pack_start ($ticker, 0,0,0);
    my $action = $self->{'actiongroup'}->get_action ('Ticker');
    Glib::Ex::ConnectProperties->new ([$action,'active'],
                                      [$ticker,'visible']);
    $ticker;
  });
}

# 'symbol-changed' class closure
sub _do_symbol_changed {
  my ($self, $symbol) = @_;
  my $sensitive = (defined $symbol && $symbol ne '');
  my $actiongroup = $self->{'actiongroup'};
  foreach my $name (@{$self->{'symbol_sensitive_actions'}}) {
    my $action = $actiongroup->get_action ($name);
    $action->set_sensitive ($sensitive);
  }

  { my $action = $actiongroup->get_action ('ManualDataSource');
    my $node = $symbol && App::Chart::symbol_source_help ($symbol);
    $action->set_sensitive ($node);
    my $tip = $node && __x('Open the manual at the "{node}" section about this symbol\'s data source', node => $node);
    $action->set (tooltip => $tip);
  }

  { my $action = $actiongroup->get_action ('ManualMovingAverage');
    my $node = manual_for_graph_n($self,0);
    $action->set_sensitive ($node);
    my $tip = $node && __x('Open the manual at the "{node}" section about this moving average', node => $node);
    $action->set (tooltip => $tip);
  }
  { my $action = $actiongroup->get_action ('ManualIndicator');
    my $node = manual_for_graph_n($self,1);
    $action->set_sensitive ($node);
    my $tip = $node && __x('Open the manual at the "{node}" section about this indicator', node => $node);
    $action->set (tooltip => $tip);
  }
}

sub manual_for_graph_n {
  my ($self, $n) = @_;
  my $view = $self->{'view'};
  my $graph = $view->{'graphs'}->[$n] || return;
  my $series = (List::Util::first {! $_->isa('App::Chart::Series::Database')}
                @{$graph->get('series-list')})
    || return;
  my $func = $series->can('manual') || return;
  return $series->$func;
}

#------------------------------------------------------------------------------
# navigation

sub symbol_history {
  my ($self) = @_;
  return $self->{'history'};
}
sub _history_place_to_text {
  my ($history, $place) = @_;
  require App::Chart::Database;
  my ($symbol, $symlist_key) = @$place;
  if (defined (my $name = App::Chart::Database->symbol_name ($symbol))) {
    $symbol .= " - $name";
  }
  return $symbol;
}
sub _history_place_to_symbol_symlist {
  my ($place) = @_;
  my ($symbol, $symlist_key) = @$place;
  require App::Chart::Gtk2::Symlist;
  my $symlist = App::Chart::Gtk2::Symlist->new_from_key_maybe ($symlist_key);
  return ($symbol, $symlist);
}
sub _history_symbol_symlist_to_place {
  my ($symbol, $symlist) = @_;
  return [ $symbol, $symlist && $symlist->key ];
}

sub _goto {
  my ($self, $symbol, $symlist) = @_;
  Gtk2::Ex::WidgetCursor->busy;
  $self->{'symbol'} = $symbol;
  $self->{'symlist'} = $symlist;
  $self->{'view'}->set('symbol', $symbol);
  if (my $webmenu = $self->{'webmenu'}) { $webmenu->set('symbol', $symbol); }
  $self->signal_emit ('symbol-changed', $symbol);

  if ($symbol) {
    require App::Chart::Gtk2::Job::Latest;
    App::Chart::Gtk2::Job::Latest->start_for_view ($symbol, $symlist);
  }
}
sub _goto_with_history {
  my ($self, $symbol, $symlist) = @_;
  ### _goto_with_history: $symbol, $symlist && $symlist->key
  if ($symbol) {
    my $history = $self->symbol_history;
    $history->goto (_history_symbol_symlist_to_place ($symbol, $symlist));
  }
}
sub _history_notify_current {
  my ($history, $pspec, $self) = @_;
  _goto ($self, _history_place_to_symbol_symlist($history->get('current')));
}

sub smarker {
  my ($self) = @_;
  return ($self->{'smarker'} ||= do {
    require App::Chart::Gtk2::Smarker;
    App::Chart::Gtk2::Smarker->new;
  });
}

sub goto_symbol {
  my ($self, $symbol, $symlist) = @_;
  ### Main goto: $symbol, $symlist && $symlist->key
  _goto_with_history ($self, $symbol, $symlist);
  $self->smarker->goto ($symbol, $symlist);
}

sub goto_next {
  my ($self) = @_;
  Gtk2::Ex::WidgetCursor->busy;
  my ($symbol, $symlist) = $self->smarker->next ('database');

  #   require App::Chart::Gtk2::Symlist;
  #   my ($symbol, $symlist)
  #     = App::Chart::Gtk2::Symlist::next ($self->{'symbol'}, $self->{'symlist'});
  if ($symbol) {
    _goto_with_history ($self, $symbol, $symlist);
  } else {
    _message ($self, __('At end of lists'));
  }
}

sub go_prev {
  my ($self) = @_;
  Gtk2::Ex::WidgetCursor->busy;
  my ($symbol, $symlist) = $self->smarker->prev ('database');
  #   require App::Chart::Gtk2::Symlist;
  #   my ($symbol, $symlist)
  #     = App::Chart::Gtk2::Symlist::previous ($self->{'symbol'}, $self->{'symlist'});
  if ($symbol) {
    _goto_with_history ($self, $symbol, $symlist);
  } else {
    _message ($self, __('At start of lists'));
  }
}

sub go_back {
  my ($self) = @_;
  $self->symbol_history->back;
}
sub go_forward {
  my ($self) = @_;
  $self->symbol_history->forward;
}


#------------------------------------------------------------------------------
# other

sub _message {
  my ($self, $str) = @_;
  require Gtk2::Ex::Statusbar::MessageUntilKey;
  Gtk2::Ex::Statusbar::MessageUntilKey->message ($self->{'statusbar'}, $str);
}

# return currently displayed symbol, or undef
sub get_symbol {
  my ($self) = @_;
  return $self->{'view'}->get('symbol');
}

# return the menubar widget
sub menubar {
  my ($self) = @_;
  return $self->{'ui'}->get_widget('/MenuBar');
}

# return App::Chart::Gtk2::Main widget, preferring the transient parent of $dialog,
# if $dialog is given
sub find_for_dialog {
  my ($class, $dialog) = @_;
  if ($dialog
      && $dialog->can('get_transient_for')
      && (my $parent = $dialog->get_transient_for)) {
    if ($parent->isa($class)) {
      return $parent;
    }
  }

  my $screen = $dialog->get_screen;
  foreach my $toplevel (Gtk2::Window->list_toplevels) {
    if ($toplevel->isa($class) && $toplevel->get_screen == $screen) {
      return $toplevel;
    }
  }



( run in 0.518 second using v1.01-cache-2.11-cpan-483215c6ad5 )