From e967f81f6abdf24b8eb13d0aa8f58ae44e4d9be7 Mon Sep 17 00:00:00 2001
From: Lyndon Brown <jnqnfe@gmail.com>
Date: Thu, 18 Apr 2019 20:02:54 +0100
Subject: [PATCH] config: lookup cat from subcat

having `set_category()` + `set_subcategory()` pairs of calls to setup the
location in the preferences tree where a plugin node needs to be attached
to, with corresponding pairs of option records in the plugin option sets,
is silly, inefficient and bug prone. all we need is the subcat records
and we can look up the corresponding cat from the data table when it
comes to time to build the tree.

here we take a step forward to address this, adding cat data to the subcat
data table, and a lookup function making use of it.

note, qt and macos tree construction are done a little differently from
each other, so while the change here is entirely sufficient to rid the core
option set of category hints as far as the macos code is concerned, more
work in a subsequent commit will be needed for qt. thus the purge of
`set_category()` must be postponed for a later commit and so for now we
must just ignore those records.

a subcat table entry was added for `SUBCAT_HIDDEN` since for now the qt
code could potentially look this up and we should preserve the existing
behaviour for it for now.
---
 include/vlc_config_cat.h                      | 89 +++++++++++--------
 modules/gui/macosx/preferences/prefs.m        | 24 ++---
 .../preferences/complete_preferences.cpp      | 12 ++-
 .../preferences/complete_preferences.hpp      | 12 ++-
 4 files changed, 75 insertions(+), 62 deletions(-)

diff --git a/include/vlc_config_cat.h b/include/vlc_config_cat.h
index 93cf7da7fdf7..96b2526cfaea 100644
--- a/include/vlc_config_cat.h
+++ b/include/vlc_config_cat.h
@@ -202,6 +202,7 @@ struct config_category_t
 struct config_subcategory_t
 {
     int         id;
+    int         cat;
     const char *name;
     const char *help;
 };
