[master] Fix the way categories are handled in text mode.

Vratislav Podzimek vpodzime at redhat.com
Mon Mar 31 09:34:30 UTC 2014


On Thu, 2014-03-27 at 17:17 -0400, Samantha N. Bueno wrote:
> This statically maintained list of spoke categories for text mode has
> been bothering me for almost a year, so it's time to get rid of it.
> 
> This now more or less mirrors the GUI logic we have for handling spoke
> categories. I wanted to originally make the category classes something
> that could be used by both GUI and TUI to reduce duplication, but it is
> not meant to be.
> 
> This also moves the collectCategoriesAndSpokes, collect_categories, and
> collect_spokes functions into pyanaconda.ui.common since I could at
> least consolidate that.
> ---
>  po/POTFILES.in                                |  6 ++++
>  pyanaconda/ui/common.py                       | 46 +++++++++++++++++++++++++++
>  pyanaconda/ui/gui/categories/__init__.py      | 13 +-------
>  pyanaconda/ui/gui/hubs/__init__.py            | 23 ++------------
>  pyanaconda/ui/gui/spokes/__init__.py          | 20 +-----------
>  pyanaconda/ui/tui/__init__.py                 |  4 +++
>  pyanaconda/ui/tui/categories/Makefile.am      | 22 +++++++++++++
>  pyanaconda/ui/tui/categories/__init__.py      | 46 +++++++++++++++++++++++++++
>  pyanaconda/ui/tui/categories/customization.py | 32 +++++++++++++++++++
>  pyanaconda/ui/tui/categories/localization.py  | 31 ++++++++++++++++++
>  pyanaconda/ui/tui/categories/software.py      | 31 ++++++++++++++++++
>  pyanaconda/ui/tui/categories/system.py        | 32 +++++++++++++++++++
>  pyanaconda/ui/tui/categories/user_settings.py | 32 +++++++++++++++++++
>  pyanaconda/ui/tui/hubs/__init__.py            | 18 +++++------
>  pyanaconda/ui/tui/hubs/summary.py             |  2 --
>  pyanaconda/ui/tui/spokes/__init__.py          | 24 ++------------
>  pyanaconda/ui/tui/spokes/askvnc.py            |  2 --
>  pyanaconda/ui/tui/spokes/network.py           |  3 +-
>  pyanaconda/ui/tui/spokes/password.py          |  3 +-
>  pyanaconda/ui/tui/spokes/shell_spoke.py       |  3 +-
>  pyanaconda/ui/tui/spokes/software.py          |  3 +-
>  pyanaconda/ui/tui/spokes/source.py            | 11 ++++---
>  pyanaconda/ui/tui/spokes/storage.py           |  7 ++--
>  pyanaconda/ui/tui/spokes/time_spoke.py        |  3 +-
>  pyanaconda/ui/tui/spokes/user.py              |  3 +-
>  25 files changed, 319 insertions(+), 101 deletions(-)
>  create mode 100644 pyanaconda/ui/tui/categories/Makefile.am
>  create mode 100644 pyanaconda/ui/tui/categories/__init__.py
>  create mode 100644 pyanaconda/ui/tui/categories/customization.py
>  create mode 100644 pyanaconda/ui/tui/categories/localization.py
>  create mode 100644 pyanaconda/ui/tui/categories/software.py
>  create mode 100644 pyanaconda/ui/tui/categories/system.py
>  create mode 100644 pyanaconda/ui/tui/categories/user_settings.py
> 
> diff --git a/po/POTFILES.in b/po/POTFILES.in
> index 358534c..e48469e 100644
> --- a/po/POTFILES.in
> +++ b/po/POTFILES.in
> @@ -62,6 +62,12 @@ pyanaconda/ui/tui/spokes/warnings.py
>  pyanaconda/ui/tui/spokes/progress.py
>  pyanaconda/ui/tui/spokes/__init__.py
>  pyanaconda/ui/tui/__init__.py
> +pyanaconda/ui/tui/categories/__init__.py
> +pyanaconda/ui/tui/categories/customization.py
> +pyanaconda/ui/tui/categories/localization.py
> +pyanaconda/ui/tui/categories/software.py
> +pyanaconda/ui/tui/categories/system.py
> +pyanaconda/ui/tui/categories/user_settings.py
>  
>  # Graphical interface
>  pyanaconda/ui/gui/__init__.py
> diff --git a/pyanaconda/ui/common.py b/pyanaconda/ui/common.py
> index ddd5016..afca06a 100644
> --- a/pyanaconda/ui/common.py
> +++ b/pyanaconda/ui/common.py
> @@ -673,3 +673,49 @@ def collect(module_pattern, path, pred):
>  
>      return retval
>  
> +def collect_spokes(mask_paths, category):
> +    """Return a list of all spoke subclasses that should appear for a given
> +       category. Look for them in files imported as module_path % basename(f)
> +
> +       :param mask_paths: list of mask, path tuples to search for classes
> +       :type mask_paths: list of (mask, path)
> +
> +       :return: list of Spoke classes belonging to category
> +       :rtype: list of Spoke classes
> +
> +    """
> +    spokes = []
> +    for mask, path in mask_paths:
> +        spokes.extend(collect(mask, path, lambda obj: hasattr(obj, "category") and obj.category != None and obj.category.__name__ == category))
While moving this code, could you please split this into two lines? And
make sure all the trailing whitespace is removed from it?

