/// <summary>
        /// Determine whether the specified locale is a custom one the user is allowed to modify.
        /// </summary>
        /// <param name="localeId"></param>
        /// <returns></returns>
        public bool IsCustomLocale(string localeId)
        {
            ILgIcuResourceBundle rbroot = LgIcuResourceBundleClass.Create();

            try
            {
#if !__MonoCS__
                rbroot.Init(null, "en");
#else
                // TODO-Linux: fix Mono bug
                rbroot.Init("", "en");
#endif
                ILgIcuResourceBundle rbCustom = rbroot.get_GetSubsection("Custom");
                if (rbCustom != null)
                {
                    ILgIcuResourceBundle rbCustomLocales = rbCustom.get_GetSubsection("LocalesAdded");
                    Marshal.ReleaseComObject(rbCustom);
                    if (rbCustomLocales == null)
                    {
                        return(false);                        // Should never be.
                    }
                    while (rbCustomLocales.HasNext)
                    {
                        ILgIcuResourceBundle rbItem = rbCustomLocales.Next;
                        if (rbItem.String == localeId)
                        {
                            Marshal.ReleaseComObject(rbItem);
                            Marshal.ReleaseComObject(rbCustomLocales);
                            return(true);
                        }
                        Marshal.ReleaseComObject(rbItem);
                    }
                    Marshal.ReleaseComObject(rbCustomLocales);
                }
                // Now, compare the locale againt all known locales -- it may not exist at all yet!
                // If not, it is considered custom.
                ILgIcuLocaleEnumerator locEnum = LgIcuLocaleEnumeratorClass.Create();

                int cloc = locEnum.Count;
                for (int iloc = 0; iloc < cloc; iloc++)
                {
                    if (localeId == locEnum.get_Name(iloc))
                    {
                        Marshal.ReleaseComObject(locEnum);
                        return(false);
                    }
                }
                //Didn't find in either list...custom.
                Marshal.ReleaseComObject(locEnum);
                return(true);
            }
            finally
            {
                Marshal.ReleaseComObject(rbroot);
            }
        }
        /// <summary>
        /// Determine whether the specified locale is a custom one the user is allowed to modify.
        /// </summary>
        /// <param name="localeId"></param>
        /// <param name="rbroot"></param>
        /// <returns></returns>
        public bool IsCustomLocale(string localeId, ILgIcuResourceBundle rbroot)
        {
            ILgIcuResourceBundle rbCustom = rbroot.get_GetSubsection("Custom");

            if (rbCustom != null)
            {
                ILgIcuResourceBundle rbCustomLocales = rbCustom.get_GetSubsection("LocalesAdded");
                System.Runtime.InteropServices.Marshal.ReleaseComObject(rbCustom);
                if (rbCustomLocales == null)
                {
                    return(false);                      // Should never be.
                }
                while (rbCustomLocales.HasNext)
                {
                    ILgIcuResourceBundle rbItem = rbCustomLocales.Next;
                    if (rbItem.String == localeId)
                    {
                        System.Runtime.InteropServices.Marshal.ReleaseComObject(rbItem);
                        System.Runtime.InteropServices.Marshal.ReleaseComObject(rbCustomLocales);
                        return(true);
                    }
                    System.Runtime.InteropServices.Marshal.ReleaseComObject(rbItem);
                }
                System.Runtime.InteropServices.Marshal.ReleaseComObject(rbCustomLocales);
            }
            // Now, compare the locale againt all known locales -- it may not exist at all yet!
            // If not, it is considered custom.
            ILgIcuLocaleEnumerator locEnum = LgIcuLocaleEnumeratorClass.Create();

            int cloc = locEnum.Count;

            for (int iloc = 0; iloc < cloc; iloc++)
            {
                if (localeId == locEnum.get_Name(iloc))
                {
                    System.Runtime.InteropServices.Marshal.ReleaseComObject(locEnum);
                    return(false);
                }
            }
            //Didn't find in either list...custom.
            System.Runtime.InteropServices.Marshal.ReleaseComObject(locEnum);
            return(true);
        }
        /// ------------------------------------------------------------------------------------
        /// <summary>
        /// Raises the click event.
        /// </summary>
        /// <param name="e">The <see cref="T:System.EventArgs"/> instance containing the event data.</param>
        /// ------------------------------------------------------------------------------------
        protected override void OnClick(EventArgs e)
        {
            ILgIcuLocaleEnumerator locEnum = LgIcuLocaleEnumeratorClass.Create();
            var menu = components.ContextMenuStrip("contextMenu");

            // Create the various collections we use in the process of assembling
            // the menu.
            m_locales   = new Dictionary <string, List <LocaleMenuItemData> >();
            m_mainItems = new List <LocaleMenuItemData>();
            m_itemData  = new Dictionary <ToolStripMenuItem, LocaleMenuItemData>();

            int cloc = locEnum.Count;

            for (int iloc = 0; iloc < cloc; iloc++)
            {
                string langid      = locEnum.get_Language(iloc);
                string localeid    = locEnum.get_Name(iloc);
                string displayName = locEnum.get_DisplayName(iloc, m_displayLocaleId);
                List <LocaleMenuItemData> mainItems;
                if (!m_locales.TryGetValue(langid, out mainItems))
                {
                    mainItems         = new List <LocaleMenuItemData>();
                    m_locales[langid] = mainItems;
                }
                // Todo: second arg should be display name.
                var data = new LocaleMenuItemData(localeid, displayName);
                mainItems.Add(data);
            }

            // Generate the secondary items. For each key in m_locales,
            // 1. If there is just one item in the List and its id is equal to the key,
            //		then this language has only one locale,
            //		the unmodified one that appears in the main list.
            // 2. If there is more than one item and one of them has an id equal to the key,
            //		make a single item in main list. It is a copy of the item whose id is
            //		equal to the key, that is, the most basic locale for this language.
            //		It has the arraylist for mainItems.
            // 3. Otherwise, we have a list of locales for which there is no basic locale
            //		whose id is equal to the language id. In this case, we make an item
            //		for each thing in the List, whether many or just one.
            foreach (KeyValuePair <string, List <LocaleMenuItemData> > kvp in m_locales)
            {
                string langid = kvp.Key;
                List <LocaleMenuItemData> items       = kvp.Value;
                LocaleMenuItemData        lmdRootItem = items.FirstOrDefault(lmd => lmd.m_id == langid);
                // See if there is an item in the array list that matches the langid
                if (lmdRootItem == null)
                {
                    // case 3
                    foreach (LocaleMenuItemData lmd in items)
                    {
                        m_mainItems.Add(lmd);
                    }
                }
                else
                {
                    if (items.Count == 1)
                    {
                        // case 1
                        var lmdMenu = new LocaleMenuItemData(lmdRootItem.m_id, lmdRootItem.m_displayName);
                        m_mainItems.Add(lmdMenu);
                    }
                    else
                    {
                        // case 2
                        var lmdMenu = new LocaleMenuItemData(lmdRootItem.m_id, lmdRootItem.m_displayName)
                        {
                            m_subitems = items
                        };
                        m_mainItems.Add(lmdMenu);
                    }
                }
            }

            // Sort the items in each menu.
            m_mainItems.Sort();
            var NoneData = new LocaleMenuItemData(FwCoreDlgControls.kstid_None, FwCoreDlgControls.kstid_None);
            var NoneItem = new ToolStripMenuItem(NoneData.m_displayName, null, ItemClickHandler);

            menu.Items.Add(NoneItem);             // This goes strictly at the beginning, irrespective of sorting

            foreach (LocaleMenuItemData lmd in m_mainItems)
            {
                var mi = new ToolStripMenuItem(lmd.m_displayName, null, ItemClickHandler);
                menu.Items.Add(mi);
                m_itemData[mi] = lmd;
                if (lmd.m_subitems != null)
                {
                    mi.DropDownOpened += mi_Popup;
                    lmd.m_subitems.Sort();
                    // To make the system realize this item is a submenu, we have to
                    // add at least one item. To save time and space, we don't add the others
                    // until it pops up.
                    LocaleMenuItemData lmdSub = lmd.m_subitems[0];
                    var miSub = new ToolStripMenuItem(lmdSub.m_displayName, null, ItemClickHandler);
                    mi.DropDownItems.Add(miSub);
                    m_itemData[miSub] = lmdSub;

                    // Turns out popup events don't happen in a .NET submenu, only for the top-level
                    // menu. DavidO has a workaround that should soon be checked in. In the meantime,
                    // generate the submenu at once. This may actually be fast enough to keep permanently.
                    mi_Popup(mi, new EventArgs());
                }
            }

            if (MiscUtils.IsUnix)
            {
                menu.ShowWithOverflow(this, new Point(0, Height));
            }
            else
            {
                menu.Show(this, new Point(0, Height));
            }

            Marshal.ReleaseComObject(locEnum);
            base.OnClick(e);             // Review JohnT: is this useful or harmful or neither? MS recommends it.
        }