mmenu; fix for minor bug -- when 'do not show app in main cat, if it has subcats...
[pandora-libraries.git] / minimenu / mmcat.c
index ba030a4..ab3e9d4 100644 (file)
@@ -39,6 +39,12 @@ void category_init ( void ) {
   return;
 }
 
+static char *_normalize ( char *catname, char *parentcatname ) {
+  static char buffer [ 101 ];
+  snprintf ( buffer, 100, "%s*%s", catname, parentcatname ? parentcatname : "NoParent" );
+  return ( buffer );
+}
+
 unsigned char category_push ( char *catname, char *parentcatname, pnd_disco_t *app, pnd_conf_handle ovrh, char *fspath, unsigned char visiblep ) {
   mm_category_t *c;
 
@@ -51,12 +57,12 @@ unsigned char category_push ( char *catname, char *parentcatname, pnd_disco_t *a
   // find or create category
   //
 
-  if ( ( c = pnd_box_find_by_key ( m_categories, catname ) ) ) {
+  if ( ( c = pnd_box_find_by_key ( m_categories, _normalize ( catname, parentcatname ) ) ) ) {
     // category was found..
   } else {
     // category wasn't found..
     //pnd_log ( PND_LOG_DEFAULT, "New category '%s'\n", catname );
-    c = pnd_box_allocinsert ( m_categories, catname, sizeof(mm_category_t) );
+    c = pnd_box_allocinsert ( m_categories, _normalize ( catname, parentcatname ), sizeof(mm_category_t) );
     c -> catname = strdup ( catname );
     if ( parentcatname ) {
       c -> parent_catname = strdup ( parentcatname );
@@ -291,7 +297,7 @@ unsigned char category_map_setup ( void ) {
        //pnd_log ( pndn_debug, "target(%s) from(%s)\n", k, buffer );
 
        category_push ( k, NULL /* parent cat */, NULL, 0, NULL /* fspath */, 1 );
-       g_catmaps [ g_catmapcount ].target = pnd_box_find_by_key ( m_categories, k );
+       g_catmaps [ g_catmapcount ].target = pnd_box_find_by_key ( m_categories, _normalize ( k, NULL /* TBD: hack, not sure if this is right default value */ ) );
        g_catmaps [ g_catmapcount ].from = strdup ( buffer );
        g_catmapcount++;
 
@@ -318,7 +324,7 @@ mm_category_t *category_map_query ( char *cat ) {
   return ( NULL );
 }
 
-unsigned char category_meta_push ( char *catname, char *parentcatname, pnd_disco_t *app, pnd_conf_handle ovrh, unsigned char visiblep ) {
+unsigned char category_meta_push ( char *catname, char *parentcatname, pnd_disco_t *app, pnd_conf_handle ovrh, unsigned char visiblep, unsigned char parentp ) {
   mm_category_t *cat;
 #if 0 // prepending
   char catnamebuffer [ 512 ] = "";
@@ -335,6 +341,11 @@ unsigned char category_meta_push ( char *catname, char *parentcatname, pnd_disco
     goto category_done_audit;
   }
 
+  // check if category came from an ovr-file; if so, we implicitly trust it instead of enforcing rules
+  if ( app -> object_flags & ( PND_DISCO_CUSTOM1 | PND_DISCO_CUSTOM2 ) ) {
+    goto category_done_audit;
+  }
+
   // category cleansing; lets..
   // - ensure we only let good freedesktop categories through
   // - we fix case.. no more UtIliTy (a good cat, studlycaps)
@@ -343,19 +354,19 @@ unsigned char category_meta_push ( char *catname, char *parentcatname, pnd_disco
 
   unsigned char cat_is_clean = 1;
   freedesktop_cat_t *fdcat = NULL, *fdpcat = NULL;
-  fdcat = freedesktop_category_query ( catname );
+  fdcat = freedesktop_category_query ( catname, parentcatname );
   if ( parentcatname ) {
-    fdpcat = freedesktop_category_query ( parentcatname );
+    fdpcat = freedesktop_category_query ( parentcatname, NULL );
   }
 
   // ensure requested cat is good
   if ( ! fdcat ) {
     // requested cat is bad, send it to Other
     cat_is_clean = 0;
-    printf ( "PXML Fail %s: Cat request %s (parent %s) -> bad cat\n", app -> title_en ? app -> title_en : "no name?", catname, parentcatname ? parentcatname : "n/a" );
+    pnd_log ( pndn_warning, "PXML Fail %s: Cat request %s (parent %s) -> bad cat\n", app -> title_en ? app -> title_en : "no name?", catname, parentcatname ? parentcatname : "n/a" );
 
     // do the Other substitution right away, so remaining code has something to look at in fdcat
-    fdcat = freedesktop_category_query ( BADCATNAME );
+    fdcat = freedesktop_category_query ( BADCATNAME, NULL );
     catname = fdcat -> cat;
     fdpcat = NULL;
     parentcatname = NULL;
@@ -370,7 +381,7 @@ unsigned char category_meta_push ( char *catname, char *parentcatname, pnd_disco
     if ( ! fdpcat ) {
       // requested cat is bad, send it to Other
       cat_is_clean = 0;
-      printf ( "PXML Fail %s: Cat request %s (parent %s) -> parent bad cat\n", app -> title_en ? app -> title_en : "no name?", catname, parentcatname ? parentcatname : "n/a" );
+      pnd_log ( pndn_warning, "PXML Fail %s: Cat request %s (parent %s) -> parent bad cat\n", app -> title_en ? app -> title_en : "no name?", catname, parentcatname ? parentcatname : "n/a" );
       // fix immediately so code doesn't explode
       parentcatname = NULL;
     } else {
@@ -390,12 +401,12 @@ unsigned char category_meta_push ( char *catname, char *parentcatname, pnd_disco
     if ( fdcat -> parent_cat == NULL ) {
       // but wait, catname is actually a parent cat...
       cat_is_clean = 0;
-      printf ( "PXML Fail %s: Cat request %s (parent %s) -> cat wants to be child, but FD says its a parent\n", app -> title_en ? app -> title_en : "no name?", catname, parentcatname ? parentcatname : "n/a" );
+      pnd_log ( pndn_warning, "PXML Fail %s: Cat request %s (parent %s) -> cat wants to be child, but FD says its a parent\n", app -> title_en ? app -> title_en : "no name?", catname, parentcatname ? parentcatname : "n/a" );
     }
     if ( fdpcat -> parent_cat ) {
       // but wait, parent cat is actually a subcat!
       cat_is_clean = 0;
-      printf ( "PXML Fail %s: Cat request %s (parent %s) -> parent cat, FD says its a child\n", app -> title_en ? app -> title_en : "no name?", catname, parentcatname ? parentcatname : "n/a" );
+      pnd_log ( pndn_warning, "PXML Fail %s: Cat request %s (parent %s) -> parent cat, FD says its a child\n", app -> title_en ? app -> title_en : "no name?", catname, parentcatname ? parentcatname : "n/a" );
     }
 
   } else {
@@ -404,7 +415,7 @@ unsigned char category_meta_push ( char *catname, char *parentcatname, pnd_disco
     if ( fdcat -> parent_cat ) {
       // but wait, cat actually has a parent!
       cat_is_clean = 0;
-      printf ( "PXML Fail %s: Cat request %s (parent %s) -> cat wants to be parent, FD says its a child\n", app -> title_en ? app -> title_en : "no name?", catname, parentcatname ? parentcatname : "n/a" );
+      pnd_log ( pndn_warning, "PXML Fail %s: Cat request %s (parent %s) -> cat wants to be parent, FD says its a child\n", app -> title_en ? app -> title_en : "no name?", catname, parentcatname ? parentcatname : "n/a" );
     }
 
   }
@@ -416,11 +427,11 @@ unsigned char category_meta_push ( char *catname, char *parentcatname, pnd_disco
     { 
       // child cat points to a different parent than requested parent!
       cat_is_clean = 0;
-      printf ( "PXML Fail %s: Cat request %s (parent %s) -> cat wants to be child of a cat which FD says is the wrong parent (1)\n", app -> title_en ? app -> title_en : "no name?", catname, parentcatname ? parentcatname : "n/a" );
+      pnd_log ( pndn_warning, "PXML Fail %s: Cat request %s (parent %s) -> cat wants to be child of a cat which FD says is the wrong parent (1)\n", app -> title_en ? app -> title_en : "no name?", catname, parentcatname ? parentcatname : "n/a" );
     } else if ( strcasecmp ( fdcat -> parent_cat, fdpcat -> cat ) != 0 ) {
       // child cat points to a different parent than requested parent!
       cat_is_clean = 0;
-      printf ( "PXML Fail %s: Cat request %s (parent %s) -> cat wants to be child of a cat which FD says is the wrong parent (2)\n", app -> title_en ? app -> title_en : "no name?", catname, parentcatname ? parentcatname : "n/a" );
+      pnd_log ( pndn_warning, "PXML Fail %s: Cat request %s (parent %s) -> cat wants to be child of a cat which FD says is the wrong parent (2)\n", app -> title_en ? app -> title_en : "no name?", catname, parentcatname ? parentcatname : "n/a" );
     }
   }
 
@@ -430,7 +441,7 @@ unsigned char category_meta_push ( char *catname, char *parentcatname, pnd_disco
     // set Other visibility
     visiblep = cat_is_visible ( g_conf, BADCATNAME );
     // fix cat request
-    fdcat = freedesktop_category_query ( BADCATNAME );
+    fdcat = freedesktop_category_query ( BADCATNAME, NULL );
     catname = fdcat -> cat;
     // nullify parent cat request (if any)
     fdpcat = NULL;
@@ -488,6 +499,11 @@ unsigned char category_meta_push ( char *catname, char *parentcatname, pnd_disco
   }
 #endif
 
+  // if this is a subcat push, and its requesting special 'no subcat', then just ditch it
+  if ( parentcatname && strcmp ( catname, "NoSubcategory" ) == 0 ) {
+    return ( 1 );
+  }
+
   // do we honour cat mapping at all?
   if ( pnd_conf_get_as_int_d ( g_conf, "categories.map_on", 0 ) ) {
 
@@ -512,18 +528,37 @@ unsigned char category_meta_push ( char *catname, char *parentcatname, pnd_disco
 
   // is app already in the target cat? (ie: its being pushed twice due to cat mapping or Other'ing or something..)
   if ( app ) {
-    if ( category_contains_app ( catname, app -> unique_id ) ) {
-      printf ( "App Fail: app (%s %s) is already in cat %s\n", app -> title_en ? app -> title_en : "no name?", app -> unique_id, catname );
+    if ( category_contains_app ( catname, parentcatname, app -> unique_id ) ) {
+      pnd_log ( pndn_warning, "App Fail: app (%s %s) is already in cat %s\n", app -> title_en ? app -> title_en : "no name?", app -> unique_id, catname );
       return ( 1 ); // success, already there!
     }
   }
 
+  // are we not putting apps into parent cat, when subcat is present? if so..
+  // if the cat we're looking at now is the main (or main alt-cat), and we also have a subcat, then ditch it.
+  // so, is the cat we're looking at right now the apps main (or main alt) cat?
+  if ( parentp ) {
+    // and does this app have sub/altsub cats?
+    if ( ( parentp == 1 && ( app -> main_category1 || app -> main_category2 ) ) ||
+        ( parentp == 2 && ( app -> alt_category1 || app -> alt_category2 ) )
+       )
+    {
+      // and we're only desiring the subcat version of the app?
+      if ( pnd_conf_get_as_int_d ( g_conf, "tabs.subcat_to_parent", 1 ) == 0 ) {
+       // create the parent category, since we need to be able to place a folder here maybe
+       category_push ( catname, parentcatname /* parent cat */, NULL /* app */, NULL /* ovrh */, NULL /* fspath */, visiblep );
+       // bail
+       return ( 1 );
+      } // subcat to parent?
+    } // app has subcat?
+  } // tab we're looking at now is the main tab?
+
   // not default, just do it
   category_push ( catname, parentcatname /* parent cat */, app, ovrh, NULL /* fspath */, visiblep );
 
   // if subcats as folders, then lets just make up a dummy app that pretends to be a folder,
   // and stuff it into the parent cat
-  if ( parentcatname && pnd_conf_get_as_int_d ( g_conf, "tabs.subcat_as_folders", 1 ) ) {
+  if ( parentcatname && pnd_conf_get_as_int_d ( g_conf, "tabs.subcat_as_folders", 1 ) && cat_is_visible ( g_conf, catname ) ) {
 
     // it is implicit that since we're talking parentcat, its already been created in a previous call
     // therefore, we need to..
@@ -533,7 +568,7 @@ unsigned char category_meta_push ( char *catname, char *parentcatname, pnd_disco
     // iv) create the dummy app folder by pushing the disco into the apprefs as normal
     // v) create a dummy '..' for going back up, in the child
 
-    mm_category_t *pcat = pnd_box_find_by_key ( m_categories, parentcatname );
+    mm_category_t *pcat = pnd_box_find_by_key ( m_categories, _normalize ( parentcatname, NULL ) );
 
     if ( ! pcat -> disco ) {
       pcat -> disco = pnd_box_new ( pcat -> catname );
@@ -549,7 +584,7 @@ unsigned char category_meta_push ( char *catname, char *parentcatname, pnd_disco
       disco = pnd_box_allocinsert ( pcat -> disco, catname, sizeof(pnd_disco_t) );
       if ( disco ) {
 
-       // create the subcat faux-disco entry, and register into parent cat
+       // create the subcat faux-disco entry, and register into parent cat .. if its visible
        char uid [ 30 ];
        sprintf ( uid, "%p", catname );
 
@@ -561,7 +596,7 @@ unsigned char category_meta_push ( char *catname, char *parentcatname, pnd_disco
        }
        disco -> object_flags = PND_DISCO_GENERATED;
        disco -> object_type = pnd_object_type_directory; // suggest to Grid that its a dir
-       disco -> object_path = strdup ( catname );
+       disco -> object_path = strdup ( _normalize ( catname, parentcatname ) );
 
        category_push ( parentcatname, NULL /* parent cat */, disco, 0 /*ovrh*/, NULL /* fspath */, 1 /* visible */ );
 
@@ -751,19 +786,33 @@ void category_publish ( unsigned int filter_mask, char *param ) {
     if ( filter_mask == CFALL ) {
       interested = 1;
     } else if ( filter_mask == CFBYNAME ) {
-      if ( strcasecmp ( iter -> catname, param ) == 0 ) {
+      char *foo = strchr ( param, '*' ) + 1;
+      if ( strncasecmp ( iter -> catname, param, strlen ( iter -> catname ) ) == 0 &&
+          iter -> parent_catname &&
+          strcasecmp ( iter -> parent_catname, foo ) == 0 )
+      {
        interested = 1;
       }
     } else if ( iter -> catflags == filter_mask ) {
       interested = 1;
     } // if
 
+    // desired tab?
     if ( interested ) {
-      // set us up the bomb; notice that we're just duplicating the pointers, not making
-      // any new data here; none of this should ever be free'd!
-      g_categories [ g_categorycount ] = iter;
-      g_categorycount++;
-    }
+
+      // lets only publish tabs that actually have an app in them .. just in case we've
+      // pruned out all the apps (sent them to Other or are suppressing apps in parent cats or
+      // something) at some point.
+      if ( iter -> fspath || iter -> refs ) {
+
+       // set us up the bomb; notice that we're just duplicating the pointers, not making
+       // any new data here; none of this should ever be free'd!
+       g_categories [ g_categorycount ] = iter;
+       g_categorycount++;
+
+      } // has apps?
+
+    } // interested?
 
     // next
     iter = pnd_box_get_next ( iter );
@@ -816,9 +865,9 @@ int category_index ( char *catname ) {
   return ( -1 );
 }
 
-unsigned char category_contains_app ( char *catname, char *unique_id ) {
+unsigned char category_contains_app ( char *catname, char *parentcatname, char *unique_id ) {
 
-  mm_category_t *c = pnd_box_find_by_key ( m_categories, catname );
+  mm_category_t *c = pnd_box_find_by_key ( m_categories, _normalize ( catname, parentcatname ) );
 
   if ( ! c ) {
     return ( 0 ); // wtf?