[PATCH 1/2] Add a help button to every Anaconda screen

Anne Mulhern amulhern at redhat.com
Wed Aug 27 14:36:03 UTC 2014





----- Original Message -----
> From: "Vratislav Podzimek" <vpodzime at redhat.com>
> To: "anaconda patch review" <anaconda-patches at lists.fedorahosted.org>
> Sent: Wednesday, August 27, 2014 4:09:46 AM
> Subject: Re: [PATCH 1/2] Add a help button to every Anaconda screen
> 
> On Tue, 2014-08-26 at 08:46 -0400, Anne Mulhern wrote:
> > 
> > 
> > 
> > ----- Original Message -----
> > > From: "Anne Mulhern" <amulhern at redhat.com>
> > > To: "anaconda patch review" <anaconda-patches at lists.fedorahosted.org>
> > > Sent: Monday, August 25, 2014 4:24:00 PM
> > > Subject: Re: [PATCH 1/2] Add a help button to every Anaconda screen
> > > 
> > > 
> > > 
> > > 
> > > 
> > > ----- Original Message -----
> > > > From: "Martin Kolman" <mkolman at redhat.com>
> > > > To: anaconda-patches at lists.fedorahosted.org
> > > > Sent: Monday, August 25, 2014 10:17:36 AM
> > > > Subject: [PATCH 1/2] Add a help button to every Anaconda screen
> > > > 
> > > > This makes context aware help possible for every Anaconda screen by
> > > > providing a help button in the upper right corner of the screen.
> > > > Clicking the button opens the yelp help viewer with either a help page
> > > > tailored for the given screen, the main page of the installation guide
> > > > (if no help is available for the screen) or a "no help found"
> > > > placeholder
> > > > page.
> > > > The new helpFile GUIObject attribute is used to specify which help
> > > > file to show for the given screen. If no help file is specified
> > > > either the main page of the Installation Guide will be shown (if
> > > > available) or the placeholder page will be shown.
> > > > 
> > > > Signed-off-by: Martin Kolman <mkolman at redhat.com>
> > > > ---
> > > >  anaconda.spec.in                          |   1 +
> > > >  data/help/FedoraPlaceholder.html          |   5 ++
> > > >  data/help/FedoraPlaceholderWithLinks.html |  13 ++++
> > > >  data/help/Makefile.am                     |  22 ++++++
> > > >  pyanaconda/ihelp.py                       | 123
> > > >  ++++++++++++++++++++++++++++++
> > > >  pyanaconda/installclass.py                |   6 ++
> > > >  pyanaconda/installclasses/fedora.py       |   3 +
> > > >  pyanaconda/ui/gui/__init__.py             |  12 +++
> > > >  pyanaconda/ui/gui/spokes/__init__.py      |   9 +++
> > > >  widgets/configure.ac                      |   2 +-
> > > >  widgets/glade/AnacondaWidgets.xml         |   9 ++-
> > > >  widgets/src/BaseWindow.c                  |  48 ++++++++++++
> > > >  widgets/src/BaseWindow.h                  |   3 +
> > > >  widgets/src/Makefile.am                   |   2 +-
> > > >  14 files changed, 254 insertions(+), 4 deletions(-)
> > > >  create mode 100644 data/help/FedoraPlaceholder.html
> > > >  create mode 100644 data/help/FedoraPlaceholderWithLinks.html
> > > >  create mode 100644 data/help/Makefile.am
> > > >  create mode 100644 pyanaconda/ihelp.py
> > > > 
> > > > diff --git a/anaconda.spec.in b/anaconda.spec.in
> > > > index d897888..ffb6785 100644
> > > > --- a/anaconda.spec.in
> > > > +++ b/anaconda.spec.in
> > > > @@ -174,6 +174,7 @@ Requires: zenity
> > > >  %endif
> > > >  Requires: keybinder3
> > > >  Requires: NetworkManager-wifi
> > > > +Requires: yelp
> > > >  
> > > >  %description gui
> > > >  This package contains graphical user interface for the Anaconda
> > > >  installer.
> > > > diff --git a/data/help/FedoraPlaceholder.html
> > > > b/data/help/FedoraPlaceholder.html
> > > > new file mode 100644
> > > > index 0000000..4d1781a
> > > > --- /dev/null
> > > > +++ b/data/help/FedoraPlaceholder.html
> > > > @@ -0,0 +1,5 @@
> > > > +<body>
> > > > +<h1>The Anaconda built-in help</h1>
> > > > +<p>...is not yet available for this screen.</p>
> > > > +<p>You can check the Anaconda wiki page, the Fedora Installation Guide
> > > > or
> > > > other online help resources instead.</p>
> > > > +</body>
> > > > diff --git a/data/help/FedoraPlaceholderWithLinks.html
> > > > b/data/help/FedoraPlaceholderWithLinks.html
> > > > new file mode 100644
> > > > index 0000000..5fe0485
> > > > --- /dev/null
> > > > +++ b/data/help/FedoraPlaceholderWithLinks.html
> > > > @@ -0,0 +1,13 @@
> > > > +<body>
> > > > +<h1>The Anaconda built-in help</h1>
> > > > +<p>...is not yet available for this screen.</p>
> > > > +<p>You can check the Anaconda wiki page, the Fedora Installation Guide
> > > > or
> > > > other online help resources instead:</p>
> > > > +<p>
> > > > +<ul>
> > > > +    <li><a
> > > > href="http://docs.fedoraproject.org/en-US/Fedora/20/html/Installation_Guide/">Fedora
> > > > Installation Guide</a></li>
> > > > +    <li><a href="https://fedoraproject.org/wiki/Anaconda">Anaconda
> > > > Wiki</a></li>
> > > > +    <li><a
> > > > href="http://fedoraproject.org/wiki/Anaconda_Boot_Options">Anaconda
> > > > Boot
> > > > Options</a></li>
> > > > +    <li><a
> > > > href="http://fedoraproject.org/wiki/Anaconda/Kickstart">Anaconda
> > > > Kickstart</a></li>
> > > > +</ul>
> > > > +</p>
> > > > +</body>
> > > > diff --git a/data/help/Makefile.am b/data/help/Makefile.am
> > > > new file mode 100644
> > > > index 0000000..8ecdd18
> > > > --- /dev/null
> > > > +++ b/data/help/Makefile.am
> > > > @@ -0,0 +1,22 @@
> > > > +# data/Makefile.am for anaconda
> > > > +#
> > > > +# Copyright (C) 2014  Red Hat, Inc.
> > > > +#
> > > > +# This program is free software; you can redistribute it and/or modify
> > > > +# it under the terms of the GNU Lesser General Public License as
> > > > published
> > > > +# by the Free Software Foundation; either version 2.1 of the License,
> > > > or
> > > > +# (at your option) any later version.
> > > > +#
> > > > +# This program 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 Lesser General Public License for more details.
> > > > +#
> > > > +# You should have received a copy of the GNU Lesser General Public
> > > > License
> > > > +# along with this program.  If not, see
> > > > <http://www.gnu.org/licenses/>.
> > > > +#
> > > > +# Author: Martin Kolman <mkolman at redhat.com>
> > > > +
> > > > +dist_doc_DATA         = HelpPlaceholder.html
> > > > HelpPlaceholderWithLinks.html
> > > > +
> > > > +MAINTAINERCLEANFILES = Makefile.in
> > > > diff --git a/pyanaconda/ihelp.py b/pyanaconda/ihelp.py
> > > > new file mode 100644
> > > > index 0000000..4c8dbad
> > > > --- /dev/null
> > > > +++ b/pyanaconda/ihelp.py
> > > > @@ -0,0 +1,123 @@
> > > > +#
> > > > +# Copyright (C) 2014  Red Hat, Inc.
> > > > +#
> > > > +# This copyrighted material is made available to anyone wishing to
> > > > use,
> > > > +# modify, copy, or redistribute it subject to the terms and conditions
> > > > of
> > > > +# the GNU General Public License v.2, or (at your option) any later
> > > > version.
> > > > +# This program is distributed in the hope that it will be useful, but
> > > > WITHOUT
> > > > +# ANY WARRANTY expressed or implied, including the implied warranties
> > > > 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 this program; if not, write to
> > > > the
> > > > +# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
> > > > Boston,
> > > > MA
> > > > +# 02110-1301, USA.  Any Red Hat trademarks that are incorporated in
> > > > the
> > > > +# source code or documentation are not subject to the GNU General
> > > > Public
> > > > +# License and may only be used or replicated with the express
> > > > permission
> > > > of
> > > > +# Red Hat, Inc.
> > > > +#
> > > > +# Red Hat Author(s): Martin Kolman <mkolman at redhat.com>
> > > > +#
> > > > +"""
> > > > +Anaconda built-in help module
> > > > +"""
> > > > +import os
> > > > +import subprocess
> > > > +
> > > > +from pyanaconda.flags import flags
> > > > +from pyanaconda.localization import find_best_locale_match
> > > > +from pyanaconda.constants import DEFAULT_LANG
> > > > +
> > > > +import logging
> > > > +log = logging.getLogger("anaconda")
> > > > +
> > > > +yelp_process = None
> > > > +
> > > > +def _get_best_lang_code(instclass):
> > > > +    """Return the best language code for the current language and
> > > > available
> > > > +    help content
> > > > +
> > > > +    :param instclass: current install class instance
> > > > +    :return: best language code for help content or None is no match
> > > > is
> > > > found
> > > > +    :rtype: str or None
> > > > +
> > > > +    """
> > > > +    help_langs = []
> > > > +    # list all available languages for the Anaconda help,
> > > > +    # content is stored in folders named after the given
> > > > +    # language code (en-US, cs-CZ, jp-JP, etc.)
> > > > +    for item in os.listdir(instclass.help_folder):
> > > > +        if os.path.isdir(os.path.join(instclass.help_folder, item)):
> > > > +            help_langs.append(item)
> > > 
> > > I'm not sure if there's much point in checking if the matches are
> > > directories.
> > > If they are empty directories or missing a few files...what then?
> > > You still need a fallback.
> > > 
> > > I would probably turn the above into a list comprehension, maybe:
> > > 
> > > help_langs = (item for item in os.listdir(instclass.help_folder))
> > > 
> > > and have this function take another parameter, help_file, and instead of
> > > finding the best
> > > language code, find the best help file for the locale, i.e., move some
> > > of the functionality of get_help_path into this function. It can always
> > > exit early if help_file is None.
> > > 
> > > The advantage isn't all that large but this would mean that if a
> > > help_file
> > > is not provided in the best locale match directory, the code could still
> > > fall back on the help file in the default locale directory.
> > > 
> > > > +    best_lang = find_best_locale_match(os.environ["LANG"], help_langs)
> > > > +    if not best_lang:
> > > > +        # nothing found, try the default language
> > > > +        best_lang = find_best_locale_match(DEFAULT_LANG, help_langs)
> > > > +    return best_lang
> > > > +
> > > > +def get_help_path(help_file, instclass):
> > > > +    """Return the full path for the given help file name,
> > > > +    if the help file path does not exist a fallback path is returned.
> > > > +    There are actually two possible fallback paths that might be
> > > > returned:
> > > > +    * first we try to return path to the main page of the installation
> > > > guide
> > > > +      (if it exists)
> > > > +    * if we can't find the main page of the installation page, path to
> > > > a
> > > > +      "no help found" placeholder bundled with Anaconda is returned
> > > > +
> > > > +    :param str help_file: help file name
> > > 
> > > Since help_file may be None, that should be documented here. Something
> > > like:
> > > 
> > > :type help_file: str or NoneType
> > > 
> > > > +    :param instclass: current install class instance
> > > > +    :return str: full path to the help file requested or to a
> > > > placeholder
> > > > +    """
> > > > +    # help l10n handling
> > > > +    lang_code = _get_best_lang_code(instclass)
> > > > +
> > > > +    # no lang code means we don't have any help content,
> > > > +    # not even untranslated in the default language (English)
> > > > +    if lang_code:
> > > > +        # check if the screen has any helpFile defined
> > > > +        if help_file:
> > > > +            # check if the help file exists
> > > > +            help_path = os.path.join(instclass.help_folder, lang_code,
> > > > help_file)
> > > > +            if os.path.isfile(help_path):
> > > > +                return help_path
> > > > +            else:
> > > > +                log.debug("the %s help file has been requested, but is
> > > > not
> > > > available", help_file)
> > > > +
> > > > +        # the screen did not have a helpFile defined or the defined
> > > > help
> > > > file
> > > > +        # does not exist, so next try to check if we can find the main
> > > > page
> > > > +        # of the installation guide and use it instead
> > > > +        help_path = os.path.join(instclass.help_folder, lang_code,
> > > > instclass.help_main_page)
> > > > +        if os.path.exists(help_path):
> > > > +            return help_path
> > > > +    else:
> > > > +        log.warning("no help content found, using a placeholder")
> > > > +
> > > > +    # looks like the installation guide is not available, so just
> > > > return
> > > > +    # a placeholder page that should always be available
> > > > +    if flags.livecdInstall:
> > > > +        return os.path.join(instclass.help_folder,
> > > > instclass.help_placeholder_with_links)
> > > > +    else:
> > > > +        return os.path.join(instclass.help_folder,
> > > > instclass.help_placeholder)
> > > > +
> > > > +def start_yelp(help_path):
> > > > +    """Start a new yelp process and make sure to kill any existing
> > > > ones
> > > > +
> > > > +    :param str help_path: path to the help file yelp should load
> > > > +    """
> > > > +
> > > > +    kill_yelp()
> > > > +    log.debug("starting yelp")
> > > > +    global yelp_process
> > > > +    yelp_process = subprocess.Popen(["yelp", help_path])
> > > > +
> > > > +def kill_yelp():
> > > > +    """Try to kill any existing yelp processes"""
> > > > +
> > > > +    global yelp_process
> > > > +    if not yelp_process:
> > > > +        return False
> > > > +
> > > > +    log.debug("killing yelp")
> > > > +    yelp_process.kill()
> > > > +    yelp_process = None
> > > > +    return True
> > > > +
> > > > diff --git a/pyanaconda/installclass.py b/pyanaconda/installclass.py
> > > > index 4fd8865..e17f33d 100644
> > > > --- a/pyanaconda/installclass.py
> > > > +++ b/pyanaconda/installclass.py
> > > > @@ -61,6 +61,12 @@ class BaseInstallClass(object):
> > > >      # don't select this class by default
> > > >      default = 0
> > > >  
> > > > +    # help
> > > > +    help_folder = "/usr/share/doc/anaconda"
> > > > +    help_main_page = "Installation_Guide.xml"
> > > > +    help_placeholder = None
> > > > +    help_placeholder_with_links = None
> > > > +
> > > >      @property
> > > >      def l10n_domain(self):
> > > >          if self._l10n_domain is None:
> > > > diff --git a/pyanaconda/installclasses/fedora.py
> > > > b/pyanaconda/installclasses/fedora.py
> > > > index 1fe192b..ec110aa 100644
> > > > --- a/pyanaconda/installclasses/fedora.py
> > > > +++ b/pyanaconda/installclasses/fedora.py
> > > > @@ -37,6 +37,9 @@ class InstallClass(BaseInstallClass):
> > > >  
> > > >      efi_dir = "fedora"
> > > >  
> > > > +    help_placeholder = "FedoraPlaceholder.html"
> > > > +    help_placeholder_with_links = "FedoraPlaceholderWithLinks.html"
> > > > +
> > > >      def configure(self, anaconda):
> > > >          BaseInstallClass.configure(self, anaconda)
> > > >          BaseInstallClass.setDefaultPartitioning(self,
> > > >          anaconda.storage)
> > > 
> > > Should probably do the correct thing for
> > > pyanaconda/installclasses/rhel7.py
> > > while you're doing this one.
> > > 
> > > > diff --git a/pyanaconda/ui/gui/__init__.py
> > > > b/pyanaconda/ui/gui/__init__.py
> > > > index 117879b..dca0280 100644
> > > > --- a/pyanaconda/ui/gui/__init__.py
> > > > +++ b/pyanaconda/ui/gui/__init__.py
> > > > @@ -31,6 +31,7 @@ from pyanaconda import product, iutil
> > > >  
> > > >  from pyanaconda.ui import UserInterface, common
> > > >  from pyanaconda.ui.gui.utils import gtk_action_wait, busyCursor,
> > > >  unbusyCursor
> > > > +from pyanaconda import ihelp
> > > >  import os.path
> > > >  
> > > >  import logging
> > > > @@ -81,6 +82,10 @@ class GUIObject(common.UIObject):
> > > >                             that use GUI elements (Hubs & Spokes) from
> > > >                             Anaconda
> > > >                             can override the translation domain with
> > > >                             their
> > > >                             own,
> > > >                             so that their subclasses are properly
> > > >                             translated.
> > > > +       helpFile         -- The location of the yelp-compatible help
> > > > file
> > > > for
> > > > the
> > > > +                           given GUI object. The default value of ""
> > > > indicates
> > > > +                           that the object has not specific help file
> > > > assigned
> > > > +                           and the default help file should be used.
> > > >      """
> > > >      builderObjects = []
> > > >      mainWidgetName = None
> > > > @@ -91,6 +96,7 @@ class GUIObject(common.UIObject):
> > > >      focusWidgetName = None
> > > >  
> > > >      uiFile = ""
> > > > +    helpFile = ""
> > > >      translationDomain = "anaconda"
> > > >  
> > > >      screenshots_directory = "/tmp/anaconda-screenshots"
> > > > @@ -536,6 +542,7 @@ class GraphicalUserInterface(UserInterface):
> > > >  
> > > >          # Use connect_after so classes can add actions before we
> > > >          change
> > > >          screens
> > > >          obj.window.connect_after("continue-clicked",
> > > >          self._on_continue_clicked)
> > > > +        obj.window.connect_after("help-button-clicked",
> > > > self._on_help_clicked, obj)
> > > >          obj.window.connect_after("quit-clicked",
> > > >          self._on_quit_clicked)
> > > > 
> > > 
> > > I'm not sure whether any of these should really be connect_after...the
> > > comment
> > > does not really help me much.
> > >  
> > > >          return obj
> > > > @@ -697,6 +704,11 @@ class GraphicalUserInterface(UserInterface):
> > > >          self._currentAction = nextAction
> > > >          self._actions.pop(0)
> > > >  
> > > > +    def _on_help_clicked(self, window, obj):
> > > > +        # the help button has been clicked, start the yelp viewer with
> > > > +        # content for the current screen
> > > > +        ihelp.start_yelp(ihelp.get_help_path(obj.helpFile,
> > > > self.instclass))
> > > > +
> > > >      def _on_quit_clicked(self, win, userData=None):
> > > >          if not win.get_quit_button():
> > > >              return
> > > > diff --git a/pyanaconda/ui/gui/spokes/__init__.py
> > > > b/pyanaconda/ui/gui/spokes/__init__.py
> > > > index 183dc6f..1227d44 100644
> > > > --- a/pyanaconda/ui/gui/spokes/__init__.py
> > > > +++ b/pyanaconda/ui/gui/spokes/__init__.py
> > > > @@ -21,6 +21,7 @@
> > > >  
> > > >  from pyanaconda.ui import common
> > > >  from pyanaconda.ui.gui import GUIObject
> > > > +from pyanaconda import ihelp
> > > >  
> > > >  __all__ = ["StandaloneSpoke", "NormalSpoke"]
> > > >  
> > > > @@ -44,6 +45,14 @@ class NormalSpoke(GUIObject, common.NormalSpoke):
> > > >          GUIObject.__init__(self, data)
> > > >          common.NormalSpoke.__init__(self, storage, payload, instclass)
> > > >  
> > > > +        # Add a help handler
> > > > +        self.window.connect_after("help-button-clicked",
> > > > self._on_help_clicked)
> > > 
> > > Should this really be connect_after instead of connect?
> > > 
> > > > +
> > > > +    def _on_help_clicked(self, window):
> > > > +        # the help button has been clicked, start the yelp viewer with
> > > > +        # content for the current spoke
> > > > +        ihelp.start_yelp(ihelp.get_help_path(self.helpFile,
> > > > self.instclass))
> > > > +
> > > >      def on_back_clicked(self, window):
> > > >          # Notify the hub that we're finished.
> > > >          # The hub will be the current-action of the main window.
> > > > diff --git a/widgets/configure.ac b/widgets/configure.ac
> > > > index 1035c6c..6456db9 100644
> > > > --- a/widgets/configure.ac
> > > > +++ b/widgets/configure.ac
> > > > @@ -20,7 +20,7 @@
> > > >  #
> > > >  
> > > >  AC_PREREQ([2.63])
> > > > -AC_INIT([AnacondaWidgets], [3.0], [clumens at redhat.com])
> > > > +AC_INIT([AnacondaWidgets], [3.1], [clumens at redhat.com])
> > > >  AM_INIT_AUTOMAKE([foreign])
> > > >  AM_SILENT_RULES([yes])
> > > >  
> > > > diff --git a/widgets/glade/AnacondaWidgets.xml
> > > > b/widgets/glade/AnacondaWidgets.xml
> > > > index 42c4194..044ceb2 100644
> > > > --- a/widgets/glade/AnacondaWidgets.xml
> > > > +++ b/widgets/glade/AnacondaWidgets.xml
> > > > @@ -1,6 +1,6 @@
> > > >  <glade-catalog name="AnacondaWidgets"
> > > > -               version="3.0"
> > > > -               targetable="2.0,1.0"
> > > > +               version="3.1"
> > > > +               targetable="3.0,2.0,1.0"
> > > >                 library="AnacondaWidgets"
> > > >                 domain="glade-3"
> > > >                 depends="gtk+">
> > > > @@ -25,6 +25,11 @@
> > > >                  <property id="distribution" translatable="True" />
> > > >                  <property id="window-name" translatable="True" />
> > > >              </properties>
> > > > +
> > > > +            <signals>
> > > > +              <signal since="3.1" id="help-button-clicked" />
> > > > +            </signals>
> > > > +
> > > >          </glade-widget-class>
> > > >  
> > > >          <glade-widget-class title="Standalone Spoke Window"
> > > > diff --git a/widgets/src/BaseWindow.c b/widgets/src/BaseWindow.c
> > > > index 5b7f337..94dee1f 100644
> > > > --- a/widgets/src/BaseWindow.c
> > > > +++ b/widgets/src/BaseWindow.c
> > > > @@ -28,6 +28,8 @@
> > > >  #include "BaseWindow.h"
> > > >  #include "intl.h"
> > > >  
> > > > + #include <atk/atk.h>
> > > > +
> > > >  /**
> > > >   * SECTION: BaseWindow
> > > >   * @title: AnacondaBaseWindow
> > > > @@ -95,6 +97,7 @@
> > > >  
> > > >  enum {
> > > >      SIGNAL_INFO_BAR_CLICKED,
> > > > +    SIGNAL_HELP_BUTTON_CLICKED,
> > > >      LAST_SIGNAL
> > > >  };
> > > >  
> > > > @@ -109,6 +112,7 @@ enum {
> > > >  #define DEFAULT_WINDOW_NAME   N_("SPOKE NAME")
> > > >  #define DEFAULT_BETA          N_("PRE-RELEASE / TESTING")
> > > >  #define LAYOUT_INDICATOR_LABEL_WIDTH 10
> > > > +#define HELP_BUTTON_LABEL _("_Help!")
> > > >  
> > > >  struct _AnacondaBaseWindowPrivate {
> > > >      gboolean    is_beta, info_shown;
> > > > @@ -117,6 +121,7 @@ struct _AnacondaBaseWindowPrivate {
> > > >      GtkWidget  *nav_box, *nav_area, *action_area;
> > > >      GtkWidget  *name_label, *distro_label, *beta_label;
> > > >      GtkWidget  *layout_indicator;
> > > > +    GtkWidget  *help_button;
> > > >  
> > > >      /* Untranslated versions of various things. */
> > > >      gchar *orig_name, *orig_distro, *orig_beta;
> > > > @@ -128,6 +133,7 @@ static void
> > > > anaconda_base_window_buildable_init(GtkBuildableIface *iface);
> > > >  static void format_beta_label(AnacondaBaseWindow *window, const char
> > > >  *markup);
> > > >  
> > > >  static gboolean anaconda_base_window_info_bar_clicked(GtkWidget
> > > >  *widget,
> > > >  GdkEvent *event, AnacondaBaseWindow *win);
> > > > +static void anaconda_base_window_help_button_clicked(GtkButton
> > > > *button,
> > > > AnacondaBaseWindow *win);
> > > >  
> > > >  G_DEFINE_TYPE_WITH_CODE(AnacondaBaseWindow, anaconda_base_window,
> > > >  GTK_TYPE_BIN,
> > > >                          G_IMPLEMENT_INTERFACE(GTK_TYPE_BUILDABLE,
> > > >                          anaconda_base_window_buildable_init))
> > > > @@ -173,6 +179,7 @@ static void
> > > > anaconda_base_window_class_init(AnacondaBaseWindowClass *klass) {
> > > >                                                          G_PARAM_READWRITE));
> > > >  
> > > >      klass->info_bar_clicked = NULL;
> > > > +    klass->help_button_clicked = NULL;
> > > >  
> > > >      /**
> > > >       * AnacondaBaseWindow::info-bar-clicked:
> > > > @@ -192,6 +199,24 @@ static void
> > > > anaconda_base_window_class_init(AnacondaBaseWindowClass *klass) {
> > > >                                                             g_cclosure_marshal_VOID__VOID,
> > > >                                                             G_TYPE_NONE,
> > > >                                                             0);
> > > >  
> > > > +    /**
> > > > +     * AnacondaBaseWindow::help-button-clicked:
> > > > +     * @window: the window that received the signal
> > > > +     *
> > > > +     * Emitted when the help button in the right corner has been
> > > > activated
> > > > +     * (pressed and released). This is commonly used to open the help
> > > > view
> > > > with
> > > > +     * help content for the given spoke or hub
> > > > +     *
> > > > +     * Since: 4.0
> > > > +     */
> > > > +    window_signals[SIGNAL_HELP_BUTTON_CLICKED] =
> > > > g_signal_new("help-button-clicked",
> > > > +
> > > > G_TYPE_FROM_CLASS(object_class),
> > > > +
> > > > G_SIGNAL_RUN_FIRST
> > > > | G_SIGNAL_ACTION,
> > > > +
> > > > G_STRUCT_OFFSET(AnacondaBaseWindowClass,
> > > > help_button_clicked),
> > > > +                                                              NULL,
> > > > NULL,
> > > > +
> > > > g_cclosure_marshal_VOID__VOID,
> > > > +
> > > > G_TYPE_NONE,
> > > > 0);
> > > > +
> > > >      g_type_class_add_private(object_class,
> > > >      sizeof(AnacondaBaseWindowPrivate));
> > > >  }
> > > >  
> > > > @@ -210,6 +235,7 @@ GtkWidget *anaconda_base_window_new() {
> > > >  
> > > >  static void anaconda_base_window_init(AnacondaBaseWindow *win) {
> > > >      char *markup;
> > > > +    AtkObject *atk;
> > > >  
> > > >      win->priv = G_TYPE_INSTANCE_GET_PRIVATE(win,
> > > >                                              ANACONDA_TYPE_BASE_WINDOW,
> > > > @@ -325,11 +351,28 @@ G_GNUC_END_IGNORE_DEPRECATIONS
> > > >      gtk_widget_set_margin_top(win->priv->layout_indicator, 6);
> > > >      gtk_widget_set_margin_bottom(win->priv->layout_indicator, 6);
> > > >  
> > > > +    /* Create the help button. */
> > > > +    win->priv->help_button =
> > > > gtk_button_new_with_mnemonic(HELP_BUTTON_LABEL);
> > > > +    gtk_widget_set_halign(win->priv->help_button, GTK_ALIGN_START);
> > > > +    gtk_widget_set_vexpand(win->priv->help_button, FALSE);
> > > > +    gtk_widget_set_valign(win->priv->help_button, GTK_ALIGN_END);
> > > > +    gtk_widget_set_margin_bottom(win->priv->help_button, 6);
> > > > +
> > > > +    atk = gtk_widget_get_accessible(win->priv->help_button);
> > > > +    atk_object_set_name(atk, HELP_BUTTON_LABEL);
> > > > +
> > > > +    /* Hook up some signals for that button.  The signal handlers here
> > > > will
> > > > +     * just raise our own custom signals for the whole window.
> > > > +     */
> > > > +    g_signal_connect(win->priv->help_button, "clicked",
> > > > +
> > > > G_CALLBACK(anaconda_base_window_help_button_clicked),
> > > > win);
> > > > +
> > > >      /* Add everything to the nav area. */
> > > >      gtk_grid_attach(GTK_GRID(win->priv->nav_area),
> > > >      win->priv->name_label,
> > > >      0,
> > > >      0, 1, 1);
> > > >      gtk_grid_attach(GTK_GRID(win->priv->nav_area),
> > > >      win->priv->distro_label,
> > > >      1, 0, 1, 1);
> > > >      gtk_grid_attach(GTK_GRID(win->priv->nav_area),
> > > >      win->priv->beta_label,
> > > >      1,
> > > >      1, 1, 1);
> > > >      gtk_grid_attach(GTK_GRID(win->priv->nav_area),
> > > >      win->priv->layout_indicator, 1, 2, 1, 1);
> > > > +    gtk_grid_attach(GTK_GRID(win->priv->nav_area),
> > > > win->priv->help_button,
> > > > 2, 1, 1, 2);
> > > >  }
> > > >  
> > > >  static void anaconda_base_window_get_property(GObject *object, guint
> > > >  prop_id, GValue *value, GParamSpec *pspec) {
> > > > @@ -587,6 +630,11 @@ static gboolean
> > > > anaconda_base_window_info_bar_clicked(GtkWidget *wiget, GdkEvent
> > > >      return FALSE;
> > > >  }
> > > >  
> > > > +static void anaconda_base_window_help_button_clicked(GtkButton
> > > > *button,
> > > > +
> > > > AnacondaBaseWindow
> > > > *win) {
> > > > +        g_signal_emit(win, window_signals[SIGNAL_HELP_BUTTON_CLICKED],
> > > > 0);
> > > > +}
> > > > +
> > > >  /**
> > > >   * anaconda_base_window_clear_info:
> > > >   * @win: a #AnacondaBaseWindow
> > > > diff --git a/widgets/src/BaseWindow.h b/widgets/src/BaseWindow.h
> > > > index eb6191d..19891c1 100644
> > > > --- a/widgets/src/BaseWindow.h
> > > > +++ b/widgets/src/BaseWindow.h
> > > > @@ -56,11 +56,14 @@ struct _AnacondaBaseWindow {
> > > >   *                pointer to be cast to a #GtkBin pointer.
> > > >   * @info_bar_clicked : Function pointer called when the
> > > >   #AnacondaBaseWindow::info-bar-clicked
> > > >   *                     signal is emitted.
> > > > + * @help_button_clicked: Function pointer called when the
> > > > #AnacondaSpokeWindow::help-button-clicked
> > > > + *                       signal is emitted.
> > > >   */
> > > >  struct _AnacondaBaseWindowClass {
> > > >      GtkBinClass parent_class;
> > > >  
> > > >      void (* info_bar_clicked) (AnacondaBaseWindow *window);
> > > > +    void (* help_button_clicked) (AnacondaBaseWindow *window);
> > > >  };
> > > >  
> > > >  GType       anaconda_base_window_get_type (void);
> > > > diff --git a/widgets/src/Makefile.am b/widgets/src/Makefile.am
> > > > index dfed620..42615c2 100644
> > > > --- a/widgets/src/Makefile.am
> > > > +++ b/widgets/src/Makefile.am
> > > > @@ -65,7 +65,7 @@ libAnacondaWidgets_la_CFLAGS = $(GTK_CFLAGS)
> > > > $(GLADEUI_CFLAGS) $(LIBXKLAVIER_CFL
> > > >  			       -DWIDGETS_DATADIR=$(WIDGETSDATA)\
> > > >  			       -DTZMAP_DATADIR=$(TZMAPDATA)
> > > >  libAnacondaWidgets_la_LIBADD = $(GTK_LIBS) $(GLADEUI_LIBS)
> > > >  $(LIBXKLAVIER_LIBS)
> > > > -libAnacondaWidgets_la_LDFLAGS = $(LTLIBINTL) -version-info 2:0:0
> > > > +libAnacondaWidgets_la_LDFLAGS = $(LTLIBINTL) -version-info 3:0:1
> > > >  libAnacondaWidgets_la_SOURCES = $(SOURCES) $(HDRS) \
> > > >  	  glade-adaptor.c
> > > >  
> > > > --
> > > > 1.9.3
> > > > 
> > > > _______________________________________________
> > > > anaconda-patches mailing list
> > > > anaconda-patches at lists.fedorahosted.org
> > > > https://lists.fedorahosted.org/mailman/listinfo/anaconda-patches
> > > > 
> > > 
> > > Just a few inline comments.
> > > 
> > > - mulhern
> > > _______________________________________________
> > > anaconda-patches mailing list
> > > anaconda-patches at lists.fedorahosted.org
> > > https://lists.fedorahosted.org/mailman/listinfo/anaconda-patches
> > > 
> > 
> > Actually,
> > 
> > I think that, ideally, we would store all this data in an sqlite
> > database, rather than in separate files in separate directories.
> > We would do the same for the CLI help text, now that it
> > has gotten so mature, and we would be able to use _exactly_ the
> > same database schema for both, since, at least in theory, CLI
> > help text should be available in any language.
> > 
> > However, we would have to handle version control of the structure
> > of the database and also its contents.
> > 
> > It might be that adding an sqlite dependency to anaconda
> > is not so attractive to some.
> > 
> > Also, I don't know how translation is expected to work with the
> > contents of databases.
> > 
> > So maybe this idea is a bit too ambitious. But now is as good
> > a time to think about it as any.
> I don't think we need such a big-hammer approach. Using directories for
> translations is really common and not so hard.
> 

"too ambitious" is my way of saying using a database would be
harder but also the kind of thing you might see in a more mature application.
I don't think there's any question that using directories for this
problem is the path of least resistance. A lot of the hardness
of using the database might however be due to unfamiliarity and novelty,
rather than anything really fundamental. IMHO, we should consider
not taking the path of least resistance occasionally, i.e., doing
something unfamiliar and novel and hence a bit difficult for us at the time,
especially as technologies mature and the path of least resistance turns
inexorably into the stuff that everybody used to do before the
clever ones learned a better way. On the other hand, I'm certainly
willing to be persuaded that right now is not a good time to choose
to try to break out of this particular rut.

Is it the case that the CLI help text should, at least in theory,
be translatable?

- mulhern

> --
> Vratislav Podzimek
> 
> Anaconda Rider | RHCE | Red Hat, Inc. | Brno - Czech Republic
> 
> 
> _______________________________________________
> anaconda-patches mailing list
> anaconda-patches at lists.fedorahosted.org
> https://lists.fedorahosted.org/mailman/listinfo/anaconda-patches
> 


More information about the anaconda-patches mailing list