Provide support for a hierarchical config menu listing

- Shows all configs in a subdirectory grouped into a
  submenu entry. This hopefully provided a better UX when
  there are more than a few 10's of config files.

- Enabled only if number of configs is > 50 or if the
  option config_menu_view is set to 2.
  To force the current flat listing, set config_menu_view = 1.

TODO: Make config_menu_view user configurable.

Signed-off-by: Selva Nair <selva.nair@gmail.com>
pull/298/head
Selva Nair 7 years ago
parent 567efd1f45
commit 2d64cb5603

108
tray.c

@ -38,6 +38,7 @@
#include "openvpn-gui-res.h" #include "openvpn-gui-res.h"
#include "localization.h" #include "localization.h"
#include "misc.h" #include "misc.h"
#include "assert.h"
/* Popup Menus */ /* Popup Menus */
HMENU hMenu; HMENU hMenu;
@ -47,17 +48,35 @@ HMENU hMenuService;
NOTIFYICONDATA ni; NOTIFYICONDATA ni;
extern options_t o; extern options_t o;
#define USE_NESTED_CONFIG_MENU ((o.config_menu_view == CONFIG_VIEW_AUTO && o.num_configs > 50) \
|| (o.config_menu_view == CONFIG_VIEW_NESTED))
/* Create popup menus */ /* Create popup menus */
void void
CreatePopupMenus() CreatePopupMenus()
{ {
int i; int i;
/* We use groups[0].menu as the root menu, so,
* even if num_configs = 0, we want num_groups > 0.
* This is guaranteed as the root node is always defined.
*/
assert(o.num_groups > 0);
for (i = 0; i < o.num_configs; i++) for (i = 0; i < o.num_configs; i++)
{
hMenuConn[i] = CreatePopupMenu(); hMenuConn[i] = CreatePopupMenu();
}
for (i = 0; i < o.num_groups; i++)
{
if (!o.groups[i].active)
continue;
o.groups[i].menu = CreatePopupMenu();
o.groups[i].children = 0; /* we have to recount this when assigning menu position index */
}
hMenuService = CreatePopupMenu(); hMenuService = CreatePopupMenu();
hMenu = CreatePopupMenu(); hMenu = o.groups[0].menu; /* the first group menu is also the root menu */
if (o.num_configs == 1) { if (o.num_configs == 1) {
/* Create Main menu with actions */ /* Create Main menu with actions */
@ -91,13 +110,48 @@ CreatePopupMenus()
AppendMenu(hMenu, MF_STRING ,IDM_SETTINGS, LoadLocalizedString(IDS_MENU_SETTINGS)); AppendMenu(hMenu, MF_STRING ,IDM_SETTINGS, LoadLocalizedString(IDS_MENU_SETTINGS));
AppendMenu(hMenu, MF_STRING ,IDM_CLOSE, LoadLocalizedString(IDS_MENU_CLOSE)); AppendMenu(hMenu, MF_STRING ,IDM_CLOSE, LoadLocalizedString(IDS_MENU_CLOSE));
SetMenuStatus(&o.conn[0], o.conn[0].state); SetMenuStatusById(0, o.conn[0].state);
} }
else { else {
/* Create Main menu with all connections */
int i; int i;
/* construct the submenu tree first */
if (USE_NESTED_CONFIG_MENU)
{
/* i = 0 is the root menu and has no parent */
for (i = 1; i < o.num_groups; i++)
{
config_group_t *this = &o.groups[i];
config_group_t *parent = this->parent;
if (!this->active || !parent)
continue;
AppendMenu(parent->menu, MF_POPUP, (UINT_PTR) this->menu, this->name);
this->pos = parent->children++;
PrintDebug(L"Submenu %d named %s added to parent %s with position %d",
i, this->name, parent->name, this->pos);
}
}
/* add config file (connection) entries */
for (i = 0; i < o.num_configs; i++) for (i = 0; i < o.num_configs; i++)
AppendMenu(hMenu, MF_POPUP, (UINT_PTR) hMenuConn[i], o.conn[i].config_name); {
connection_t *c = &o.conn[i];
config_group_t *parent = &o.groups[0]; /* by default config is added to the root */
if (USE_NESTED_CONFIG_MENU)
{
if (c->group) /* should be always true, but in case... */
parent = c->group;
}
/* Add config to the current sub menu */
AppendMenu(parent->menu, MF_POPUP, (UINT_PTR) hMenuConn[i], c->config_name);
c->pos = parent->children++;
PrintDebug(L"Config %d named %s added to submenu %s with position %d",
i, c->config_name, parent->name, c->pos);
}
if (o.num_configs > 0) if (o.num_configs > 0)
AppendMenu(hMenu, MF_SEPARATOR, 0, 0); AppendMenu(hMenu, MF_SEPARATOR, 0, 0);
@ -134,7 +188,7 @@ CreatePopupMenus()
AppendMenu(hMenuConn[i], MF_STRING, IDM_PASSPHRASEMENU + i, LoadLocalizedString(IDS_MENU_PASSPHRASE)); AppendMenu(hMenuConn[i], MF_STRING, IDM_PASSPHRASEMENU + i, LoadLocalizedString(IDS_MENU_PASSPHRASE));
#endif #endif
SetMenuStatus(&o.conn[i], o.conn[i].state); SetMenuStatusById(i, o.conn[i].state);
} }
} }
@ -152,6 +206,9 @@ DestroyPopupMenus()
DestroyMenu(hMenuService); DestroyMenu(hMenuService);
DestroyMenu(hMenu); DestroyMenu(hMenu);
hMenuService = NULL;
hMenu = NULL;
} }
@ -348,6 +405,22 @@ ShowTrayBalloon(TCHAR *infotitle_msg, TCHAR *info_msg)
void void
SetMenuStatus(connection_t *c, conn_state_t state) SetMenuStatus(connection_t *c, conn_state_t state)
{ {
int i;
for (i = 0; i < o.num_configs; ++i)
{
if (c == &o.conn[i])
break;
}
SetMenuStatusById(i, state);
}
void
SetMenuStatusById(int i, conn_state_t state)
{
connection_t *c = &o.conn[i];
BOOL checked = (state == connected || state == disconnecting);
if (o.num_configs == 1) if (o.num_configs == 1)
{ {
if (state == disconnected) if (state == disconnected)
@ -378,15 +451,26 @@ SetMenuStatus(connection_t *c, conn_state_t state)
} }
else else
{ {
int i; config_group_t *parent = &o.groups[0];
for (i = 0; i < o.num_configs; ++i) int pos = c->pos;
if (USE_NESTED_CONFIG_MENU && c->group)
parent = c->group;
CheckMenuItem(parent->menu, pos, MF_BYPOSITION | (checked ? MF_CHECKED : MF_UNCHECKED));
PrintDebug(L"Setting state of config %s checked = %d, parent %s, pos %d",
c->config_name, checked, (parent->id == 0)? L"Main Menu" : L"SubMenu", pos);
if (checked) /* also check all parent groups */
{ {
if (c == &o.conn[i]) while (parent->parent)
break; {
pos = parent->pos;
parent = parent->parent;
CheckMenuItem(parent->menu, pos, MF_BYPOSITION | MF_CHECKED);
}
} }
BOOL checked = (state == connected || state == disconnecting);
CheckMenuItem(hMenu, i, MF_BYPOSITION | (checked ? MF_CHECKED : MF_UNCHECKED));
if (state == disconnected) if (state == disconnected)
{ {

@ -48,6 +48,7 @@ void OnDestroyTray(void);
void ShowTrayIcon(); void ShowTrayIcon();
void SetTrayIcon(conn_state_t); void SetTrayIcon(conn_state_t);
void SetMenuStatus(connection_t *, conn_state_t); void SetMenuStatus(connection_t *, conn_state_t);
void SetMenuStatusById(int, conn_state_t);
void SetServiceMenuStatus(); void SetServiceMenuStatus();
void ShowTrayBalloon(TCHAR *, TCHAR *); void ShowTrayBalloon(TCHAR *, TCHAR *);
void CheckAndSetTrayIcon(); void CheckAndSetTrayIcon();

Loading…
Cancel
Save