> +    
> +    return spokes
> +
> +def collect_categories(mask_paths):
> +    """Return a list of all category subclasses. Look for them in modules
> +       imported as module_mask % basename(f) where f is name of all files in path.
> +    """
> +    categories = []
> +    for mask, path in mask_paths:
> +        categories.extend(collect(mask, path, lambda obj: getattr(obj, "displayOnHub", None) != None))
> +
> +    return categories
> +
> +def collectCategoriesAndSpokes(paths, klass):
> +    """collects categories and spokes to be displayed on this Hub
> +
> +       :param paths: dictionary mapping categories, spokes, and hubs to their
> +       their respective search path(s)
> +       :return: dictionary mapping category class to list of spoke classes
> +       :rtype: dictionary[category class] -> [ list of spoke classes ]
> +    """
Missing documentation for the klass parameter. Also the (klass, paths)
ordering of the arguments seems more natural to me.

> +    
> +    ret = {}
> +    
> +    # Collect all the categories this hub displays, then collect all the
> +    # spokes belonging to all those categories.
> +    categories = sorted(filter(lambda c: c.displayOnHub == klass, collect_categories(paths["categories"])),
> +                        key=lambda c: c.sortOrder)
> +    for c in categories:
> +        ret[c] = collect_spokes(paths["spokes"], c.__name__)
> +
> +    return ret
> diff --git a/pyanaconda/ui/gui/categories/__init__.py b/pyanaconda/ui/gui/categories/__init__.py
> index 66bd5d4..06e431a 100644
> --- a/pyanaconda/ui/gui/categories/__init__.py
> +++ b/pyanaconda/ui/gui/categories/__init__.py
> @@ -21,9 +21,8 @@
>  
>  import os.path
>  from pyanaconda.i18n import N_
> -from pyanaconda.ui.common import collect
>  
> -__all__ = ["SpokeCategory", "collect_categories"]
> +__all__ = ["SpokeCategory"]
>  
>  class SpokeCategory(object):
>      """A SpokeCategory is an object used to group multiple related Spokes
> @@ -45,13 +44,3 @@ class SpokeCategory(object):
>      displayOnHub = None
>      sortOrder = 1000
>      title = N_("DEFAULT TITLE")
> -
> -def collect_categories(mask_paths):
> -    """Return a list of all category subclasses. Look for them in modules
> -       imported as module_mask % basename(f) where f is name of all files in path.
> -    """
> -    categories = []
> -    for mask, path in mask_paths:
> -        categories.extend(collect(mask, path, lambda obj: getattr(obj, "displayOnHub", None) != None))
> -
> -    return categories
> diff --git a/pyanaconda/ui/gui/hubs/__init__.py b/pyanaconda/ui/gui/hubs/__init__.py
> index 7dcdcdb..f7fc172 100644
> --- a/pyanaconda/ui/gui/hubs/__init__.py
> +++ b/pyanaconda/ui/gui/hubs/__init__.py
> @@ -29,8 +29,7 @@ from pyanaconda.product import distributionText
>  
>  from pyanaconda.ui import common
>  from pyanaconda.ui.gui import GUIObject
> -from pyanaconda.ui.gui.categories import collect_categories
> -from pyanaconda.ui.gui.spokes import StandaloneSpoke, collect_spokes
> +from pyanaconda.ui.gui.spokes import StandaloneSpoke
>  from pyanaconda.ui.gui.utils import gtk_call_once, escape_markup
>  from pyanaconda.constants import ANACONDA_ENVIRON
>  
> @@ -130,29 +129,11 @@ class Hub(GUIObject, common.Hub):
>  
>          action.exit_logger()
>  
> -    def _collectCategoriesAndSpokes(self):
> -        """collects categories and spokes to be displayed on this Hub
> -
> -           :return: dictionary mapping category class to list of spoke classes
> -           :rtype: dictionary[category class] -> [ list of spoke classes ]
> -        """
> -
> -        ret = {}
> -
> -        # Collect all the categories this hub displays, then collect all the
> -        # spokes belonging to all those categories.
> -        categories = sorted(filter(lambda c: c.displayOnHub == self.__class__, collect_categories(self.paths["categories"])),
> -                            key=lambda c: c.sortOrder)
> -        for c in categories:
> -            ret[c] = collect_spokes(self.paths["spokes"], c.__name__)
> -
> -        return ret
> -
>      def _createBox(self):
>          from gi.repository import Gtk, AnacondaWidgets
>          from pyanaconda.ui.gui.utils import setViewportBackground
>  
> -        cats_and_spokes = self._collectCategoriesAndSpokes()
> +        cats_and_spokes = common.collectCategoriesAndSpokes(self.paths, self.__class__)
>          categories = cats_and_spokes.keys()
>  
>          grid = Gtk.Grid(row_spacing=6, column_spacing=6, column_homogeneous=True,
> diff --git a/pyanaconda/ui/gui/spokes/__init__.py b/pyanaconda/ui/gui/spokes/__init__.py
> index f3fc74f..f9d11e8 100644
> --- a/pyanaconda/ui/gui/spokes/__init__.py
> +++ b/pyanaconda/ui/gui/spokes/__init__.py
> @@ -20,11 +20,10 @@
>  #                    Martin Sivak <msivak at redhat.com>
>  
>  from pyanaconda.ui import common
> -from pyanaconda.ui.common import collect
>  from pyanaconda.ui.gui import GUIObject
>  import os.path
>  
> -__all__ = ["StandaloneSpoke", "NormalSpoke", "collect_spokes"]
> +__all__ = ["StandaloneSpoke", "NormalSpoke"]
>  
>  class Spoke(GUIObject):
>      def __init__(self, data):
> @@ -93,20 +92,3 @@ class NormalSpoke(Spoke, common.NormalSpoke):
>  
>          self.window.hide()
>          Gtk.main_quit()
> -
> -def collect_spokes(mask_paths, category):
> -    """Return a list of all spoke subclasses that should appear for a given
> -       category. Look for them in files imported as module_path % basename(f)
> -
> -       :param mask_paths: list of mask, path tuples to search for classes
> -       :type mask_paths: list of (mask, path)
> -
> -       :return: list of Spoke classes belonging to category
> -       :rtype: list of Spoke classes
> -
> -    """
> -    spokes = []
> -    for mask, path in mask_paths:
> -        spokes.extend(collect(mask, path, lambda obj: hasattr(obj, "category") and obj.category != None and obj.category.__name__ == category))
> -
> -    return spokes
> diff --git a/pyanaconda/ui/tui/__init__.py b/pyanaconda/ui/tui/__init__.py
> index 402d625..4cf3690 100644
> --- a/pyanaconda/ui/tui/__init__.py
> +++ b/pyanaconda/ui/tui/__init__.py
> @@ -105,6 +105,9 @@ class TextUserInterface(ui.UserInterface):
>      pathlist = set([updatepath, basepath] + sitepackages)
>  
>      paths = ui.UserInterface.paths + {
> +            "categories": [(basemask + ".categories.%s",
> +                        os.path.join(path, "categories"))
> +                        for path in pathlist],
>              "spokes": [(basemask + ".spokes.%s",
>                          os.path.join(path, "spokes"))
>                          for path in pathlist],
> @@ -162,6 +165,7 @@ class TextUserInterface(ui.UserInterface):
>  
>              if hasattr(obj, "set_path"):
>                  obj.set_path("spokes", self.paths["spokes"])
> +                obj.set_path("categories", self.paths["categories"])
>  
>              should_schedule = obj.setup(self.ENVIRONMENT)
>  
> diff --git a/pyanaconda/ui/tui/categories/Makefile.am b/pyanaconda/ui/tui/categories/Makefile.am
> new file mode 100644
> index 0000000..0ad7913
> --- /dev/null
> +++ b/pyanaconda/ui/tui/categories/Makefile.am
> @@ -0,0 +1,22 @@
> +# Copyright (C) 2011  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: Chris Lumens <clumens at redhat.com>
> +
> +MAINTAINERCLEANFILES = Makefile.in
> +
> +pkgpyexecdir        = $(pyexecdir)/py$(PACKAGE_NAME)
> +categoriesdir       = $(pkgpyexecdir)/ui/tui/categories
> +categories_PYTHON   = $(srcdir)/*.py
> diff --git a/pyanaconda/ui/tui/categories/__init__.py b/pyanaconda/ui/tui/categories/__init__.py
> new file mode 100644
> index 0000000..06e431a
> --- /dev/null
> +++ b/pyanaconda/ui/tui/categories/__init__.py
> @@ -0,0 +1,46 @@
> +# Base classes for spoke categories.
> +#
> +# Copyright (C) 2011, 2013  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): Chris Lumens <clumens at redhat.com>
> +#
> +
> +import os.path
> +from pyanaconda.i18n import N_
> +
> +__all__ = ["SpokeCategory"]
> +
> +class SpokeCategory(object):
> +    """A SpokeCategory is an object used to group multiple related Spokes
> +       together on a hub.  It consists of a title displayed above, and then
> +       a two-column grid of SpokeSelectors.  Each SpokeSelector is associated
> +       with a Spoke subclass.  A SpokeCategory will only display those Spokes
> +       with a matching category attribute.
> +
> +       Class attributes:
> +
> +       displayOnHub  -- The Hub subclass to display this Category on.  If
> +                        None, this Category will be skipped.
> +       sortOrder     -- A number indicating the order in which this Category
> +                        will be displayed.  A lower number indicates display
> +                        higher up in the Hub.
> +       title         -- The title of this SpokeCategory, to be displayed above
> +                        the grid.
> +    """
> +    displayOnHub = None
> +    sortOrder = 1000
Do we need the sortOrder attribute?

> +    title = N_("DEFAULT TITLE")
> diff --git a/pyanaconda/ui/tui/categories/customization.py b/pyanaconda/ui/tui/categories/customization.py
> new file mode 100644
> index 0000000..b845e39
> --- /dev/null
> +++ b/pyanaconda/ui/tui/categories/customization.py
> @@ -0,0 +1,32 @@
> +# Localization category classes
> +#
> +# Copyright (C) 2011, 2013  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): Chris Lumens <clumens at redhat.com>
> +#                    Martin Sivak <msivak at redhat.com>
> +#
> +
> +from pyanaconda.i18n import N_
> +from pyanaconda.ui.tui.categories import SpokeCategory
> +from pyanaconda.ui.tui.hubs.summary import SummaryHub
> +
> +__all__ = ["CustomizationCategory"]
> +
> +class CustomizationCategory(SpokeCategory):
> +    displayOnHub = SummaryHub
> +    sortOrder = 100
> +    title = N_("CUSTOMIZATION")
> diff --git a/pyanaconda/ui/tui/categories/localization.py b/pyanaconda/ui/tui/categories/localization.py
> new file mode 100644
> index 0000000..b87ce40
> --- /dev/null
> +++ b/pyanaconda/ui/tui/categories/localization.py
> @@ -0,0 +1,31 @@
> +# Localization category classes
> +#
> +# Copyright (C) 2011, 2013  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): Chris Lumens <clumens at redhat.com>
> +#
> +
> +from pyanaconda.i18n import N_
> +from pyanaconda.ui.tui.categories import SpokeCategory
> +from pyanaconda.ui.tui.hubs.summary import SummaryHub
> +
> +__all__ = ["LocalizationCategory"]
> +
> +class LocalizationCategory(SpokeCategory):
> +    displayOnHub = SummaryHub
> +    sortOrder = 100
> +    title = N_("LOCALIZATION")
> diff --git a/pyanaconda/ui/tui/categories/software.py b/pyanaconda/ui/tui/categories/software.py
> new file mode 100644
> index 0000000..e15b7a9
> --- /dev/null
> +++ b/pyanaconda/ui/tui/categories/software.py
> @@ -0,0 +1,31 @@
> +# Software category classes
> +#
> +# Copyright (C) 2011, 2013  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): Chris Lumens <clumens at redhat.com>
> +#
> +
> +from pyanaconda.i18n import N_
> +from pyanaconda.ui.tui.categories import SpokeCategory
> +from pyanaconda.ui.tui.hubs.summary import SummaryHub
> +
> +__all__ = ["SoftwareCategory"]
> +
> +class SoftwareCategory(SpokeCategory):
> +    displayOnHub = SummaryHub
> +    sortOrder = 200
> +    title = N_("SOFTWARE")
> diff --git a/pyanaconda/ui/tui/categories/system.py b/pyanaconda/ui/tui/categories/system.py
> new file mode 100644
> index 0000000..4613c9b
> --- /dev/null
> +++ b/pyanaconda/ui/tui/categories/system.py
> @@ -0,0 +1,32 @@
> +# Storage category classes
> +#
> +# Copyright (C) 2011, 2013 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): Chris Lumens <clumens at redhat.com>
> +#                    David Lehman <dlehman at redhat.com>
> +#
> +
> +from pyanaconda.i18n import N_
> +from pyanaconda.ui.tui.categories import SpokeCategory
> +from pyanaconda.ui.tui.hubs.summary import SummaryHub
> +
> +__all__ = ["SystemCategory"]
> +
> +class SystemCategory(SpokeCategory):
> +    displayOnHub = SummaryHub
> +    sortOrder = 300
> +    title = N_("SYSTEM")
> diff --git a/pyanaconda/ui/tui/categories/user_settings.py b/pyanaconda/ui/tui/categories/user_settings.py
> new file mode 100644
> index 0000000..0ef3612
> --- /dev/null
> +++ b/pyanaconda/ui/tui/categories/user_settings.py
> @@ -0,0 +1,32 @@
> +# User settings category classes
> +#
> +# Copyright (C) 2011, 2013  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): Chris Lumens <clumens at redhat.com>
> +#                    Martin Sivak <msivak at redhat.com>
> +#
> +
> +from pyanaconda.i18n import N_
> +from pyanaconda.ui.tui.categories import SpokeCategory
> +from pyanaconda.ui.tui.hubs.summary import SummaryHub
> +
> +__all__ = ["UserSettingsCategory"]
> +
> +class UserSettingsCategory(SpokeCategory):
> +    displayOnHub = SummaryHub
> +    sortOrder = 200
> +    title = N_("USER SETTINGS")
> diff --git a/pyanaconda/ui/tui/hubs/__init__.py b/pyanaconda/ui/tui/hubs/__init__.py
> index e886b63..a1ee93e 100644
> --- a/pyanaconda/ui/tui/hubs/__init__.py
> +++ b/pyanaconda/ui/tui/hubs/__init__.py
> @@ -20,7 +20,6 @@
>  #
>  from pyanaconda.ui.tui import simpleline as tui
>  from pyanaconda.ui.tui.tuiobject import TUIObject
> -from pyanaconda.ui.tui.spokes import collect_spokes
>  from pyanaconda.ui import common
>  
>  from pyanaconda.i18n import _, C_, N_
> @@ -50,17 +49,18 @@ class TUIHub(TUIObject, common.Hub):
>          self._spoke_count = 0
>  
>      def setup(self, environment="anaconda"):
> -        # look for spokes having category present in self.categories
> -        for c in self.categories:
> -            spokes = collect_spokes(self.paths["spokes"], c)
> +        cats_and_spokes = common.collectCategoriesAndSpokes(self.paths, self.__class__)
> +        categories = cats_and_spokes.keys()
>  
> -            # sort them according to their priority
> -            for s in sorted(spokes, key = lambda s: s.title):
> +        for c in sorted(categories, key=lambda c: c.title):
This should use the c.sortOrder or we should get rid of that attribute.

> +            obj = c()
> +
> +            for spokeClass in sorted(cats_and_spokes[c], key=lambda s: s.title):
>                  # Check if this spoke is to be shown in anaconda
> -                if not s.should_run(environment, self.data):
> +                if not spokeClass.should_run(environment, self.data):
>                      continue
>  
> -                spoke = s(self.app, self.data, self.storage, self.payload, self.instclass)
> +                spoke = spokeClass(self.app, self.data, self.storage, self.payload, self.instclass)
>                  spoke.initialize()
>  
>                  if not spoke.showable:
> @@ -73,7 +73,7 @@ class TUIHub(TUIObject, common.Hub):
>  
>                  self._spoke_count += 1
>                  self._keys[self._spoke_count] = spoke
> -                self._spokes[spoke.__class__.__name__] = spoke
> +                self._spokes[spokeClass.__name__] = spoke
>  
>          # only schedule the hub if it has some spokes
>          return self._spoke_count != 0
> diff --git a/pyanaconda/ui/tui/hubs/summary.py b/pyanaconda/ui/tui/hubs/summary.py
> index 936812c..3b04c90 100644
> --- a/pyanaconda/ui/tui/hubs/summary.py
> +++ b/pyanaconda/ui/tui/hubs/summary.py
> @@ -32,8 +32,6 @@ log = logging.getLogger("anaconda")
>  
>  class SummaryHub(TUIHub):
>      title = N_("Installation")
> -    ## FIXME: this should be pulling data from somewhere, not just a static list
> -    categories = ["localization", "software", "system", "user"]
>  
>      def setup(self, environment="anaconda"):
>          should_schedule = TUIHub.setup(self, environment=environment)
> diff --git a/pyanaconda/ui/tui/spokes/__init__.py b/pyanaconda/ui/tui/spokes/__init__.py
> index 57984ba..51eb6d3 100644
> --- a/pyanaconda/ui/tui/spokes/__init__.py
> +++ b/pyanaconda/ui/tui/spokes/__init__.py
> @@ -20,7 +20,7 @@
>  #
>  from pyanaconda.ui.tui import simpleline as tui
>  from pyanaconda.ui.tui.tuiobject import TUIObject, YesNoDialog
> -from pyanaconda.ui.common import Spoke, StandaloneSpoke, NormalSpoke, collect
> +from pyanaconda.ui.common import Spoke, StandaloneSpoke, NormalSpoke
>  from pyanaconda.users import validatePassword, cryptPassword
>  import re
>  from collections import namedtuple
> @@ -29,8 +29,7 @@ from pyanaconda.i18n import N_, _
>  from pyanaconda.constants import PASSWORD_CONFIRM_ERROR_TUI
>  
>  __all__ = ["TUISpoke", "EditTUISpoke", "EditTUIDialog", "EditTUISpokeEntry",
> -           "StandaloneSpoke", "NormalTUISpoke", "collect_spokes",
> -           "collect_categories"]
> +           "StandaloneSpoke", "NormalTUISpoke"]
>  
>  # Inherit abstract methods from Spoke
>  # pylint: disable=W0223
> @@ -47,7 +46,6 @@ class TUISpoke(TUIObject, tui.Widget, Spoke):
>      """
>  
>      title = N_("Default spoke title")
> -    category = u""
>  
>      def __init__(self, app, data, storage, payload, instclass):
>          if self.__class__ is TUISpoke:
> @@ -311,21 +309,3 @@ class EditTUISpoke(NormalTUISpoke):
>  
>  class StandaloneTUISpoke(TUISpoke, StandaloneSpoke):
>      pass
> -
> -def collect_spokes(mask_paths, category):
> -    """Return a list of all spoke subclasses that should appear for a given
> -       category.
> -    """
> -    spokes = []
> -    for mask, path in mask_paths:
> -        spokes.extend(collect(mask, path, lambda obj: hasattr(obj, "category") and obj.category != None and obj.category == category))
> -
> -    return spokes
> -
> -def collect_categories(mask_paths):
> -    classes = []
> -    for mask, path in mask_paths:
> -        classes.extend(collect(mask, path, lambda obj: hasattr(obj, "category") and obj.category != None and obj.category != ""))
> -
> -    categories = set(c.category for c in classes)
> -    return categories
> diff --git a/pyanaconda/ui/tui/spokes/askvnc.py b/pyanaconda/ui/tui/spokes/askvnc.py
> index 19c0d50..dc9273e 100644
> --- a/pyanaconda/ui/tui/spokes/askvnc.py
> +++ b/pyanaconda/ui/tui/spokes/askvnc.py
> @@ -36,7 +36,6 @@ def exception_msg_handler_and_exit(event, data):
>  
>  class AskVNCSpoke(NormalTUISpoke):
>      title = N_("VNC")
> -    category = "vnc"
>  
>      # This spoke is kinda standalone, not meant to be used with a hub
>      # We pass in some fake data just to make our parents happy
> @@ -109,7 +108,6 @@ class AskVNCSpoke(NormalTUISpoke):
>  
>  class VNCPassSpoke(NormalTUISpoke):
>      title = N_("VNC Password")
> -    category = "vnc"
>  
>      def __init__(self, app, data, storage, payload, instclass, message=None):
>          NormalTUISpoke.__init__(self, app, data, storage, payload, instclass)
> diff --git a/pyanaconda/ui/tui/spokes/network.py b/pyanaconda/ui/tui/spokes/network.py
> index 8ede756..fe74446 100644
> --- a/pyanaconda/ui/tui/spokes/network.py
> +++ b/pyanaconda/ui/tui/spokes/network.py
> @@ -22,6 +22,7 @@
>  
> 
>  from pyanaconda.flags import can_touch_runtime_system
> +from pyanaconda.ui.tui.categories.system import SystemCategory
>  from pyanaconda.ui.tui.spokes import EditTUISpoke, OneShotEditTUIDialog
>  from pyanaconda.ui.tui.spokes import EditTUISpokeEntry as Entry
>  from pyanaconda.ui.tui.simpleline import TextWidget, ColumnWidget
> @@ -40,7 +41,7 @@ __all__ = ["NetworkSpoke"]
>  class NetworkSpoke(EditTUISpoke):
>      """ Spoke used to configure network settings. """
>      title = N_("Network configuration")
> -    category = "system"
> +    category = SystemCategory
>  
>      def __init__(self, app, data, storage, payload, instclass):
>          EditTUISpoke.__init__(self, app, data, storage, payload, instclass)
> diff --git a/pyanaconda/ui/tui/spokes/password.py b/pyanaconda/ui/tui/spokes/password.py
> index 870fff4..bb98418 100644
> --- a/pyanaconda/ui/tui/spokes/password.py
> +++ b/pyanaconda/ui/tui/spokes/password.py
> @@ -21,6 +21,7 @@
>  #                    Chris Lumens <clumens at redhat.com>
>  #
>  
> +from pyanaconda.ui.tui.categories.user_settings import UserSettingsCategory
>  from pyanaconda.ui.tui.spokes import EditTUIDialog, EditTUISpokeEntry
>  from pyanaconda.ui.common import FirstbootSpokeMixIn
>  from pyanaconda.ui.tui.simpleline import TextWidget
> @@ -29,7 +30,7 @@ from pyanaconda.i18n import N_, _
>  
>  class PasswordSpoke(FirstbootSpokeMixIn, EditTUIDialog):
>      title = N_("Root password")
> -    category = "user"
> +    category = UserSettingsCategory
>  
>      def __init__(self, app, data, storage, payload, instclass):
>          EditTUIDialog.__init__(self, app, data, storage, payload, instclass)
> diff --git a/pyanaconda/ui/tui/spokes/shell_spoke.py b/pyanaconda/ui/tui/spokes/shell_spoke.py
> index 4915f98..b355387 100644
> --- a/pyanaconda/ui/tui/spokes/shell_spoke.py
> +++ b/pyanaconda/ui/tui/spokes/shell_spoke.py
> @@ -20,6 +20,7 @@
>  
>  """Text mode shell spoke"""
>  
> +from pyanaconda.ui.tui.categories.system import SystemCategory
>  from pyanaconda.ui.tui.spokes import NormalTUISpoke
>  from pyanaconda.ui.tui.simpleline.widgets import TextWidget
>  from pyanaconda.i18n import N_, _
> @@ -31,7 +32,7 @@ import subprocess
>  
>  class ShellSpoke(NormalTUISpoke):
>      title = N_("Shell")
> -    category = "system"
> +    category = SystemCategory
>  
>      @classmethod
>      def should_run(cls, environment, data):
> diff --git a/pyanaconda/ui/tui/spokes/software.py b/pyanaconda/ui/tui/spokes/software.py
> index 2b414d6..e63242f 100644
> --- a/pyanaconda/ui/tui/spokes/software.py
> +++ b/pyanaconda/ui/tui/spokes/software.py
> @@ -20,6 +20,7 @@
>  #
>  
>  from pyanaconda.flags import flags
> +from pyanaconda.ui.tui.categories.software import SoftwareCategory
>  from pyanaconda.ui.tui.spokes import NormalTUISpoke
>  from pyanaconda.ui.tui.simpleline import TextWidget, ColumnWidget, CheckboxWidget
>  from pyanaconda.threads import threadMgr, AnacondaThread
> @@ -36,7 +37,7 @@ __all__ = ["SoftwareSpoke"]
>  class SoftwareSpoke(NormalTUISpoke):
>      """ Spoke used to read new value of text to represent source repo. """
>      title = N_("Software selection")
> -    category = "software"
> +    category = SoftwareCategory
>  
>      def __init__(self, app, data, storage, payload, instclass):
>          NormalTUISpoke.__init__(self, app, data, storage, payload, instclass)
> diff --git a/pyanaconda/ui/tui/spokes/source.py b/pyanaconda/ui/tui/spokes/source.py
> index 45381df..0aaf4c2 100644
> --- a/pyanaconda/ui/tui/spokes/source.py
> +++ b/pyanaconda/ui/tui/spokes/source.py
> @@ -20,6 +20,7 @@
>  #
>  
>  from pyanaconda.flags import flags
> +from pyanaconda.ui.tui.categories.software import SoftwareCategory
>  from pyanaconda.ui.tui.spokes import EditTUISpoke, NormalTUISpoke
>  from pyanaconda.ui.tui.spokes import EditTUISpokeEntry as Entry
>  from pyanaconda.ui.tui.simpleline import TextWidget, ColumnWidget
> @@ -51,7 +52,7 @@ __all__ = ["SourceSpoke"]
>  class SourceSpoke(EditTUISpoke, SourceSwitchHandler):
>      """ Spoke used to customize the install source repo. """
>      title = N_("Installation source")
> -    category = "software"
> +    category = SoftwareCategory
>  
>      _protocols = (N_("Closest mirror"), "http://", "https://", "ftp://", "nfs")
>  
> @@ -254,7 +255,7 @@ class SourceSpoke(EditTUISpoke, SourceSwitchHandler):
>  class SpecifyRepoSpoke(EditTUISpoke, SourceSwitchHandler):
>      """ Specify the repo URL here if closest mirror not selected. """
>      title = N_("Specify Repo Options")
> -    category = "software"
> +    category = SoftwareCategory
>  
>      edit_fields = [
>          Entry(N_("Repo URL"), "url", re.compile(".*$"), True)
> @@ -292,7 +293,7 @@ class SpecifyRepoSpoke(EditTUISpoke, SourceSwitchHandler):
>  class SpecifyNFSRepoSpoke(EditTUISpoke, SourceSwitchHandler):
>      """ Specify server and mount opts here if NFS selected. """
>      title = N_("Specify Repo Options")
> -    category = "software"
> +    category = SoftwareCategory
>  
>      edit_fields = [
>          Entry(N_("NFS <server>:/<path>"), "server", re.compile(".*$"), True),
> @@ -339,7 +340,7 @@ class SpecifyNFSRepoSpoke(EditTUISpoke, SourceSwitchHandler):
>  class SelectDeviceSpoke(NormalTUISpoke):
>      """ Select device containing the install source ISO file. """
>      title = N_("Select device containing the ISO file")
> -    category = "source"
> +    category = SoftwareCategory
>  
>      def __init__(self, app, data, storage, payload, instclass):
>          NormalTUISpoke.__init__(self, app, data, storage, payload, instclass)
> @@ -426,7 +427,7 @@ class SelectDeviceSpoke(NormalTUISpoke):
>  class SelectISOSpoke(NormalTUISpoke, SourceSwitchHandler):
>      """ Select an ISO to use as install source. """
>      title = N_("Select an ISO to use as install source")
> -    category = "source"
> +    category = SoftwareCategory
>  
>      def __init__(self, app, data, storage, payload, instclass, device):
>          NormalTUISpoke.__init__(self, app, data, storage, payload, instclass)
> diff --git a/pyanaconda/ui/tui/spokes/storage.py b/pyanaconda/ui/tui/spokes/storage.py
> index cb43d98..9e47f81 100644
> --- a/pyanaconda/ui/tui/spokes/storage.py
> +++ b/pyanaconda/ui/tui/spokes/storage.py
> @@ -23,6 +23,7 @@
>  #
>  
>  from pyanaconda.ui.lib.disks import getDisks, applyDiskSelection
> +from pyanaconda.ui.tui.categories.system import SystemCategory
>  from pyanaconda.ui.tui.spokes import NormalTUISpoke
>  from pyanaconda.ui.tui.simpleline import TextWidget, CheckboxWidget
>  from pyanaconda.ui.tui.tuiobject import YesNoDialog
> @@ -66,7 +67,7 @@ class StorageSpoke(NormalTUISpoke):
>      as disk selection, partitioning, and fs type.
>      """
>      title = N_("Installation Destination")
> -    category = "system"
> +    category = SystemCategory
>  
>      def __init__(self, app, data, storage, payload, instclass):
>          NormalTUISpoke.__init__(self, app, data, storage, payload, instclass)
> @@ -433,7 +434,7 @@ class StorageSpoke(NormalTUISpoke):
>  class AutoPartSpoke(NormalTUISpoke):
>      """ Autopartitioning options are presented here. """
>      title = N_("Autopartitioning Options")
> -    category = "system"
> +    category = SystemCategory
>  
>      def __init__(self, app, data, storage, payload, instclass):
>          NormalTUISpoke.__init__(self, app, data, storage, payload, instclass)
> @@ -499,7 +500,7 @@ class AutoPartSpoke(NormalTUISpoke):
>  class PartitionSchemeSpoke(NormalTUISpoke):
>      """ Spoke to select what partitioning scheme to use on disk(s). """
>      title = N_("Partition Scheme Options")
> -    category = "system"
> +    category = SystemCategory
>  
>      # set default FS to LVM, for consistency with graphical behavior
>      _selection = 1
> diff --git a/pyanaconda/ui/tui/spokes/time_spoke.py b/pyanaconda/ui/tui/spokes/time_spoke.py
> index 75c1244..ec0f8f4 100644
> --- a/pyanaconda/ui/tui/spokes/time_spoke.py
> +++ b/pyanaconda/ui/tui/spokes/time_spoke.py
> @@ -19,6 +19,7 @@
>  # Red Hat Author(s): Martin Sivak <msivak at redhat.com>
>  #
>  
> +from pyanaconda.ui.tui.categories.localization import LocalizationCategory
>  from pyanaconda.ui.tui.spokes import NormalTUISpoke
>  from pyanaconda.ui.tui.simpleline import TextWidget, ColumnWidget
>  from pyanaconda.ui.common import FirstbootSpokeMixIn
> @@ -28,7 +29,7 @@ from pyanaconda.constants_text import INPUT_PROCESSED
>  
>  class TimeZoneSpoke(FirstbootSpokeMixIn, NormalTUISpoke):
>      title = N_("Timezone settings")
> -    category = "localization"
> +    category = LocalizationCategory
>  
>      def __init__(self, app, data, storage, payload, instclass):
>          NormalTUISpoke.__init__(self, app, data, storage, payload, instclass)
> diff --git a/pyanaconda/ui/tui/spokes/user.py b/pyanaconda/ui/tui/spokes/user.py
> index f069eec..4871ab7 100644
> --- a/pyanaconda/ui/tui/spokes/user.py
> +++ b/pyanaconda/ui/tui/spokes/user.py
> @@ -20,6 +20,7 @@
>  #                    Chris Lumens <clumens at redhat.com>
>  #
>  
> +from pyanaconda.ui.tui.categories.user_settings import UserSettingsCategory
>  from pyanaconda.ui.tui.spokes import EditTUISpoke
>  from pyanaconda.ui.tui.spokes import EditTUISpokeEntry as Entry
>  from pyanaconda.ui.common import FirstbootSpokeMixIn
> @@ -34,7 +35,7 @@ __all__ = ["UserSpoke"]
>  
>  class UserSpoke(FirstbootSpokeMixIn, EditTUISpoke):
>      title = N_("User creation")
> -    category = "user"
> +    category = UserSettingsCategory
>  
>      edit_fields = [
>          Entry("Create user", "_create", EditTUISpoke.CHECK, True),
Other that those comments above, I'm quite sure this is going to break
the TUI Initial Setup. Martin, could you please try applying this patch
and see what needs to be changed in the Initial Setup? I remember some
hacks/overrides in the GUI code due to categories, we will probably need
the same in the TUI code now.

-- 
Vratislav Podzimek

Anaconda Rider | Red Hat, Inc. | Brno - Czech Republic



More information about the anaconda-patches mailing list