@@ -219,45 +220,47 @@ static const struct config_category_t categories_array[] =
 
 static const struct config_subcategory_t subcategories_array[] =
 {
-    { SUBCAT_INTERFACE_GENERAL, INTF_TITLE, INTF_GENERAL_HELP },
-    { SUBCAT_INTERFACE_MAIN, INTF_MAIN_TITLE, INTF_MAIN_HELP },
-    { SUBCAT_INTERFACE_CONTROL, INTF_CONTROL_TITLE, INTF_CONTROL_HELP },
-    { SUBCAT_INTERFACE_HOTKEYS, INTF_HOTKEYS_TITLE, INTF_HOTKEYS_HELP },
-
-    { SUBCAT_AUDIO_GENERAL, AUDIO_TITLE, AUDIO_GENERAL_HELP },
-    { SUBCAT_AUDIO_AOUT, AOUT_TITLE, AOUT_HELP },
-    { SUBCAT_AUDIO_AFILTER, AFILTER_TITLE, AFILTER_HELP },
-    { SUBCAT_AUDIO_RESAMPLER, ARESAMPLER_TITLE, AFILTER_HELP },
-    { SUBCAT_AUDIO_VISUAL, AVISUAL_TITLE, AVISUAL_HELP },
-
-    { SUBCAT_VIDEO_GENERAL, VIDEO_TITLE, VIDEO_GENERAL_HELP },
-    { SUBCAT_VIDEO_VOUT, _VOUT_TITLE, VOUT_HELP },
-    { SUBCAT_VIDEO_VFILTER, VFILTER_TITLE, VFILTER_HELP },
-    { SUBCAT_VIDEO_SUBPIC, SUBPIC_TITLE, SUBPIC_HELP },
-    { SUBCAT_VIDEO_SPLITTER, SPLITTER_TITLE, SPLITTER_HELP },
-
-    { SUBCAT_INPUT_GENERAL, INPUT_TITLE, INPUT_HELP },
-    { SUBCAT_INPUT_ACCESS, ACCESS_TITLE, ACCESS_HELP },
-    { SUBCAT_INPUT_DEMUX, DEMUX_TITLE, DEMUX_HELP },
-    { SUBCAT_INPUT_VCODEC, VDEC_TITLE, VDEC_HELP },
-    { SUBCAT_INPUT_ACODEC, ADEC_TITLE, ADEC_HELP },
-    { SUBCAT_INPUT_SCODEC, SDEC_TITLE, SDEC_HELP },
-    { SUBCAT_INPUT_STREAM_FILTER, STREAM_FILTER_TITLE, STREAM_FILTER_HELP },
-
-    { SUBCAT_SOUT_GENERAL, SOUT_TITLE, SOUT_GENERAL_HELP },
-    { SUBCAT_SOUT_STREAM, SOUT_STREAM_TITLE, SOUT_STREAM_HELP },
-    { SUBCAT_SOUT_MUX, SOUT_MUX_TITLE, SOUT_MUX_HELP },
-    { SUBCAT_SOUT_ACO, SOUT_ACO_TITLE, SOUT_ACO_HELP },
-    { SUBCAT_SOUT_PACKETIZER, SOUT_PACKET_TITLE, SOUT_PACKET_HELP },
-    { SUBCAT_SOUT_RENDERER, SOUT_RENDER_TITLE, SOUT_RENDER_HELP },
-    { SUBCAT_SOUT_VOD, SOUT_VOD_TITLE, SOUT_VOD_HELP },
-
-    { SUBCAT_PLAYLIST_GENERAL, PLAYLIST_TITLE, PGENERAL_HELP },
-    { SUBCAT_PLAYLIST_EXPORT, PEXPORT_TITLE, PEXPORT_HELP },
-    { SUBCAT_PLAYLIST_SD, SD_TITLE, SD_HELP },
-
-    { SUBCAT_ADVANCED_MISC, MISC_TITLE, AADVANCED_HELP },
-    { SUBCAT_ADVANCED_NETWORK, ANETWORK_TITLE, ANETWORK_HELP },
+    { SUBCAT_INTERFACE_GENERAL,    CAT_INTERFACE,  INTF_TITLE,           INTF_GENERAL_HELP  },
+    { SUBCAT_INTERFACE_MAIN,       CAT_INTERFACE,  INTF_MAIN_TITLE,      INTF_MAIN_HELP     },
+    { SUBCAT_INTERFACE_CONTROL,    CAT_INTERFACE,  INTF_CONTROL_TITLE,   INTF_CONTROL_HELP  },
+    { SUBCAT_INTERFACE_HOTKEYS,    CAT_INTERFACE,  INTF_HOTKEYS_TITLE,   INTF_HOTKEYS_HELP  },
+
+    { SUBCAT_AUDIO_GENERAL,        CAT_AUDIO,      AUDIO_TITLE,          AUDIO_GENERAL_HELP },
+    { SUBCAT_AUDIO_AOUT,           CAT_AUDIO,      AOUT_TITLE,           AOUT_HELP          },
+    { SUBCAT_AUDIO_AFILTER,        CAT_AUDIO,      AFILTER_TITLE,        AFILTER_HELP       },
+    { SUBCAT_AUDIO_RESAMPLER,      CAT_AUDIO,      ARESAMPLER_TITLE,     AFILTER_HELP       },
+    { SUBCAT_AUDIO_VISUAL,         CAT_AUDIO,      AVISUAL_TITLE,        AVISUAL_HELP       },
+
+    { SUBCAT_VIDEO_GENERAL,        CAT_VIDEO,      VIDEO_TITLE,          VIDEO_GENERAL_HELP },
+    { SUBCAT_VIDEO_VOUT,           CAT_VIDEO,      _VOUT_TITLE,          VOUT_HELP          },
+    { SUBCAT_VIDEO_VFILTER,        CAT_VIDEO,      VFILTER_TITLE,        VFILTER_HELP       },
+    { SUBCAT_VIDEO_SUBPIC,         CAT_VIDEO,      SUBPIC_TITLE,         SUBPIC_HELP        },
+    { SUBCAT_VIDEO_SPLITTER,       CAT_VIDEO,      SPLITTER_TITLE,       SPLITTER_HELP      },
+
+    { SUBCAT_INPUT_GENERAL,        CAT_INPUT,      INPUT_TITLE,          INPUT_HELP         },
+    { SUBCAT_INPUT_ACCESS,         CAT_INPUT,      ACCESS_TITLE,         ACCESS_HELP        },
+    { SUBCAT_INPUT_DEMUX,          CAT_INPUT,      DEMUX_TITLE,          DEMUX_HELP         },
+    { SUBCAT_INPUT_VCODEC,         CAT_INPUT,      VDEC_TITLE,           VDEC_HELP          },
+    { SUBCAT_INPUT_ACODEC,         CAT_INPUT,      ADEC_TITLE,           ADEC_HELP          },
+    { SUBCAT_INPUT_SCODEC,         CAT_INPUT,      SDEC_TITLE,           SDEC_HELP          },
+    { SUBCAT_INPUT_STREAM_FILTER,  CAT_INPUT,      STREAM_FILTER_TITLE,  STREAM_FILTER_HELP },
+
+    { SUBCAT_SOUT_GENERAL,         CAT_SOUT,       SOUT_TITLE,           SOUT_GENERAL_HELP  },
+    { SUBCAT_SOUT_STREAM,          CAT_SOUT,       SOUT_STREAM_TITLE,    SOUT_STREAM_HELP   },
+    { SUBCAT_SOUT_MUX,             CAT_SOUT,       SOUT_MUX_TITLE,       SOUT_MUX_HELP      },
+    { SUBCAT_SOUT_ACO,             CAT_SOUT,       SOUT_ACO_TITLE,       SOUT_ACO_HELP      },
+    { SUBCAT_SOUT_PACKETIZER,      CAT_SOUT,       SOUT_PACKET_TITLE,    SOUT_PACKET_HELP   },
+    { SUBCAT_SOUT_RENDERER,        CAT_SOUT,       SOUT_RENDER_TITLE,    SOUT_RENDER_HELP   },
+    { SUBCAT_SOUT_VOD,             CAT_SOUT,       SOUT_VOD_TITLE,       SOUT_VOD_HELP      },
+
+    { SUBCAT_PLAYLIST_GENERAL,     CAT_PLAYLIST,   PLAYLIST_TITLE,       PGENERAL_HELP      },
+    { SUBCAT_PLAYLIST_EXPORT,      CAT_PLAYLIST,   PEXPORT_TITLE,        PEXPORT_HELP       },
+    { SUBCAT_PLAYLIST_SD,          CAT_PLAYLIST,   SD_TITLE,             SD_HELP            },
+
+    { SUBCAT_ADVANCED_MISC,        CAT_ADVANCED,   MISC_TITLE,           AADVANCED_HELP     },
+    { SUBCAT_ADVANCED_NETWORK,     CAT_ADVANCED,   ANETWORK_TITLE,       ANETWORK_HELP      },
+
+    { SUBCAT_HIDDEN,               CAT_HIDDEN,     NULL,                 NULL               },
 };
 
 /** Get the table index for the given category entry. */
