tor-commits
Threads by month
- ----- 2026 -----
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- 1 participants
- 215237 discussions
[tor/maint-0.2.2] Make ControlSocketsGroupWritable work with User.
by nickm@torproject.org 14 Jun '11
by nickm@torproject.org 14 Jun '11
14 Jun '11
commit 54d7d31cba84232b50fef4287951b2c4bfa746c2
Author: Jérémy Bobbio <lunar(a)debian.org>
Date: Tue Jun 14 12:18:32 2011 -0400
Make ControlSocketsGroupWritable work with User.
Original message from bug3393:
check_private_dir() to ensure that ControlSocketsGroupWritable is
safe to use. Unfortunately, check_private_dir() only checks against
the currently running user… which can be root until privileges are
dropped to the user and group configured by the User config option.
The attached patch fixes the issue by adding a new effective_user
argument to check_private_dir() and updating the callers. It might
not be the best way to fix the issue, but it did in my tests.
(Code by lunar; changelog by nickm)
---
src/common/util.c | 33 ++++++++++++++++++++++++++-------
src/common/util.h | 3 ++-
src/or/config.c | 6 ++++--
src/or/connection.c | 2 +-
src/or/geoip.c | 6 +++---
src/or/rendservice.c | 2 +-
src/or/rephist.c | 4 ++--
src/or/router.c | 4 ++--
8 files changed, 41 insertions(+), 19 deletions(-)
diff --git a/src/common/util.c b/src/common/util.c
index 6f323dd..36aa9cc 100644
--- a/src/common/util.c
+++ b/src/common/util.c
@@ -1677,15 +1677,20 @@ file_status(const char *fname)
* is group-readable, but in all cases we create the directory mode 0700.
* If CPD_CHECK_MODE_ONLY is set, then we don't alter the directory permissions
* if they are too permissive: we just return -1.
+ * When effective_user is not NULL, check permissions against the given user and
+ * its primary group.
*/
int
-check_private_dir(const char *dirname, cpd_check_t check)
+check_private_dir(const char *dirname, cpd_check_t check, const char *effective_user)
{
int r;
struct stat st;
char *f;
#ifndef MS_WINDOWS
int mask;
+ struct passwd *pw = NULL;
+ uid_t running_uid;
+ gid_t running_gid;
#endif
tor_assert(dirname);
@@ -1724,33 +1729,47 @@ check_private_dir(const char *dirname, cpd_check_t check)
return -1;
}
#ifndef MS_WINDOWS
- if (st.st_uid != getuid()) {
+ if (effective_user) {
+ /* Lookup the user and group information, if we have a problem, bail out. */
+ pw = getpwnam(effective_user);
+ if (pw == NULL) {
+ log_warn(LD_CONFIG, "Error setting configured user: %s not found", effective_user);
+ return -1;
+ }
+ running_uid = pw->pw_uid;
+ running_gid = pw->pw_gid;
+ } else {
+ running_uid = getuid();
+ running_gid = getgid();
+ }
+
+ if (st.st_uid != running_uid) {
struct passwd *pw = NULL;
char *process_ownername = NULL;
- pw = getpwuid(getuid());
+ pw = getpwuid(running_uid);
process_ownername = pw ? tor_strdup(pw->pw_name) : tor_strdup("<unknown>");
pw = getpwuid(st.st_uid);
log_warn(LD_FS, "%s is not owned by this user (%s, %d) but by "
"%s (%d). Perhaps you are running Tor as the wrong user?",
- dirname, process_ownername, (int)getuid(),
+ dirname, process_ownername, (int)running_uid,
pw ? pw->pw_name : "<unknown>", (int)st.st_uid);
tor_free(process_ownername);
return -1;
}
- if ((check & CPD_GROUP_OK) && st.st_gid != getgid()) {
+ if ((check & CPD_GROUP_OK) && st.st_gid != running_gid) {
struct group *gr;
char *process_groupname = NULL;
- gr = getgrgid(getgid());
+ gr = getgrgid(running_gid);
process_groupname = gr ? tor_strdup(gr->gr_name) : tor_strdup("<unknown>");
gr = getgrgid(st.st_gid);
log_warn(LD_FS, "%s is not owned by this group (%s, %d) but by group "
"%s (%d). Are you running Tor as the wrong user?",
- dirname, process_groupname, (int)getgid(),
+ dirname, process_groupname, (int)running_gid,
gr ? gr->gr_name : "<unknown>", (int)st.st_gid);
tor_free(process_groupname);
diff --git a/src/common/util.h b/src/common/util.h
index d657db6..b9db25c 100644
--- a/src/common/util.h
+++ b/src/common/util.h
@@ -292,7 +292,8 @@ typedef unsigned int cpd_check_t;
#define CPD_CHECK 2
#define CPD_GROUP_OK 4
#define CPD_CHECK_MODE_ONLY 8
-int check_private_dir(const char *dirname, cpd_check_t check);
+int check_private_dir(const char *dirname, cpd_check_t check,
+ const char *effective_user);
#define OPEN_FLAGS_REPLACE (O_WRONLY|O_CREAT|O_TRUNC)
#define OPEN_FLAGS_APPEND (O_WRONLY|O_CREAT|O_APPEND)
typedef struct open_file_t open_file_t;
diff --git a/src/or/config.c b/src/or/config.c
index 44cecf3..8ab23a3 100644
--- a/src/or/config.c
+++ b/src/or/config.c
@@ -1025,7 +1025,8 @@ options_act_reversible(or_options_t *old_options, char **msg)
/* Ensure data directory is private; create if possible. */
if (check_private_dir(options->DataDirectory,
- running_tor ? CPD_CREATE : CPD_CHECK)<0) {
+ running_tor ? CPD_CREATE : CPD_CHECK,
+ options->User)<0) {
tor_asprintf(msg,
"Couldn't access/create private data directory \"%s\"",
options->DataDirectory);
@@ -1038,7 +1039,8 @@ options_act_reversible(or_options_t *old_options, char **msg)
char *fn = tor_malloc(len);
tor_snprintf(fn, len, "%s"PATH_SEPARATOR"cached-status",
options->DataDirectory);
- if (check_private_dir(fn, running_tor ? CPD_CREATE : CPD_CHECK) < 0) {
+ if (check_private_dir(fn, running_tor ? CPD_CREATE : CPD_CHECK,
+ options->User) < 0) {
tor_asprintf(msg,
"Couldn't access/create private data directory \"%s\"", fn);
tor_free(fn);
diff --git a/src/or/connection.c b/src/or/connection.c
index 3f4ca1d..a9e3a74 100644
--- a/src/or/connection.c
+++ b/src/or/connection.c
@@ -867,7 +867,7 @@ check_location_for_unix_socket(or_options_t *options, const char *path)
if (options->ControlSocketsGroupWritable)
flags |= CPD_GROUP_OK;
- if (check_private_dir(p, flags) < 0) {
+ if (check_private_dir(p, flags, options->User) < 0) {
char *escpath, *escdir;
escpath = esc_for_log(path);
escdir = esc_for_log(p);
diff --git a/src/or/geoip.c b/src/or/geoip.c
index 5bb2410..c621ea8 100644
--- a/src/or/geoip.c
+++ b/src/or/geoip.c
@@ -970,7 +970,7 @@ geoip_dirreq_stats_write(time_t now)
geoip_remove_old_clients(start_of_dirreq_stats_interval);
statsdir = get_datadir_fname("stats");
- if (check_private_dir(statsdir, CPD_CREATE) < 0)
+ if (check_private_dir(statsdir, CPD_CREATE, get_options()->User) < 0)
goto done;
filename = get_datadir_fname2("stats", "dirreq-stats");
data_v2 = geoip_get_client_history(GEOIP_CLIENT_NETWORKSTATUS_V2);
@@ -1209,7 +1209,7 @@ geoip_bridge_stats_write(time_t now)
/* Write it to disk. */
statsdir = get_datadir_fname("stats");
- if (check_private_dir(statsdir, CPD_CREATE) < 0)
+ if (check_private_dir(statsdir, CPD_CREATE, get_options()->User) < 0)
goto done;
filename = get_datadir_fname2("stats", "bridge-stats");
@@ -1304,7 +1304,7 @@ geoip_entry_stats_write(time_t now)
geoip_remove_old_clients(start_of_entry_stats_interval);
statsdir = get_datadir_fname("stats");
- if (check_private_dir(statsdir, CPD_CREATE) < 0)
+ if (check_private_dir(statsdir, CPD_CREATE, get_options()->User) < 0)
goto done;
filename = get_datadir_fname2("stats", "entry-stats");
data = geoip_get_client_history(GEOIP_CLIENT_CONNECT);
diff --git a/src/or/rendservice.c b/src/or/rendservice.c
index a10e43f..d9a9364 100644
--- a/src/or/rendservice.c
+++ b/src/or/rendservice.c
@@ -569,7 +569,7 @@ rend_service_load_keys(void)
s->directory);
/* Check/create directory */
- if (check_private_dir(s->directory, CPD_CREATE) < 0)
+ if (check_private_dir(s->directory, CPD_CREATE, get_options()->User) < 0)
return -1;
/* Load key */
diff --git a/src/or/rephist.c b/src/or/rephist.c
index 54593a0..b7341f3 100644
--- a/src/or/rephist.c
+++ b/src/or/rephist.c
@@ -2307,7 +2307,7 @@ rep_hist_exit_stats_write(time_t now)
/* Try to write to disk. */
statsdir = get_datadir_fname("stats");
- if (check_private_dir(statsdir, CPD_CREATE) < 0) {
+ if (check_private_dir(statsdir, CPD_CREATE, get_options()->User) < 0) {
log_warn(LD_HIST, "Unable to create stats/ directory!");
goto done;
}
@@ -2497,7 +2497,7 @@ rep_hist_buffer_stats_write(time_t now)
smartlist_clear(circuits_for_buffer_stats);
/* write to file */
statsdir = get_datadir_fname("stats");
- if (check_private_dir(statsdir, CPD_CREATE) < 0)
+ if (check_private_dir(statsdir, CPD_CREATE, get_options()->User) < 0)
goto done;
filename = get_datadir_fname2("stats", "buffer-stats");
out = start_writing_to_stdio_file(filename, OPEN_FLAGS_APPEND,
diff --git a/src/or/router.c b/src/or/router.c
index 68e29bb..2165e6e 100644
--- a/src/or/router.c
+++ b/src/or/router.c
@@ -533,12 +533,12 @@ init_keys(void)
return 0;
}
/* Make sure DataDirectory exists, and is private. */
- if (check_private_dir(options->DataDirectory, CPD_CREATE)) {
+ if (check_private_dir(options->DataDirectory, CPD_CREATE, options->User)) {
return -1;
}
/* Check the key directory. */
keydir = get_datadir_fname("keys");
- if (check_private_dir(keydir, CPD_CREATE)) {
+ if (check_private_dir(keydir, CPD_CREATE, options->User)) {
tor_free(keydir);
return -1;
}
1
0
14 Jun '11
commit a5af27f67a0c07b190997f36ed829b6a05b83a91
Author: Damian Johnson <atagar(a)torproject.org>
Date: Mon Jun 13 19:46:57 2011 -0700
Toggling the INCLUDE_GUI flag back to being off
It isn't ready yet for users so toggling the gui back to being disabled.
---
src/starter.py | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/src/starter.py b/src/starter.py
index 50feceb..d2ac910 100644
--- a/src/starter.py
+++ b/src/starter.py
@@ -30,7 +30,7 @@ import util.uiTools
import TorCtl.TorCtl
import TorCtl.TorUtil
-INCLUDE_GUI = True
+INCLUDE_GUI = False
LOG_DUMP_PATH = os.path.expanduser("~/.arm/log")
DEFAULT_CONFIG = os.path.expanduser("~/.arm/armrc")
CONFIG = {"startup.controlPassword": None,
1
0
commit 2e7531e2ac0c36516f4a0b7a7169a988710e041d
Author: Kamran Riaz Khan <krkhan(a)inspirated.com>
Date: Tue Jun 14 01:17:07 2011 +0500
Updated graph widgets' names.
---
src/gui/arm.xml | 22 ++++++++++++++--------
src/starter.py | 2 +-
2 files changed, 15 insertions(+), 9 deletions(-)
diff --git a/src/gui/arm.xml b/src/gui/arm.xml
index 85f60d3..a511583 100644
--- a/src/gui/arm.xml
+++ b/src/gui/arm.xml
@@ -307,11 +307,11 @@
<object class="GtkHBox" id="hbox_graph">
<property name="visible">True</property>
<child>
- <object class="GtkVBox" id="vbox_graph_a">
+ <object class="GtkVBox" id="vbox_graph_primary">
<property name="visible">True</property>
<property name="orientation">vertical</property>
<child>
- <object class="GtkLabel" id="label_graph_a_top">
+ <object class="GtkLabel" id="label_graph_primary_top">
<property name="visible">True</property>
<property name="label" translatable="yes">Download (0.0 b/sec)</property>
</object>
@@ -322,15 +322,18 @@
</packing>
</child>
<child>
- <object class="GtkVBox" id="placeholder_graph_a">
+ <object class="GtkVBox" id="placeholder_graph_primary">
<property name="visible">True</property>
+ <child>
+ <placeholder/>
+ </child>
</object>
<packing>
<property name="position">1</property>
</packing>
</child>
<child>
- <object class="GtkLabel" id="label_graph_a_bottom">
+ <object class="GtkLabel" id="label_graph_primary_bottom">
<property name="visible">True</property>
<property name="label" translatable="yes">avg: 3.5 Kb/sec, total: 2.0 MB</property>
</object>
@@ -346,11 +349,11 @@
</packing>
</child>
<child>
- <object class="GtkVBox" id="vbox_graph_b">
+ <object class="GtkVBox" id="vbox_graph_secondary">
<property name="visible">True</property>
<property name="orientation">vertical</property>
<child>
- <object class="GtkLabel" id="label_graph_b_top">
+ <object class="GtkLabel" id="label_graph_secondary_top">
<property name="visible">True</property>
<property name="label" translatable="yes">Upload (0.0 b/sec)</property>
</object>
@@ -361,15 +364,18 @@
</packing>
</child>
<child>
- <object class="GtkVBox" id="placeholder_graph_b">
+ <object class="GtkVBox" id="placeholder_graph_secondary">
<property name="visible">True</property>
+ <child>
+ <placeholder/>
+ </child>
</object>
<packing>
<property name="position">1</property>
</packing>
</child>
<child>
- <object class="GtkLabel" id="label_graph_b_bottom">
+ <object class="GtkLabel" id="label_graph_secondary_bottom">
<property name="visible">True</property>
<property name="label" translatable="yes">avg: 3.5 Kb/sec, total: 2.0 MB</property>
</object>
diff --git a/src/starter.py b/src/starter.py
index d2ac910..50feceb 100644
--- a/src/starter.py
+++ b/src/starter.py
@@ -30,7 +30,7 @@ import util.uiTools
import TorCtl.TorCtl
import TorCtl.TorUtil
-INCLUDE_GUI = False
+INCLUDE_GUI = True
LOG_DUMP_PATH = os.path.expanduser("~/.arm/log")
DEFAULT_CONFIG = os.path.expanduser("~/.arm/armrc")
CONFIG = {"startup.controlPassword": None,
1
0
[arm/master] Use resizable panes for layout, added scrolled window for connections.
by atagar@torproject.org 14 Jun '11
by atagar@torproject.org 14 Jun '11
14 Jun '11
commit 39fe520fa85256c506c7f5eeb6dfd02bed787b05
Author: Kamran Riaz Khan <krkhan(a)inspirated.com>
Date: Tue Jun 14 01:29:13 2011 +0500
Use resizable panes for layout, added scrolled window for connections.
---
src/gui/arm.xml | 550 +++++++++++++++++++++++++++++--------------------------
1 files changed, 287 insertions(+), 263 deletions(-)
diff --git a/src/gui/arm.xml b/src/gui/arm.xml
index a511583..e58279b 100644
--- a/src/gui/arm.xml
+++ b/src/gui/arm.xml
@@ -282,358 +282,403 @@
</packing>
</child>
<child>
- <object class="GtkHBox" id="hbox_main">
+ <object class="GtkVPaned" id="vpaned_main">
<property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="orientation">vertical</property>
<child>
- <object class="GtkNotebook" id="notebook_main">
+ <object class="GtkHPaned" id="hpaned_main">
<property name="visible">True</property>
<property name="can_focus">True</property>
<child>
- <object class="GtkVBox" id="vbox_graph">
+ <object class="GtkNotebook" id="notebook_main">
<property name="visible">True</property>
- <property name="orientation">vertical</property>
- <child>
- <object class="GtkLabel" id="label_graph_top">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Limit: 40 Mb/s, Burst: 80 Mb/s</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">0</property>
- </packing>
- </child>
+ <property name="can_focus">True</property>
<child>
- <object class="GtkHBox" id="hbox_graph">
+ <object class="GtkVBox" id="vbox_graph">
<property name="visible">True</property>
+ <property name="orientation">vertical</property>
<child>
- <object class="GtkVBox" id="vbox_graph_primary">
+ <object class="GtkLabel" id="label_graph_top">
<property name="visible">True</property>
- <property name="orientation">vertical</property>
- <child>
- <object class="GtkLabel" id="label_graph_primary_top">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Download (0.0 b/sec)</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkVBox" id="placeholder_graph_primary">
- <property name="visible">True</property>
- <child>
- <placeholder/>
- </child>
- </object>
- <packing>
- <property name="position">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="label_graph_primary_bottom">
- <property name="visible">True</property>
- <property name="label" translatable="yes">avg: 3.5 Kb/sec, total: 2.0 MB</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">2</property>
- </packing>
- </child>
+ <property name="label" translatable="yes">Limit: 40 Mb/s, Burst: 80 Mb/s</property>
</object>
<packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
- <object class="GtkVBox" id="vbox_graph_secondary">
+ <object class="GtkHBox" id="hbox_graph">
<property name="visible">True</property>
- <property name="orientation">vertical</property>
<child>
- <object class="GtkLabel" id="label_graph_secondary_top">
+ <object class="GtkVBox" id="vbox_graph_primary">
<property name="visible">True</property>
- <property name="label" translatable="yes">Upload (0.0 b/sec)</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkLabel" id="label_graph_primary_top">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Download (0.0 b/sec)</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="placeholder_graph_primary">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_graph_primary_bottom">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">avg: 3.5 Kb/sec, total: 2.0 MB</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
</object>
<packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
- <object class="GtkVBox" id="placeholder_graph_secondary">
+ <object class="GtkVBox" id="vbox_graph_secondary">
<property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkLabel" id="label_graph_secondary_top">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Upload (0.0 b/sec)</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
<child>
- <placeholder/>
+ <object class="GtkVBox" id="placeholder_graph_secondary">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_graph_secondary_bottom">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">avg: 3.5 Kb/sec, total: 2.0 MB</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
</child>
</object>
<packing>
<property name="position">1</property>
</packing>
</child>
- <child>
- <object class="GtkLabel" id="label_graph_secondary_bottom">
- <property name="visible">True</property>
- <property name="label" translatable="yes">avg: 3.5 Kb/sec, total: 2.0 MB</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">2</property>
- </packing>
- </child>
</object>
<packing>
<property name="position">1</property>
</packing>
</child>
</object>
- <packing>
- <property name="position">1</property>
- </packing>
</child>
- </object>
- </child>
- <child type="tab">
- <object class="GtkLabel" id="label_notebook_graph">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Graphs</property>
- </object>
- <packing>
- <property name="tab_fill">False</property>
- </packing>
- </child>
- <child>
- <object class="GtkVBox" id="vbox_conn">
- <property name="visible">True</property>
- <property name="orientation">vertical</property>
- <child>
- <object class="GtkLabel" id="label_conn_top">
+ <child type="tab">
+ <object class="GtkLabel" id="label_notebook_graph">
<property name="visible">True</property>
- <property name="label" translatable="yes">2 Clients, 1 Control</property>
+ <property name="label" translatable="yes">Graphs</property>
</object>
<packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">0</property>
+ <property name="tab_fill">False</property>
</packing>
</child>
<child>
- <object class="GtkTreeView" id="treeview_conn">
+ <object class="GtkVBox" id="vbox_conn">
<property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="model">liststore_conn</property>
- <property name="headers_visible">False</property>
- <child>
- <object class="GtkTreeViewColumn" id="treeviewcolumn_conn_origin">
- <property name="title">column</property>
- <child>
- <object class="GtkCellRendererText" id="cellrenderertext_conn_origin"/>
- <attributes>
- <attribute name="foreground">4</attribute>
- <attribute name="markup">0</attribute>
- </attributes>
- </child>
- </object>
- </child>
- <child>
- <object class="GtkTreeViewColumn" id="treeviewcolumn_conn_dest">
- <property name="title">column</property>
- <child>
- <object class="GtkCellRendererText" id="cellrenderertext_conn_dest"/>
- <attributes>
- <attribute name="foreground">4</attribute>
- <attribute name="markup">1</attribute>
- </attributes>
- </child>
- </object>
- </child>
+ <property name="orientation">vertical</property>
<child>
- <object class="GtkTreeViewColumn" id="treeviewcolumn_conn_time">
- <property name="title">column</property>
- <child>
- <object class="GtkCellRendererText" id="cellrenderertext_conn_time"/>
- <attributes>
- <attribute name="foreground">4</attribute>
- <attribute name="markup">2</attribute>
- </attributes>
- </child>
+ <object class="GtkLabel" id="label_conn_top">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">2 Clients, 1 Control</property>
</object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
</child>
<child>
- <object class="GtkTreeViewColumn" id="treeviewcolumn_conn_type">
- <property name="title">column</property>
+ <object class="GtkScrolledWindow" id="scrolledwindow_conn">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">automatic</property>
+ <property name="vscrollbar_policy">automatic</property>
<child>
- <object class="GtkCellRendererText" id="cellrenderertext_conn_type"/>
- <attributes>
- <attribute name="foreground">4</attribute>
- <attribute name="markup">3</attribute>
- </attributes>
+ <object class="GtkTreeView" id="treeview_conn">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="model">liststore_conn</property>
+ <property name="headers_visible">False</property>
+ <property name="headers_clickable">False</property>
+ <property name="search_column">0</property>
+ <child>
+ <object class="GtkTreeViewColumn" id="treeviewcolumn_conn_origin">
+ <property name="title">column</property>
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderertext_conn_origin"/>
+ <attributes>
+ <attribute name="foreground">4</attribute>
+ <attribute name="markup">0</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn" id="treeviewcolumn_conn_dest">
+ <property name="title">column</property>
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderertext_conn_dest"/>
+ <attributes>
+ <attribute name="foreground">4</attribute>
+ <attribute name="markup">1</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn" id="treeviewcolumn_conn_time">
+ <property name="title">column</property>
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderertext_conn_time"/>
+ <attributes>
+ <attribute name="foreground">4</attribute>
+ <attribute name="markup">2</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn" id="treeviewcolumn_conn_type">
+ <property name="title">column</property>
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderertext_conn_type"/>
+ <attributes>
+ <attribute name="foreground">4</attribute>
+ <attribute name="markup">3</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ </object>
</child>
</object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
</child>
</object>
<packing>
<property name="position">1</property>
</packing>
</child>
- </object>
- <packing>
- <property name="position">1</property>
- </packing>
- </child>
- <child type="tab">
- <object class="GtkLabel" id="label_notebook_conn">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Connections</property>
- </object>
- <packing>
- <property name="position">1</property>
- <property name="tab_fill">False</property>
- </packing>
- </child>
- <child>
- <object class="GtkVBox" id="vbox_config">
- <property name="visible">True</property>
- <property name="orientation">vertical</property>
- <child>
- <object class="GtkLabel" id="label_config_top">
+ <child type="tab">
+ <object class="GtkLabel" id="label_notebook_conn">
<property name="visible">True</property>
- <property name="label" translatable="yes"><span foreground="#368918"><u>RelayBandwidthBurst</u> (General Option)
-<b>Value</b>: 0 B (default, DataSize, usage: N bytes|KB|MB|GB|TB)
-<b>Description</b>: Limit the maximum token bucket size (also known as
-the burst) for <i>relayed traffic</i> to the given number of bytes in
-each direction. (Default: 0) </span></property>
- <property name="use_markup">True</property>
+ <property name="label" translatable="yes">Connections</property>
</object>
<packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">0</property>
+ <property name="position">1</property>
+ <property name="tab_fill">False</property>
</packing>
</child>
<child>
- <object class="GtkScrolledWindow" id="scrolledwindow_config">
+ <object class="GtkVBox" id="vbox_config">
<property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="hscrollbar_policy">automatic</property>
- <property name="vscrollbar_policy">automatic</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkLabel" id="label_config_top">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes"><span foreground="#368918"><u>RelayBandwidthBurst</u> (General Option)
+<b>Value</b>: 0 B (default, DataSize, usage: N bytes|KB|MB|GB|TB)
+<b>Description</b>: Limit the maximum token bucket size (also known as
+the burst) for <i>relayed traffic</i> to the given number of bytes in
+each direction. (Default: 0) </span></property>
+ <property name="use_markup">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
<child>
- <object class="GtkTreeView" id="treeview_config">
+ <object class="GtkScrolledWindow" id="scrolledwindow_config">
<property name="visible">True</property>
<property name="can_focus">True</property>
- <property name="model">liststore_config</property>
- <property name="headers_visible">False</property>
- <property name="search_column">0</property>
+ <property name="hscrollbar_policy">automatic</property>
+ <property name="vscrollbar_policy">automatic</property>
<child>
- <object class="GtkTreeViewColumn" id="treeviewcolumn_key">
- <property name="title">column</property>
+ <object class="GtkTreeView" id="treeview_config">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="model">liststore_config</property>
+ <property name="headers_visible">False</property>
+ <property name="headers_clickable">False</property>
+ <property name="search_column">0</property>
<child>
- <object class="GtkCellRendererText" id="cellrenderertext_config_key"/>
- <attributes>
- <attribute name="foreground">3</attribute>
- <attribute name="markup">0</attribute>
- </attributes>
+ <object class="GtkTreeViewColumn" id="treeviewcolumn_key">
+ <property name="title">column</property>
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderertext_config_key"/>
+ <attributes>
+ <attribute name="foreground">3</attribute>
+ <attribute name="markup">0</attribute>
+ </attributes>
+ </child>
+ </object>
</child>
- </object>
- </child>
- <child>
- <object class="GtkTreeViewColumn" id="treeviewcolumn_value">
- <property name="title">column</property>
<child>
- <object class="GtkCellRendererText" id="cellrenderertext_config_value"/>
- <attributes>
- <attribute name="foreground">3</attribute>
- <attribute name="markup">1</attribute>
- </attributes>
+ <object class="GtkTreeViewColumn" id="treeviewcolumn_value">
+ <property name="title">column</property>
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderertext_config_value"/>
+ <attributes>
+ <attribute name="foreground">3</attribute>
+ <attribute name="markup">1</attribute>
+ </attributes>
+ </child>
+ </object>
</child>
- </object>
- </child>
- <child>
- <object class="GtkTreeViewColumn" id="treeviewcolumn_desc">
- <property name="title">column</property>
<child>
- <object class="GtkCellRendererText" id="cellrenderertext_config_desc"/>
- <attributes>
- <attribute name="foreground">3</attribute>
- <attribute name="markup">2</attribute>
- </attributes>
+ <object class="GtkTreeViewColumn" id="treeviewcolumn_desc">
+ <property name="title">column</property>
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderertext_config_desc"/>
+ <attributes>
+ <attribute name="foreground">3</attribute>
+ <attribute name="markup">2</attribute>
+ </attributes>
+ </child>
+ </object>
</child>
</object>
</child>
</object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
</child>
</object>
<packing>
- <property name="position">1</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="label_notebook_config">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Configuration</property>
+ </object>
+ <packing>
+ <property name="position">2</property>
+ <property name="tab_fill">False</property>
</packing>
</child>
</object>
<packing>
- <property name="position">2</property>
+ <property name="resize">False</property>
+ <property name="shrink">True</property>
</packing>
</child>
- <child type="tab">
- <object class="GtkLabel" id="label_notebook_config">
+ <child>
+ <object class="GtkScrolledWindow" id="scrolledwindow_sticky">
<property name="visible">True</property>
- <property name="label" translatable="yes">Configuration</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">automatic</property>
+ <property name="vscrollbar_policy">automatic</property>
+ <child>
+ <object class="GtkTreeView" id="treeview_sticky">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="model">liststore_sticky</property>
+ <property name="headers_visible">False</property>
+ <property name="headers_clickable">False</property>
+ <property name="search_column">0</property>
+ <child>
+ <object class="GtkTreeViewColumn" id="treeviewcolumn_sticky_key">
+ <property name="title">column</property>
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderertext_sticky_key"/>
+ <attributes>
+ <attribute name="markup">0</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn" id="treeviewcolumn_sticky_value">
+ <property name="title">column</property>
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderertext_sticky_value"/>
+ <attributes>
+ <attribute name="foreground">2</attribute>
+ <attribute name="markup">1</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
</object>
<packing>
- <property name="position">2</property>
- <property name="tab_fill">False</property>
+ <property name="resize">True</property>
+ <property name="shrink">True</property>
</packing>
</child>
</object>
<packing>
- <property name="position">0</property>
+ <property name="resize">False</property>
+ <property name="shrink">True</property>
</packing>
</child>
<child>
- <object class="GtkScrolledWindow" id="scrolledwindow_sticky">
+ <object class="GtkScrolledWindow" id="scrolledwindow_log">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hscrollbar_policy">automatic</property>
<property name="vscrollbar_policy">automatic</property>
<child>
- <object class="GtkTreeView" id="treeview_sticky">
+ <object class="GtkTextView" id="textview_log">
<property name="visible">True</property>
<property name="can_focus">True</property>
- <property name="model">liststore_sticky</property>
- <property name="headers_visible">False</property>
- <property name="headers_clickable">False</property>
- <property name="search_column">0</property>
- <child>
- <object class="GtkTreeViewColumn" id="treeviewcolumn_sticky_key">
- <property name="title">column</property>
- <child>
- <object class="GtkCellRendererText" id="cellrenderertext_sticky_key"/>
- <attributes>
- <attribute name="markup">0</attribute>
- </attributes>
- </child>
- </object>
- </child>
- <child>
- <object class="GtkTreeViewColumn" id="treeviewcolumn_sticky_value">
- <property name="title">column</property>
- <child>
- <object class="GtkCellRendererText" id="cellrenderertext_sticky_value"/>
- <attributes>
- <attribute name="foreground">2</attribute>
- <attribute name="markup">1</attribute>
- </attributes>
- </child>
- </object>
- </child>
+ <property name="buffer">textbuffer_log</property>
</object>
</child>
</object>
<packing>
- <property name="padding">5</property>
- <property name="position">1</property>
+ <property name="resize">True</property>
+ <property name="shrink">True</property>
</packing>
</child>
</object>
@@ -641,27 +686,6 @@ each direction. (Default: 0) </span></property>
<property name="position">1</property>
</packing>
</child>
- <child>
- <object class="GtkScrolledWindow" id="scrolledwindow_log">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="hscrollbar_policy">automatic</property>
- <property name="vscrollbar_policy">automatic</property>
- <child>
- <object class="GtkTextView" id="textview_log">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="buffer">textbuffer_log</property>
- </object>
- </child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="padding">5</property>
- <property name="position">2</property>
- </packing>
- </child>
</object>
</child>
</object>
1
0
[arm/master] Added minimum width/height requirements for paned childs.
by atagar@torproject.org 14 Jun '11
by atagar@torproject.org 14 Jun '11
14 Jun '11
commit a3c427e1203d056f7c647ed679bbc54ced47aba8
Author: Kamran Riaz Khan <krkhan(a)inspirated.com>
Date: Tue Jun 14 02:48:30 2011 +0500
Added minimum width/height requirements for paned childs.
---
src/gui/arm.xml | 15 +++++++++------
1 files changed, 9 insertions(+), 6 deletions(-)
diff --git a/src/gui/arm.xml b/src/gui/arm.xml
index e58279b..23230b6 100644
--- a/src/gui/arm.xml
+++ b/src/gui/arm.xml
@@ -288,10 +288,12 @@
<property name="orientation">vertical</property>
<child>
<object class="GtkHPaned" id="hpaned_main">
+ <property name="height_request">300</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<child>
<object class="GtkNotebook" id="notebook_main">
+ <property name="width_request">300</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<child>
@@ -607,8 +609,8 @@ each direction. (Default: 0) </span></property>
</child>
</object>
<packing>
- <property name="resize">False</property>
- <property name="shrink">True</property>
+ <property name="resize">True</property>
+ <property name="shrink">False</property>
</packing>
</child>
<child>
@@ -653,17 +655,18 @@ each direction. (Default: 0) </span></property>
</object>
<packing>
<property name="resize">True</property>
- <property name="shrink">True</property>
+ <property name="shrink">False</property>
</packing>
</child>
</object>
<packing>
- <property name="resize">False</property>
- <property name="shrink">True</property>
+ <property name="resize">True</property>
+ <property name="shrink">False</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow" id="scrolledwindow_log">
+ <property name="height_request">100</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hscrollbar_policy">automatic</property>
@@ -678,7 +681,7 @@ each direction. (Default: 0) </span></property>
</object>
<packing>
<property name="resize">True</property>
- <property name="shrink">True</property>
+ <property name="shrink">False</property>
</packing>
</child>
</object>
1
0
commit f874c839fdf7bee393492bd6b38a5e468b1b1a06
Author: Kamran Riaz Khan <krkhan(a)inspirated.com>
Date: Tue Jun 14 02:41:29 2011 +0500
Initial commit for bandwidth graphs.
---
src/gui/controller.py | 51 +++++++++++++++++++++++++++++-
src/gui/graphing/__init__.py | 6 +++
src/gui/graphing/bandwidthStats.py | 26 +++++++++++++++
src/gui/graphing/graphStats.py | 61 ++++++++++++++++++++++++++++++++++++
4 files changed, 143 insertions(+), 1 deletions(-)
diff --git a/src/gui/controller.py b/src/gui/controller.py
index 0e444d3..91b9a03 100644
--- a/src/gui/controller.py
+++ b/src/gui/controller.py
@@ -1,14 +1,36 @@
+import gobject
+import gtk
+
from util import torTools
+from gui.graphing import graphStats, bandwidthStats
-import gtk
+from cagraph.ca_graph import CaGraph
+from cagraph.axis.xaxis import CaGraphXAxis
+from cagraph.axis.yaxis import CaGraphYAxis
+from cagraph.ca_graph_grid import CaGraphGrid
+from cagraph.series.area import CaGraphSeriesArea
+
+gobject.threads_init()
class GuiController:
def __init__(self):
filename = 'src/gui/arm.xml'
+
self.builder = gtk.Builder()
self.builder.add_from_file(filename)
self.builder.connect_signals(self)
+ # for custom widgets not present in builder xml
+ self.widgets = {}
+
+ self._pack_graph_widget('primary')
+ self._pack_graph_widget('secondary')
+
+ self.bwStats = bandwidthStats.BandwidthStats(self.widgets)
+
+ gobject.timeout_add(1000, self.bwStats.draw_graph, 'primary')
+ gobject.timeout_add(1000, self.bwStats.draw_graph, 'secondary')
+
def run(self):
window = self.builder.get_object('window_main')
@@ -23,6 +45,33 @@ class GuiController:
def on_window_main_delete_event(self, widget, data=None):
gtk.main_quit()
+ def _pack_graph_widget(self, name):
+ graph = CaGraph()
+ placeholder = self.builder.get_object('placeholder_graph_%s' % name)
+ placeholder.pack_start(graph)
+
+ xaxis = CaGraphXAxis(graph)
+ yaxis = CaGraphYAxis(graph)
+
+ xaxis.min = 0
+ xaxis.max = graphStats.GRAPH_INTERVAL - 1
+ xaxis.axis_style.draw_labels = False
+
+ graph.axiss.append(xaxis)
+ graph.axiss.append(yaxis)
+
+ series = CaGraphSeriesArea(graph, 0, 1)
+
+ line_colors = {'primary' : (1.0, 0.0, 1.0, 1.0), 'secondary' : (0.0, 1.0, 0.0, 1.0)}
+ fill_colors = {'primary' : (1.0, 0.0, 1.0, 0.3), 'secondary' : (0.0, 1.0, 0.0, 0.3)}
+ series.style.line_color = line_colors[name]
+ series.style.fill_color = fill_colors[name]
+
+ graph.seriess.append(series)
+ graph.grid = CaGraphGrid(graph, 0, 1)
+
+ self.widgets['graph_%s' % name] = graph
+
def startGui():
controller = GuiController()
controller.run()
diff --git a/src/gui/graphing/__init__.py b/src/gui/graphing/__init__.py
new file mode 100644
index 0000000..acc8645
--- /dev/null
+++ b/src/gui/graphing/__init__.py
@@ -0,0 +1,6 @@
+"""
+Graphs.
+"""
+
+__all__ = ["graphStats", "bandwidthStats"]
+
diff --git a/src/gui/graphing/bandwidthStats.py b/src/gui/graphing/bandwidthStats.py
new file mode 100644
index 0000000..304574e
--- /dev/null
+++ b/src/gui/graphing/bandwidthStats.py
@@ -0,0 +1,26 @@
+"""
+Bandwidth monitors.
+"""
+
+import sys
+
+import gobject
+import gtk
+
+from TorCtl import TorCtl
+from gui.graphing import graphStats
+from util import torTools
+
+class BandwidthStats(graphStats.GraphStats):
+ def __init__(self, widgets):
+ graphStats.GraphStats.__init__(self, widgets)
+
+ conn = torTools.getConn()
+ if not conn.isAlive():
+ conn.init()
+ conn.setControllerEvents(["BW"])
+ conn.addEventListener(self)
+
+ def bandwidth_event(self, event):
+ self._processEvent(event.read / 1024.0, event.written / 1024.0)
+
diff --git a/src/gui/graphing/graphStats.py b/src/gui/graphing/graphStats.py
new file mode 100644
index 0000000..5037c39
--- /dev/null
+++ b/src/gui/graphing/graphStats.py
@@ -0,0 +1,61 @@
+"""
+Base class for implementing graphing functionality.
+"""
+
+import random
+import sys
+
+from collections import deque
+
+import gobject
+import gtk
+
+from TorCtl import TorCtl
+from util import torTools
+
+GRAPH_INTERVAL = 30
+
+class GraphStats(TorCtl.PostEventListener):
+ def __init__(self, widgets):
+ TorCtl.PostEventListener.__init__(self)
+
+ self.widgets = widgets
+
+ self.data = {
+ 'primary' : deque([0] * GRAPH_INTERVAL),
+ 'secondary' : deque([0] * GRAPH_INTERVAL)}
+
+ def get_graph_data(self, name):
+ packed_data = []
+
+ for (index, value) in enumerate(self.data[name]):
+ packed_data.append((index, value))
+
+ return packed_data
+
+ def is_graph_data_zero(self, name):
+ data = self.data[name]
+ return len(data) == map(int, data).count(0)
+
+ def draw_graph(self, name):
+ graph = self.widgets['graph_%s' % name]
+ data = self.get_graph_data(name)
+
+ if self.is_graph_data_zero(name):
+ graph.seriess[0].data = []
+ else:
+ graph.seriess[0].data = data
+
+ for (index, axis) in enumerate(graph.axiss):
+ if axis.type != 'xaxis':
+ graph.auto_set_yrange(index)
+
+ graph.queue_draw()
+ return True
+
+ def _processEvent(self, primary, secondary):
+ self.data['primary'].rotate(1)
+ self.data['primary'][0] = primary
+ self.data['secondary'].rotate(1)
+ self.data['secondary'][0] = secondary
+
1
0
13 Jun '11
commit 910dadd6eab5b2b3af3b655f52b861085f379b84
Author: Sebastian Hahn <sebastian(a)torproject.org>
Date: Sun Jun 12 13:55:32 2011 +0200
Ensure the release tarball contains all manpages
Thanks to Nick for the idea for the fix.
---
changes/bug3389 | 4 ++++
doc/Makefile.am | 18 ++++++++++--------
2 files changed, 14 insertions(+), 8 deletions(-)
diff --git a/changes/bug3389 b/changes/bug3389
new file mode 100644
index 0000000..2442f4f
--- /dev/null
+++ b/changes/bug3389
@@ -0,0 +1,4 @@
+ o Major bugfixes:
+ - Always ship the tor-fw-helper manpage in our release tarballs. Bugfix
+ on 0.2.3.1-alpha; fixes bug 3389. Reported by Stephen Walker.
+
diff --git a/doc/Makefile.am b/doc/Makefile.am
index 6cc0ea9..d8d9fbe 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -12,19 +12,21 @@
# part of the source distribution, so that people without asciidoc can
# just use the .1 and .html files.
+regular_mans = tor tor-gencert tor-resolve torify
+all_mans = $(regular_mans) tor-fw-helper
+
if USE_ASCIIDOC
if USE_FW_HELPER
-asciidoc_files = tor tor-gencert tor-resolve torify tor-fw-helper
+nodist_man_MANS = $(all_mans:=.1)
+doc_DATA = $(all_mans:=.html)
else
-asciidoc_files = tor tor-gencert tor-resolve torify
+nodist_man_MANS = $(regular_mans:=.1)
+doc_DATA = $(regular_mans:=.html)
endif
-html_in = $(asciidoc_files:=.html.in)
-man_in = $(asciidoc_files:=.1.in)
-txt_in = $(asciidoc_files:=.1.txt)
-nodist_man_MANS = $(asciidoc_files:=.1)
-doc_DATA = $(asciidoc_files:=.html)
+html_in = $(all_mans:=.html.in)
+man_in = $(all_mans:=.1.in)
+txt_in = $(all_mans:=.1.txt)
else
-asciidoc_files =
html_in =
man_in =
txt_in =
1
0
commit bf373956a64afa6126b0836329042775119a6114
Author: Damian Johnson <atagar(a)torproject.org>
Date: Sun Jun 12 17:39:19 2011 -0700
Binding handlers for the torrc submenu
---
README | 1 +
src/cli/menu/actions.py | 26 ++++++++++++++++++
src/cli/torrcPanel.py | 65 ++++++++++++++++++++++++++++++++++-------------
3 files changed, 74 insertions(+), 18 deletions(-)
diff --git a/README b/README
index 0f26163..44fabf1 100644
--- a/README
+++ b/README
@@ -180,6 +180,7 @@ Layout:
__init__.py
menu.py - provides an interactive menu
item.py - individual items within the menu
+ actions.py - handlers for menu selections
__init__.py
controller.py - main display loop, handling input and layout
diff --git a/src/cli/menu/actions.py b/src/cli/menu/actions.py
index 2072ead..53e5d1c 100644
--- a/src/cli/menu/actions.py
+++ b/src/cli/menu/actions.py
@@ -30,6 +30,8 @@ def makeMenu():
baseMenu.add(makeConnectionsMenu(pagePanel))
elif pagePanel.getName() == "configuration":
baseMenu.add(makeConfigurationMenu(pagePanel))
+ elif pagePanel.getName() == "torrc":
+ baseMenu.add(makeTorrcMenu(pagePanel))
return baseMenu
@@ -238,3 +240,27 @@ def makeConfigurationMenu(configPanel):
return configMenu
+def makeTorrcMenu(torrcPanel):
+ """
+ Submenu for the torrc panel, consisting of...
+ Reload
+ Show / Hide Comments
+ Show / Hide Line Numbers
+
+ Arguments:
+ torrcPanel - instance of the torrc panel
+ """
+
+ torrcMenu = cli.menu.item.Submenu("Torrc")
+ torrcMenu.add(cli.menu.item.MenuItem("Reload", torrcPanel.reloadTorrc))
+
+ if torrcPanel.stripComments: label, arg = "Show", True
+ else: label, arg = "Hide", False
+ torrcMenu.add(cli.menu.item.MenuItem("%s Comments" % label, functools.partial(torrcPanel.setCommentsVisible, arg)))
+
+ if torrcPanel.showLineNum: label, arg = "Hide", False
+ else: label, arg = "Show", True
+ torrcMenu.add(cli.menu.item.MenuItem("%s Line Numbers" % label, functools.partial(torrcPanel.setLineNumberVisible, arg)))
+
+ return torrcMenu
+
diff --git a/src/cli/torrcPanel.py b/src/cli/torrcPanel.py
index a12cc87..c273bf0 100644
--- a/src/cli/torrcPanel.py
+++ b/src/cli/torrcPanel.py
@@ -6,6 +6,7 @@ import math
import curses
import threading
+import cli.controller
import popups
from util import conf, enum, panel, torConfig, torTools, uiTools
@@ -59,6 +60,49 @@ class TorrcPanel(panel.Panel):
self.redraw(True)
except: pass
+ def setCommentsVisible(self, isVisible):
+ """
+ Sets if comments and blank lines are shown or stripped.
+
+ Arguments:
+ isVisible - displayed comments and blank lines if true, strips otherwise
+ """
+
+ self.stripComments = not isVisible
+ self._lastContentHeightArgs = None
+ self.redraw(True)
+
+ def setLineNumberVisible(self, isVisible):
+ """
+ Sets if line numbers are shown or hidden.
+
+ Arguments:
+ isVisible - displays line numbers if true, hides otherwise
+ """
+
+ self.showLineNum = isVisible
+ self._lastContentHeightArgs = None
+ self.redraw(True)
+
+ def reloadTorrc(self):
+ """
+ Reloads the torrc, displaying an indicator of success or failure.
+ """
+
+ cli.controller.getController().requestRedraw(True)
+
+ try:
+ torConfig.getTorrc().load()
+ self._lastContentHeightArgs = None
+ self.redraw(True)
+ resultMsg = "torrc reloaded"
+ except IOError:
+ resultMsg = "failed to reload torrc"
+
+ self._lastContentHeightArgs = None
+ self.redraw(True)
+ popups.showMsg(resultMsg, 1)
+
def handleKey(self, key):
self.valsLock.acquire()
isKeystrokeConsumed = True
@@ -70,26 +114,11 @@ class TorrcPanel(panel.Panel):
self.scroll = newScroll
self.redraw(True)
elif key == ord('n') or key == ord('N'):
- self.showLineNum = not self.showLineNum
- self._lastContentHeightArgs = None
- self.redraw(True)
+ self.setLineNumberVisible(not self.showLineNum)
elif key == ord('s') or key == ord('S'):
- self.stripComments = not self.stripComments
- self._lastContentHeightArgs = None
- self.redraw(True)
+ self.setCommentsVisible(self.stripComments)
elif key == ord('r') or key == ord('R'):
- # reloads torrc, providing a notice if successful or not
- try:
- torConfig.getTorrc().load()
- self._lastContentHeightArgs = None
- self.redraw(True)
- resultMsg = "torrc reloaded"
- except IOError:
- resultMsg = "failed to reload torrc"
-
- self._lastContentHeightArgs = None
- self.redraw(True)
- popups.showMsg(resultMsg, 1)
+ self.reloadTorrc()
else: isKeystrokeConsumed = False
self.valsLock.release()
1
0
commit 697468f2df30460fb381fac35a650cb4f7c412ae
Author: Damian Johnson <atagar(a)torproject.org>
Date: Sun Jun 12 18:28:53 2011 -0700
Binding handlers for the help submenu
---
src/cli/configPanel.py | 2 --
src/cli/connections/connPanel.py | 2 --
src/cli/graphing/graphPanel.py | 4 ++--
src/cli/logPanel.py | 4 ----
src/cli/menu/actions.py | 15 +++++++++++++++
src/cli/menu/item.py | 8 +++++++-
src/cli/popups.py | 25 +++++++++++++++++++++++++
src/cli/torrcPanel.py | 3 ---
8 files changed, 49 insertions(+), 14 deletions(-)
diff --git a/src/cli/configPanel.py b/src/cli/configPanel.py
index 4647286..fedf1f7 100644
--- a/src/cli/configPanel.py
+++ b/src/cli/configPanel.py
@@ -275,7 +275,6 @@ class ConfigPanel(panel.Panel):
"""
# set ordering for config options
- cli.controller.getController().requestRedraw(True)
titleLabel = "Config Option Ordering:"
options = [FIELD_ATTR[field][0] for field in Field.values()]
oldSelection = [FIELD_ATTR[field][0] for field in self.sortOrdering]
@@ -357,7 +356,6 @@ class ConfigPanel(panel.Panel):
"""
# display a popup for saving the current configuration
- cli.controller.getController().requestRedraw(True)
configLines = torConfig.getCustomOptions(True)
popup, width, height = popups.init(len(configLines) + 2)
if not popup: return
diff --git a/src/cli/connections/connPanel.py b/src/cli/connections/connPanel.py
index 9490ddc..edf5a14 100644
--- a/src/cli/connections/connPanel.py
+++ b/src/cli/connections/connPanel.py
@@ -6,7 +6,6 @@ import time
import curses
import threading
-import cli.controller
import cli.descriptorPopup
import cli.popups
@@ -157,7 +156,6 @@ class ConnectionPanel(panel.Panel, threading.Thread):
"""
# set ordering for connection options
- cli.controller.getController().requestRedraw(True)
titleLabel = "Connection Ordering:"
options = entries.SortAttr.values()
oldSelection = self._sortOrdering
diff --git a/src/cli/graphing/graphPanel.py b/src/cli/graphing/graphPanel.py
index 8c3adf7..b080871 100644
--- a/src/cli/graphing/graphPanel.py
+++ b/src/cli/graphing/graphPanel.py
@@ -307,8 +307,6 @@ class GraphPanel(panel.Panel):
panel.CURSES_LOCK.acquire()
try:
while True:
- control.requestRedraw(True)
-
msg = "press the down/up to resize the graph, and enter when done"
control.setMsg(msg, curses.A_BOLD, True)
curses.cbreak()
@@ -325,6 +323,8 @@ class GraphPanel(panel.Panel):
elif key == curses.KEY_UP:
self.setGraphHeight(self.graphHeight - 1)
elif uiTools.isSelectionKey(key): break
+
+ control.requestRedraw(True)
finally:
control.setMsg()
panel.CURSES_LOCK.release()
diff --git a/src/cli/logPanel.py b/src/cli/logPanel.py
index ef372ab..fc3bfc3 100644
--- a/src/cli/logPanel.py
+++ b/src/cli/logPanel.py
@@ -13,7 +13,6 @@ import threading
from TorCtl import TorCtl
import popups
-import cli.controller
from version import VERSION
from util import conf, log, panel, sysTools, torTools, uiTools
@@ -792,7 +791,6 @@ class LogPanel(panel.Panel, threading.Thread):
Prompts the user to add a new regex filter.
"""
- cli.controller.getController().requestRedraw(True)
regexInput = popups.inputPrompt("Regular expression: ")
if regexInput:
@@ -809,7 +807,6 @@ class LogPanel(panel.Panel, threading.Thread):
"""
# allow user to enter new types of events to log - unchanged if left blank
- cli.controller.getController().requestRedraw(True)
popup, width, height = popups.init(11, 80)
if popup:
@@ -837,7 +834,6 @@ class LogPanel(panel.Panel, threading.Thread):
Lets user enter a path to take a snapshot, canceling if left blank.
"""
- cli.controller.getController().requestRedraw(True)
pathInput = popups.inputPrompt("Path to save log snapshot: ")
if pathInput:
diff --git a/src/cli/menu/actions.py b/src/cli/menu/actions.py
index 53e5d1c..b8b59e1 100644
--- a/src/cli/menu/actions.py
+++ b/src/cli/menu/actions.py
@@ -4,6 +4,7 @@ Generates the menu for arm, binding options with their related actions.
import functools
+import cli.popups
import cli.controller
import cli.menu.item
import cli.graphing.graphPanel
@@ -33,6 +34,8 @@ def makeMenu():
elif pagePanel.getName() == "torrc":
baseMenu.add(makeTorrcMenu(pagePanel))
+ baseMenu.add(makeHelpMenu())
+
return baseMenu
def makeActionsMenu():
@@ -90,6 +93,18 @@ def makeViewMenu():
return viewMenu
+def makeHelpMenu():
+ """
+ Submenu consisting of...
+ Hotkeys
+ About
+ """
+
+ helpMenu = cli.menu.item.Submenu("Help")
+ helpMenu.add(cli.menu.item.MenuItem("Hotkeys", cli.popups.showHelpPopup))
+ helpMenu.add(cli.menu.item.MenuItem("About", cli.popups.showAboutPopup))
+ return helpMenu
+
def makeGraphMenu(graphPanel):
"""
Submenu for the graph panel, consisting of...
diff --git a/src/cli/menu/item.py b/src/cli/menu/item.py
index beaac9c..f46cdbb 100644
--- a/src/cli/menu/item.py
+++ b/src/cli/menu/item.py
@@ -2,6 +2,8 @@
Menu item, representing an option in the drop-down menu.
"""
+import cli.controller
+
class MenuItem():
"""
Option in a drop-down menu.
@@ -53,7 +55,11 @@ class MenuItem():
the menu and false otherwise.
"""
- if self._callback: self._callback()
+ if self._callback:
+ control = cli.controller.getController()
+ control.setMsg()
+ control.requestRedraw(True)
+ self._callback()
return True
def next(self):
diff --git a/src/cli/popups.py b/src/cli/popups.py
index 5f1eac2..7254f4a 100644
--- a/src/cli/popups.py
+++ b/src/cli/popups.py
@@ -4,6 +4,7 @@ Functions for displaying popups in the interface.
import curses
+import version
import cli.controller
from util import panel, uiTools
@@ -155,6 +156,30 @@ def showHelpPopup():
return exitKey
else: return None
+def showAboutPopup():
+ """
+ Presents a popup with author and version information.
+ """
+
+ popup, _, height = init(9, 80)
+ if not popup: return
+
+ try:
+ control = cli.controller.getController()
+
+ popup.win.box()
+ popup.addstr(0, 0, "About:", curses.A_STANDOUT)
+ popup.addstr(1, 2, "arm, version %s (released %s)" % (version.VERSION, version.LAST_MODIFIED), curses.A_BOLD)
+ popup.addstr(2, 4, "Written by Damian Johnson (atagar1(a)gmail.com)")
+ popup.addstr(3, 4, "Project page: www.atagar.com/arm")
+ popup.addstr(5, 2, "Released under the GPL v3 (http://www.gnu.org/licenses/gpl.html)")
+ popup.addstr(7, 2, "Press any key...")
+ popup.win.refresh()
+
+ curses.cbreak()
+ control.getScreen().getch()
+ finally: finalize()
+
def showSortDialog(title, options, oldSelection, optionColors):
"""
Displays a sorting dialog of the form:
diff --git a/src/cli/torrcPanel.py b/src/cli/torrcPanel.py
index c273bf0..f651785 100644
--- a/src/cli/torrcPanel.py
+++ b/src/cli/torrcPanel.py
@@ -6,7 +6,6 @@ import math
import curses
import threading
-import cli.controller
import popups
from util import conf, enum, panel, torConfig, torTools, uiTools
@@ -89,8 +88,6 @@ class TorrcPanel(panel.Panel):
Reloads the torrc, displaying an indicator of success or failure.
"""
- cli.controller.getController().requestRedraw(True)
-
try:
torConfig.getTorrc().load()
self._lastContentHeightArgs = None
1
0
13 Jun '11
commit ee2589f311dee651c0c8d47705ebb5cb07c95a23
Author: Damian Johnson <atagar(a)torproject.org>
Date: Sun Jun 12 18:30:25 2011 -0700
Dropping alternative menu implementation
The other menus are complete now to dropping Kamran's implementation.
---
src/cli/controller.py | 11 -
src/cli/menu/menu.py | 3 +
src/cli/menu_alt/__init__.py | 6 -
src/cli/menu_alt/menu.py | 439 ------------------------------------------
src/cli/menu_alt/menuItem.py | 41 ----
5 files changed, 3 insertions(+), 497 deletions(-)
diff --git a/src/cli/controller.py b/src/cli/controller.py
index 6158ade..b019f8e 100644
--- a/src/cli/controller.py
+++ b/src/cli/controller.py
@@ -8,7 +8,6 @@ import curses
import threading
import cli.menu.menu
-import cli.menu_alt.menu
import cli.popups
import cli.headerPanel
import cli.logPanel
@@ -527,8 +526,6 @@ def drawTorMonitor(stdscr, startTime):
overrideKey = None # uses this rather than waiting on user input
isUnresponsive = False # flag for heartbeat responsiveness check
- menuKeys = []
-
while not control.isDone():
displayPanels = control.getDisplayPanels()
isUnresponsive = heartbeatCheck(isUnresponsive)
@@ -563,14 +560,6 @@ def drawTorMonitor(stdscr, startTime):
control.prevPage()
elif key == ord('p') or key == ord('P'):
control.setPaused(not control.isPaused())
- elif key == ord('n') or key == ord('N'):
- menu = cli.menu_alt.menu.Menu()
- menuKeys = menu.showMenu(keys=menuKeys)
- if menuKeys != []:
- for key in (ord('n'), ord('q'), ord('x')):
- if key in menuKeys:
- menuKeys.remove(key)
- overrideKey = key
elif key == ord('m') or key == ord('M'):
cli.menu.menu.showMenu()
elif key == ord('q') or key == ord('Q'):
diff --git a/src/cli/menu/menu.py b/src/cli/menu/menu.py
index b411a9c..1dbbbd0 100644
--- a/src/cli/menu/menu.py
+++ b/src/cli/menu/menu.py
@@ -1,3 +1,6 @@
+"""
+Display logic for presenting the menu.
+"""
import curses
diff --git a/src/cli/menu_alt/__init__.py b/src/cli/menu_alt/__init__.py
deleted file mode 100644
index 6d7b6b7..0000000
--- a/src/cli/menu_alt/__init__.py
+++ /dev/null
@@ -1,6 +0,0 @@
-"""
-Resources for displaying the menu.
-"""
-
-__all__ = ["menuItem", "menu"]
-
diff --git a/src/cli/menu_alt/menu.py b/src/cli/menu_alt/menu.py
deleted file mode 100644
index 7e10366..0000000
--- a/src/cli/menu_alt/menu.py
+++ /dev/null
@@ -1,439 +0,0 @@
-"""
-A drop-down menu for sending actions to panels.
-"""
-
-import curses
-
-import cli.controller
-import cli.menu_alt.menuItem as menuItem
-import cli.popups
-
-from cli.graphing.graphPanel import Bounds as GraphBounds
-from util import log, panel, uiTools
-
-PARENTLEVEL, TOPLEVEL = (-1, 0)
-
-class Menu():
- """Displays a popup menu and sends keys to appropriate panels"""
-
- def __init__(self, item=None):
- DEFAULT_ROOT = menuItem.MenuItem(label="Root", children=(
- menuItem.MenuItem(label="File", children=(
- menuItem.MenuItem(label="Exit",
- callback=lambda item: self._callbackReturnKey(ord('q'))),)),
- menuItem.MenuItem(label="Logs", children=(
- menuItem.MenuItem(label="Events",
- callback=lambda item: self._callbackPressKey('log', ord('e'))),
- menuItem.MenuItem(label="Clear",
- callback=lambda item: self._callbackPressKey('log', ord('c'))),
- menuItem.MenuItem(label="Save",
- callback=lambda item: self._callbackPressKey('log', ord('a'))),
- menuItem.MenuItem(label="Filter",
- callback=lambda item: self._callbackPressKey('log', ord('f'))),
- menuItem.MenuItem(label="Duplicates", children=(
- menuItem.MenuItem(label="Hidden",
- callback=lambda item: self._callbackSet('log', 'showDuplicates', False, ord('u')),
- enabled=lambda: self._getItemEnabled('log', 'showDuplicates', False)),
- menuItem.MenuItem(label="Visible",
- callback=lambda item: self._callbackSet('log', 'showDuplicates', True, ord('u')),
- enabled=lambda: self._getItemEnabled('log', 'showDuplicates', True)),
- )))),
- menuItem.MenuItem(label="View", children=(
- menuItem.MenuItem(label="Graph",
- callback=lambda item: self._callbackView('graph')),
- menuItem.MenuItem(label="Connections",
- callback=lambda item: self._callbackView('conn')),
- menuItem.MenuItem(label="Configuration",
- callback=lambda item: self._callbackView('configState')),
- menuItem.MenuItem(label="Configuration File",
- callback=lambda item: self._callbackView('configFile')),)),
- menuItem.MenuItem(label="Graph", children=(
- menuItem.MenuItem(label="Stats",
- callback=lambda item: self._callbackPressKey('graph', ord('s'))),
- menuItem.MenuItem(label="Size", children=(
- menuItem.MenuItem(label="Increase",
- callback=lambda item: self._callbackPressKey('graph', ord('m'))),
- menuItem.MenuItem(label="Decrease",
- callback=lambda item: self._callbackPressKey('graph', ord('n'))),
- )),
- menuItem.MenuItem(label="Update Interval",
- callback=lambda item: self._callbackPressKey('graph', ord('i'))),
- menuItem.MenuItem(label="Bounds", children=(
- menuItem.MenuItem(label="Local Max",
- callback=lambda item: self._callbackSet('graph', 'bounds', GraphBounds.LOCAL_MAX, ord('b')),
- enabled=lambda: self._getItemEnabled('graph', 'bounds', GraphBounds.LOCAL_MAX)),
- menuItem.MenuItem(label="Global Max",
- callback=lambda item: self._callbackSet('graph', 'bounds', GraphBounds.GLOBAL_MAX, ord('b')),
- enabled=lambda: self._getItemEnabled('graph', 'bounds', GraphBounds.GLOBAL_MAX)),
- menuItem.MenuItem(label="Tight",
- callback=lambda item: self._callbackSet('graph', 'bounds', GraphBounds.TIGHT, ord('b')),
- enabled=lambda: self._getItemEnabled('graph', 'bounds', GraphBounds.TIGHT)),
- )),)),
- menuItem.MenuItem(label="Connections", children=(
- menuItem.MenuItem(label="Identity",
- callback=lambda item: self._callbackPressKey('conn', ord('l'))),
- menuItem.MenuItem(label="Resolver",
- callback=lambda item: self._callbackPressKey('conn', ord('u'))),
- menuItem.MenuItem(label="Sort Order",
- callback=lambda item: self._callbackPressKey('conn', ord('s'))),
- )),
- menuItem.MenuItem(label="Configuration" , children=(
- menuItem.MenuItem(label="Comments", children=(
- menuItem.MenuItem(label="Hidden",
- callback=lambda item: self._callbackSet('configFile', 'stripComments', True, ord('s')),
- enabled=lambda: self._getItemEnabled('configFile', 'stripComments', True)),
- menuItem.MenuItem(label="Visible",
- callback=lambda item: self._callbackSet('configFile', 'stripComments', False, ord('s')),
- enabled=lambda: self._getItemEnabled('configFile', 'stripComments', False)),
- )),
- menuItem.MenuItem(label="Reload",
- callback=lambda item: self._callbackPressKey('configFile', ord('r'))),
- menuItem.MenuItem(label="Reset Tor",
- callback=lambda item: self._callbackReturnKey(ord('x'))),))
- ))
-
- self._first = [0]
- self._selection = [0]
-
- if item and item.isParent():
- self._rootItem = item
- else:
- self._rootItem = DEFAULT_ROOT
-
- def showMenu(self, keys=[]):
- keys.reverse()
- returnkeys = []
-
- popup, width, height = cli.popups.init(height=3)
- if popup:
- try:
- while True:
- popup.win.erase()
- popup.win.box()
-
- self._drawTopLevel(popup, width, height)
-
- popup.win.refresh()
-
- control = cli.controller.getController()
-
- if keys == []:
- key = control.getScreen().getch()
- else:
- key = keys.pop()
-
- if key == curses.KEY_RIGHT:
- self._moveTopLevelRight(width)
- elif key == curses.KEY_LEFT:
- self._moveTopLevelLeft(width)
- elif key == curses.KEY_DOWN:
- cascaded, returnkeys = self._cascadeNLevel()
- break
- elif key == 27:
- break
- elif uiTools.isSelectionKey(key):
- self._handleEvent()
- break
-
- finally:
- cli.popups.finalize()
-
- return returnkeys
-
- def _appendLevel(self):
- self._first.append(0)
- self._selection.append(0)
-
- def _removeLevel(self):
- self._first.pop()
- self._selection.pop()
-
- def _getCurrentTopLevelItem(self):
- index = self._first[TOPLEVEL] + self._selection[TOPLEVEL]
- return self._rootItem.getChildren()[index]
-
- def _getCurrentItem(self, level=0):
- item = self._rootItem
- if level == 0:
- sums = [sum(values) for values in zip(self._first, self._selection)]
- else:
- sums = [sum(values) for values in zip(self._first[:level], self._selection[:level])]
-
- for index in sums:
- if item.isParent():
- item = item.getChildren()[index]
- else:
- break
-
- return item
-
- def _calculateTopLevelWidths(self, width=0):
- labels = [menuItem.getLabel() for menuItem in self._rootItem.getChildren()]
-
- # width per label is set according to the longest label
- labelwidth = max(map(len, labels)) + 2
-
- # total number of labels that can be printed in supplied width
- printable = min(width / labelwidth - 1, self._rootItem.getChildrenCount())
-
- return (labelwidth, printable)
-
- def _calculateNLevelWidths(self, level=0):
- parent = self._getCurrentItem(level)
-
- if parent.isLeaf():
- return 0
-
- labels = [menuItem.getLabel() for menuItem in parent.getChildren()]
-
- labelwidth = max(map(len, labels))
-
- return labelwidth
-
- def _calculateNLevelHeights(self, height=0, level=0):
- control = cli.controller.getController()
- height, _ = control.getScreen().getmaxyx()
- topSize = sum(stickyPanel.getHeight() for stickyPanel in control.getStickyPanels())
- height = height - topSize
-
- parent = self._getCurrentItem(level)
-
- if parent.isLeaf():
- return 0
-
- printable = min(height - 4, parent.getChildrenCount())
-
- return printable if printable else parent.getChildrenCount()
-
- def _moveTopLevelRight(self, width):
- _, printable = self._calculateTopLevelWidths(width)
-
- if self._selection[TOPLEVEL] < printable - 1:
- self._selection[TOPLEVEL] = self._selection[TOPLEVEL] + 1
- else:
- self._selection[TOPLEVEL] = 0
- if printable < self._rootItem.getChildrenCount():
- self._first[TOPLEVEL] = (self._first[TOPLEVEL] + printable) % self._rootItem.getChildrenCount()
-
- if self._first[TOPLEVEL] + self._selection[TOPLEVEL] == self._rootItem.getChildrenCount():
- self._first[TOPLEVEL] = 0
- self._selection[TOPLEVEL] = 0
-
- def _moveTopLevelLeft(self, width):
- _, printable = self._calculateTopLevelWidths(width)
-
- if self._selection[TOPLEVEL] > 0:
- self._selection[TOPLEVEL] = self._selection[TOPLEVEL] - 1
- else:
- if self._first[TOPLEVEL] == 0:
- self._first[TOPLEVEL] = ((self._rootItem.getChildrenCount() / printable) * printable) % self._rootItem.getChildrenCount()
- else:
- self._first[TOPLEVEL] = abs(self._first[TOPLEVEL] - printable) % self._rootItem.getChildrenCount()
- self._selection[TOPLEVEL] = self._rootItem.getChildrenCount() - self._first[TOPLEVEL] - 1
-
- if self._selection[TOPLEVEL] > printable:
- self._selection[TOPLEVEL] = printable - 1
-
- def _drawTopLevel(self, popup, width, height):
- labelwidth, printable = self._calculateTopLevelWidths(width)
- children = self._rootItem.getChildren()[self._first[TOPLEVEL]:self._first[TOPLEVEL] + printable]
-
- top = 1
- left = 1
- for (index, item) in enumerate(children):
- labelformat = curses.A_STANDOUT if index == self._selection[TOPLEVEL] else curses.A_NORMAL
-
- popup.addch(top, left, curses.ACS_VLINE)
- left = left + 1
- popup.addstr(top, left, item.getLabel().center(labelwidth), labelformat)
- left = left + labelwidth
-
- popup.addch(top, left, curses.ACS_VLINE)
- left = left + 1
-
- def _cascadeNLevel(self):
- parent = self._getCurrentItem()
-
- if parent.isLeaf():
- return (False, [])
-
- self._appendLevel()
-
- labelwidth = self._calculateNLevelWidths(level=PARENTLEVEL)
- printable = self._calculateNLevelHeights(level=PARENTLEVEL)
-
- toplabelwidth, _ = self._calculateTopLevelWidths()
- left = (toplabelwidth + 2) * self._selection[TOPLEVEL]
-
- popup, width, height = cli.popups.init(height=printable+2, width=labelwidth+2, top=2, left=left)
-
- while self._getCurrentItem().isEnabled() == False:
- self._moveNLevelDown(height)
-
- if popup.win:
- returnkeys = []
- try:
- while True:
- popup.win.erase()
- popup.win.box()
-
- self._drawNLevel(popup, width, height)
-
- popup.win.refresh()
-
- control = cli.controller.getController()
- key = control.getScreen().getch()
-
- if key == curses.KEY_DOWN:
- self._moveNLevelDown(height)
- elif key == curses.KEY_UP:
- self._moveNLevelUp(height)
- elif key == curses.KEY_RIGHT:
- cascaded, returnkeys = self._cascadeNLevel()
- if cascaded == False:
- index = self._first[TOPLEVEL] + self._selection[TOPLEVEL] + 1
- returnkeys.append(ord('n'))
- for i in range(index):
- returnkeys.append(curses.KEY_RIGHT)
- returnkeys.append(curses.KEY_DOWN)
- break
- elif key == curses.KEY_LEFT:
- index = self._first[TOPLEVEL] + self._selection[TOPLEVEL] - 1
- index = index % self._rootItem.getChildrenCount()
- returnkeys.append(ord('n'))
- for i in range(index):
- returnkeys.append(curses.KEY_RIGHT)
- returnkeys.append(curses.KEY_DOWN)
- break
- elif key == 27:
- self._removeLevel()
- break
- elif uiTools.isSelectionKey(key):
- returnkey = self._handleEvent()
- if returnkey:
- returnkeys.append(returnkey)
- self._removeLevel()
- break
-
- finally:
- cli.popups.finalize()
-
- return (True, returnkeys)
-
- return (False, [])
-
- def _drawNLevel(self, popup, width, height):
- printable = self._calculateNLevelHeights(level=PARENTLEVEL)
- parent = self._getCurrentItem(level=PARENTLEVEL)
- children = parent.getChildren()[self._first[PARENTLEVEL]:self._first[PARENTLEVEL] + printable]
-
- top = 1
- left = 1
- for (index, item) in enumerate(children):
- labelformat = curses.A_STANDOUT if index == self._selection[PARENTLEVEL] else curses.A_NORMAL
-
- if not item.isEnabled():
- labelformat = labelformat | uiTools.getColor('yellow')
-
- popup.addstr(top, left, item.getLabel(), labelformat)
- top = top + 1
-
- def _moveNLevelDown(self, height):
- printable = self._calculateNLevelHeights(level=PARENTLEVEL)
- parent = self._getCurrentItem(level=PARENTLEVEL)
-
- if self._selection[PARENTLEVEL] < printable - 1:
- self._selection[PARENTLEVEL] = self._selection[PARENTLEVEL] + 1
- else:
- self._selection[PARENTLEVEL] = 0
- if printable < parent.getChildrenCount():
- self._first[PARENTLEVEL] = (self._first[PARENTLEVEL] + printable) % parent.getChildrenCount()
-
- if self._first[PARENTLEVEL] + self._selection[PARENTLEVEL] == parent.getChildrenCount():
- self._first[PARENTLEVEL] = 0
- self._selection[PARENTLEVEL] = 0
-
- while self._getCurrentItem().isEnabled() == False:
- self._moveNLevelDown(height)
-
- def _moveNLevelUp(self, height):
- printable = self._calculateNLevelHeights(level=PARENTLEVEL)
- parent = self._getCurrentItem(level=PARENTLEVEL)
-
- if self._selection[PARENTLEVEL] > 0:
- self._selection[PARENTLEVEL] = self._selection[PARENTLEVEL] - 1
- else:
- if self._first[PARENTLEVEL] == 0:
- self._first[PARENTLEVEL] = ((parent.getChildrenCount() / printable) * printable) % parent.getChildrenCount()
- else:
- self._first[PARENTLEVEL] = abs(self._first[PARENTLEVEL] - printable) % parent.getChildrenCount()
- self._selection[PARENTLEVEL] = parent.getChildrenCount() - self._first[PARENTLEVEL] - 1
-
- if self._selection[PARENTLEVEL] > printable:
- self._selection[PARENTLEVEL] = printable - 1
-
- while self._getCurrentItem().isEnabled() == False:
- self._moveNLevelUp(height)
-
- def _handleEvent(self):
- item = self._getCurrentItem()
-
- if item.isLeaf():
- return item.select()
- else:
- self._cascadeNLevel()
-
- def _callbackDefault(self, item):
- log.log(log.NOTICE, "%s selected" % item.getLabel())
-
- def _callbackView(self, panelname):
- control = cli.controller.getController()
-
- start = control.getPage()
- panels = control.getDisplayPanels(includeSticky=False)
- panelnames = [panel.getName() for panel in panels]
- while not panelname in panelnames:
- control.nextPage()
- panels = control.getDisplayPanels(includeSticky=False)
- panelnames = [panel.getName() for panel in panels]
-
- if control.getPage() == start:
- log.log(log.ERR, "Panel %s not found" % panelname)
- break
-
- def _getItemEnabled(self, panel, attr, value):
- control = cli.controller.getController()
- if control:
- panel = control.getPanel(panel)
-
- if panel:
- return getattr(panel, attr, None) != value
-
- return False
-
- def _callbackSet(self, panel, attr, value, key=None):
- control = cli.controller.getController()
- panel = control.getPanel(panel)
-
- panelattr = getattr(panel, attr, None)
-
- if panelattr != None:
- if hasattr(panelattr, '__call__'):
- panelattr(value)
- elif panelattr != value and key != None:
- start = panelattr
- while panelattr != value:
- panel.handleKey(key)
- panelattr = getattr(panel, attr, None)
- if panelattr == start:
- log.log(log.ERR, "Could not set %s.%s" % (panel, attr))
- break
-
- def _callbackPressKey(self, panel, key):
- control = cli.controller.getController()
- panel = control.getPanel(panel)
- panel.handleKey(key)
-
- def _callbackReturnKey(self, key):
- return key
-
diff --git a/src/cli/menu_alt/menuItem.py b/src/cli/menu_alt/menuItem.py
deleted file mode 100644
index 277c78a..0000000
--- a/src/cli/menu_alt/menuItem.py
+++ /dev/null
@@ -1,41 +0,0 @@
-"""
-Menu Item class, used by the drop-down menus.
-"""
-
-class MenuItem():
- """
- Contains title, callback handler and possible children.
- """
-
- def __init__(self, label=None, callback=None, children=[], enabled=None):
- self._label = label
- self._callback = callback
- self._children = children
- self._enabled = enabled
-
- def getLabel(self):
- return self._label
-
- def isLeaf(self):
- return self._children == []
-
- def isParent(self):
- return self._children != []
-
- def isEnabled(self):
- if self._enabled == None:
- return True
- elif hasattr(self._enabled, '__call__'):
- return self._enabled()
- else:
- return self._enabled
-
- def getChildren(self):
- return self._children
-
- def getChildrenCount(self):
- return len(self._children)
-
- def select(self):
- return self._callback(self)
-
1
0