@@ -324,6 +327,14 @@ static inline const char *vlc_config_subcat_GetHelp( int subcat )
     return (i != -1) ? vlc_gettext(subcategories_array[i].help) : NULL;
 }
 
+/** Get the parent category for the given subcategory. */
+VLC_USED
+static inline int vlc_config_cat_FromSubcat( int subcat )
+{
+    int i = vlc_config_subcat_IndexOf( subcat );
+    return (i != -1) ? subcategories_array[i].cat : CAT_UNKNOWN;
+}
+
 /** Check if the given subcategory is a "general" one.
  *
  * In a cat/subcat preference tree, subcategories typically appear as child
diff --git a/modules/gui/macosx/preferences/prefs.m b/modules/gui/macosx/preferences/prefs.m
index eb588e754ffd..2ea68c991606 100644
--- a/modules/gui/macosx/preferences/prefs.m
+++ b/modules/gui/macosx/preferences/prefs.m
@@ -475,6 +475,7 @@
         VLCTreeSubCategoryItem * subCategoryItem = nil;
         VLCTreePluginItem * pluginItem = nil;
         module_config_t *p_configs = NULL;
+        int lastcat = CAT_UNKNOWN;
         int lastsubcat = SUBCAT_UNKNOWN;
         unsigned int confsize;
 
@@ -496,26 +497,25 @@
         for (unsigned int j = 0; j < confsize; j++) {
             int configType = p_configs[j].i_type;
 
-            if (configType == CONFIG_CATEGORY) {
-                if( p_configs[j].value.i == CAT_HIDDEN ) {
+            if (configType == CONFIG_CATEGORY)
+                continue; /* ignore */
+
+            if (configType == CONFIG_SUBCATEGORY) {
+                lastsubcat = (int)p_configs[j].value.i;
+                if( lastsubcat == SUBCAT_HIDDEN ) {
                     categoryItem = nil;
+                    subCategoryItem = nil;
                     continue;
                 }
-                categoryItem = [self itemRepresentingCategory:(int)p_configs[j].value.i];
+                lastcat = vlc_config_cat_FromSubcat(lastsubcat);
+
+                categoryItem = [self itemRepresentingCategory:lastcat];
                 if (!categoryItem) {
-                    categoryItem = [VLCTreeCategoryItem categoryTreeItemWithCategory:(int)p_configs[j].value.i];
+                    categoryItem = [VLCTreeCategoryItem categoryTreeItemWithCategory:lastcat];
                     if (categoryItem)
                         [[self children] addObject:categoryItem];
                 }
-                continue;
-            }
 
-            if (configType == CONFIG_SUBCATEGORY) {
-                lastsubcat = (int)p_configs[j].value.i;
-                if( lastsubcat == SUBCAT_HIDDEN ) {
-                    subCategoryItem = nil;
-                    continue;
-                }
                 if (categoryItem && !vlc_config_subcat_IsGeneral(lastsubcat)) {
                     subCategoryItem = [categoryItem itemRepresentingSubCategory:lastsubcat];
                     if (!subCategoryItem) {
diff --git a/modules/gui/qt/dialogs/preferences/complete_preferences.cpp b/modules/gui/qt/dialogs/preferences/complete_preferences.cpp
index 3f28abdf65c3..936f9d0c30d0 100644
--- a/modules/gui/qt/dialogs/preferences/complete_preferences.cpp
+++ b/modules/gui/qt/dialogs/preferences/complete_preferences.cpp
@@ -193,20 +193,24 @@ PrefsTree::PrefsTree( qt_intf_t *_p_intf, QWidget *_parent,
             const module_config_t *p_item = p_config + i;
 
             if( p_item->i_type == CONFIG_CATEGORY )
-                i_category = p_item->value.i;
-            else if( p_item->i_type == CONFIG_SUBCATEGORY )
+                continue; /* ignore */
+
+            if( p_item->i_type == CONFIG_SUBCATEGORY )
+            {
                 i_subcategory = p_item->value.i;
+                i_category = vlc_config_cat_FromSubcat( i_subcategory );
+            }
 
             if( CONFIG_ITEM(p_item->i_type) )
                 b_options = true;
 
-            if( b_options && i_category != CAT_UNKNOWN && i_subcategory != SUBCAT_UNKNOWN )
+            if( b_options && i_category != CAT_UNKNOWN )
                 break;
         }
         module_config_free (p_config);
 
         /* Dummy item, please proceed */
-        if( !b_options || i_category == CAT_UNKNOWN || i_subcategory == SUBCAT_UNKNOWN )
+        if( !b_options || i_category == CAT_UNKNOWN )
             continue;
 
         // Locate the category item;
diff --git a/modules/gui/qt/dialogs/preferences/complete_preferences.hpp b/modules/gui/qt/dialogs/preferences/complete_preferences.hpp
index 45ee577b34ea..1e1f9adc4a26 100644
--- a/modules/gui/qt/dialogs/preferences/complete_preferences.hpp
+++ b/modules/gui/qt/dialogs/preferences/complete_preferences.hpp
@@ -45,13 +45,11 @@
  *    entries would just have empty panels).
  * 3) Plugins (currently) have their option sets located under a single tree
  *    node attached to one of the core cat/subcat nodes. The location for this
- *    is chosen based upon the first cat and subcat encountered in the plugin's
- *    option set (others are ignored). (If due to a mistake the subcat does not
- *    belong to the cat, then the node is attached directly to the cat node just
- *    as if the cat's general subcat had been specified; If the plugin's option
- *    set has options before the cat/subcat hint entries, this does not matter;
- *    If no cat or subcat hint is provided in the option set, then no node is
- *    created (i.e. that plugins's options will not be shown).
+ *    is chosen based upon the first subcat encountered in the plugin's option
+ *    set (others are ignored). If the plugin's option set has options before
+ *    the cat/subcat hint entries, this does not matter; If no cat or subcat
+ *    hint is provided in the option set, then no node is created (i.e. that
+ *    plugins's options will not be shown).
  */
 
 class AdvPrefsPanel;
-- 
GitLab