Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJack Zielke <kg4gjy@takeovertheworld.org>2009-05-26 05:18:32 (GMT)
committer Jack Zielke <kg4gjy@takeovertheworld.org>2009-05-26 05:18:32 (GMT)
commit0da5af5f8c3255dd681b10584acc7c0ff41a515f (patch)
tree62b55f419a5652272d784becc4fed7a4d8a2330c
parente66bd819c2f11dc4469439ea40db095c6dbc5886 (diff)
version 9 - journal works, message text in bold, scroll bugfix
-rw-r--r--NEWS1
-rw-r--r--README6
-rw-r--r--TODO6
-rw-r--r--activity/activity.info2
-rwxr-xr-xaprs.py224
5 files changed, 155 insertions, 84 deletions
diff --git a/NEWS b/NEWS
index 503d20b..0ade83a 100644
--- a/NEWS
+++ b/NEWS
@@ -7,3 +7,4 @@ October 5 2008 - version 5 - no journal, can not cancel messages
October 7 2008 - version 6 - no journal, can cancel message queue, show acks
October 18 2008 - version 7 - no journal, ack bugfix
October 18 2008 - version 8 - no journal, 8.2.0 update
+November 9 2008 - version 9 - journal works, message text in bold, scroll bugfix
diff --git a/README b/README
index 220de8a..c92acb1 100644
--- a/README
+++ b/README
@@ -1,8 +1,6 @@
-APRS for OLPC
-
-APRS Position Reporting for OLPC
+APRS for OLPC XO
This activity tries to follow the development plan outlined by Bob Bruninga,
WB4APR.
-http://www.ew.usna.edu/~bruninga/APRS-OLPC.html
+http://aprs.org/APRS-OLPC.html
diff --git a/TODO b/TODO
index ca8ab62..24da9ec 100644
--- a/TODO
+++ b/TODO
@@ -1,11 +1,11 @@
-save in journal
-
multi language
+cancel individual messages
+beep on message receive
+
cleanup timers on disconnect
cleanup old acks in self.sent_acks{}
cleanup old timers in self.timers[]
-send a default filter command like: s//A/X ?
auto reconnect?
aprs.laptop.org?
diff --git a/activity/activity.info b/activity/activity.info
index e334971..464a9bd 100644
--- a/activity/activity.info
+++ b/activity/activity.info
@@ -1,6 +1,6 @@
[Activity]
name = APRS-XO
-activity_version= 8
+activity_version= 9
service_name = org.laptop.APRSXO
icon = activity-aprs-xo
exec = sugar-activity aprs.APRSActivity
diff --git a/aprs.py b/aprs.py
index 830fd02..a3178b0 100755
--- a/aprs.py
+++ b/aprs.py
@@ -22,6 +22,7 @@ import time
import socket
import random
import gobject
+import json
from gettext import gettext as _
@@ -31,8 +32,6 @@ from sugar.bundle.activitybundle import ActivityBundle
from sugar.graphics.menuitem import MenuItem
from sugar.graphics.toolbutton import ToolButton
-TESTING = False
-
HOST = 'rotate.aprs2.net'
#HOST = '192.168.50.6'
PORT = 14580
@@ -77,6 +76,7 @@ class APRSActivity(activity.Activity):
mediumfont = pango.FontDescription('Sans 6.5')
smallfont = pango.FontDescription('Sans 6')
verysmallfont = pango.FontDescription('Sans 4')
+
firstName = profile.get_nick_name().split(None, 1)[0].capitalize()
toolbox = activity.ActivityToolbox(self)
@@ -84,12 +84,12 @@ class APRSActivity(activity.Activity):
activity_toolbar = toolbox.get_activity_toolbar()
activity_toolbar.share.props.visible = False
- activity_toolbar.keep.props.visible = False
+# activity_toolbar.keep.props.visible = False
toolbox.show()
win = gtk.HBox(False, 10)
- self.set_canvas(win)
+# self.set_canvas(win)
leftwin = gtk.VBox(False, 10)
@@ -174,6 +174,7 @@ class APRSActivity(activity.Activity):
self.calltext = gtk.Entry()
self.calltext.set_max_length(9)
self.calltext.set_width_chars(9)
+ self.calltext.set_text(self.metadata.get('callsign', ""))
self.calltext.connect("changed", self.disable_beacon)
bottomidentbox.pack_start(self.calltext, False, False, 0)
self.calltext.show()
@@ -428,9 +429,13 @@ class APRSActivity(activity.Activity):
self.messagebuffer.set_text("Welcome to APRS-XO.\n\nThis program sends your position information to a server that\nwill display your location on a webpage. This program requires an active Internet connection to work.\n\nSelect an APRS Site\nSelecting a button will copy the URI to the clipboard.\n\nIndentifiers\nEnter your callsign and optionally an aprsd password.\n\nStation Comment\nData in the Station Comment field will appear after your\nlocation information on the website.")
+ # tags for easier reading of messages
+ self.messagebold = self.messagebuffer.create_tag("bold", weight=pango.WEIGHT_BOLD)
+
self.messagewindow = gtk.ScrolledWindow()
self.messagewindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS)
- self.messagewindow.add_with_viewport(self.messageview)
+# self.messagewindow.add_with_viewport(self.messageview)
+ self.messagewindow.add(self.messageview)
self.messageview.show()
rightwin.pack_start(self.messagewindow, True, True, 0)
self.messagewindow.show()
@@ -477,7 +482,8 @@ class APRSActivity(activity.Activity):
self.statuswindow = gtk.ScrolledWindow()
self.statuswindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS)
- self.statuswindow.add_with_viewport(self.statusview)
+# self.statuswindow.add_with_viewport(self.statusview)
+ self.statuswindow.add(self.statusview)
self.statusview.show()
rightwin.pack_start(self.statuswindow, True, True, 0)
self.statuswindow.show()
@@ -504,25 +510,15 @@ class APRSActivity(activity.Activity):
win.pack_start(rightwin, False, False, 0)
rightwin.show()
- # for quick testing
- if (TESTING):
- self.calltext.set_text("kg4gjy")
- self.passtext.set_text("18107")
- self.latDDtext.set_text("35")
- self.latMMtext.set_text("7")
- self.latmmtext.set_text("42")
- self.latcombo.set_active(0)
- self.lonDDDtext.set_text("85")
- self.lonMMtext.set_text("6")
- self.lonmmtext.set_text("93")
- self.loncombo.set_active(0)
-# self.stationtext.set_text("")
- self.ziptext.set_text("")
- self.beaconbutton.set_active(True)
-
+ self.set_canvas(win)
win.show()
self.calltext.grab_focus()
+ # Fix window not updating until activity after alt-tab
+ self.statusbuffer.create_mark("end", self.statusbuffer.get_end_iter(), False)
+ # Do the same for message window, without auto delete it did not have the problem
+ self.messagebuffer.create_mark("end", self.messagebuffer.get_end_iter(), False)
+
def clear_status(self, button=None):
self.statusbuffer.set_text("")
@@ -545,7 +541,7 @@ class APRSActivity(activity.Activity):
try:
iplist = socket.gethostbyname_ex(HOST)[2]
except socket.error, msg:
- self.status_write(msg[1])
+ self.status_write("\n%s\n" % msg[1])
self.sock = None
return False
server = random.choice(iplist)
@@ -553,7 +549,7 @@ class APRSActivity(activity.Activity):
try:
self.sock.connect((server, PORT))
except socket.error, msg:
- self.status_write(msg[1])
+ self.status_write("%s\n" % msg[1])
self.sock = None
return False
@@ -566,10 +562,12 @@ class APRSActivity(activity.Activity):
if (response.find("javAPRSSrvr") == -1):
self.status_write("invalid response.\n")
self.disconnect_aprs(button)
+ return False
if (response.find("Port Full") != -1):
self.status_write("Port Full.\n")
self.disconnect_aprs(button)
+ return False
if (self.calltext.get_text() != "" and self.passtext.get_text() != ""):
sendme = "user %s pass %s vers aprs_xo %d filter %s\n" % (self.calltext.get_text(), self.passtext.get_text(), VERSION, FILTER)
@@ -583,6 +581,7 @@ class APRSActivity(activity.Activity):
if (response.find("# logresp") == -1):
self.status_write("invalid response.\n")
self.disconnect_aprs(button)
+ return False
if (response.find("unverified") != -1):
sendme = "# filter %s\n" % FILTER
@@ -720,17 +719,26 @@ class APRSActivity(activity.Activity):
deletehere = self.statusbuffer.get_iter_at_line(statuslines - MAXLINES)
self.statusbuffer.delete(self.statusbuffer.get_start_iter(), deletehere)
if (not self.statusview.is_focus()):
- adjustment = self.statuswindow.get_vadjustment()
- adjustment.set_value(adjustment.upper)
+ self.statusbuffer.move_mark_by_name("end", self.statusbuffer.get_end_iter())
+ self.statusview.scroll_mark_onscreen(self.statusbuffer.get_mark("end"))
- def message_write(self, text):
+ def message_write(self, text, bold=None):
if (self.messagebox):
self.clear_message()
self.messagebox = False
- self.messagebuffer.insert(self.messagebuffer.get_end_iter(), text)
+ iter = self.messagebuffer.get_end_iter()
+ self.messagebuffer.insert(iter, text)
+ if (bold):
+ bold_end = iter.copy()
+ bold_start = iter.copy()
+ bold_end.forward_to_line_end()
+ bold_start = bold_end.backward_search(">", gtk.TEXT_SEARCH_TEXT_ONLY)
+ bold_start[0].forward_chars(2)
+ self.messagebuffer.apply_tag(self.messagebold, bold_start[0], bold_end)
+
if (not self.messageview.is_focus()):
- adjustment = self.messagewindow.get_vadjustment()
- adjustment.set_value(adjustment.upper)
+ self.messagebuffer.move_mark_by_name("end", self.messagebuffer.get_end_iter())
+ self.messageview.scroll_mark_onscreen(self.messagebuffer.get_mark("end"))
def set_site(self, widget, data=None):
self.site = data
@@ -874,53 +882,107 @@ class APRSActivity(activity.Activity):
self.beaconbutton.set_active(beaconchecked)
self.validating = False
- def close( self ):
+ def can_close( self ):
self.hide()
if (self.sock != None):
self.disconnect()
- activity.Activity.close( self )
-
- def write_file_broken(self, filename):
- # does not appear to run
- # from self.save() returns:
- # TypeError: object of type 'dbus.Int32' has no len()
-
- self.metadata['mime_type'] = 'text/plain'
-
- self.metadata['callsign'] = self.calltext.get_text()
- self.metadata['password'] = self.passtext.get_text()
- self.metadata['latDD'] = self.latDDtext.get_text()
- self.metadata['latMM'] = self.latMMtext.get_text()
- self.metadata['latmm'] = self.latmmtext.get_text()
- self.metadata['lat'] = self.latcombo.get_active()
- self.metadata['lonDDD'] = self.lonDDDtext.get_text()
- self.metadata['lonMM'] = self.lonMMtext.get_text()
- self.metadata['lonmm'] = self.lonmmtext.get_text()
- self.metadata['lon'] = self.loncombo.get_active()
-# self.metadata['nick_name'] = self.nametext.get_text()
-# self.metadata['location'] = self.location
- self.metadata['stationtext'] = self.stationtext.get_text()
-# self.metadata['zip'] = self.ziptext.get_text()
- self.metadata['beacon'] = self.beaconbutton.get_active()
- # should save list of callsigns used in outgoing messages
-
- def read_file_broken(self, filename):
- # does not appear to run
+ return True
+
+ def write_file(self, file_path):
+ try:
+ self.metadata['mime_type'] = 'text/plain'
+
+ self.metadata['callsign'] = self.calltext.get_text()
+ self.metadata['password'] = self.passtext.get_text()
+ self.metadata['latDD'] = self.latDDtext.get_text()
+ self.metadata['latMM'] = self.latMMtext.get_text()
+ self.metadata['latmm'] = self.latmmtext.get_text()
+ self.metadata['lat'] = self.latcombo.get_active_text()
+ self.metadata['lonDDD'] = self.lonDDDtext.get_text()
+ self.metadata['lonMM'] = self.lonMMtext.get_text()
+ self.metadata['lonmm'] = self.lonmmtext.get_text()
+ self.metadata['lon'] = self.loncombo.get_active_text()
+ self.metadata['stationtext'] = self.stationtext.get_text()
+ if (self.beaconbutton.get_active()):
+ self.metadata['beacon'] = 'True'
+ else:
+ self.metadata['beacon'] = 'False'
+
+ callsignlist = []
+ model = self.messagecombo.get_model()
+ iter = model.get_iter_first()
+ while iter:
+ callsignlist.append(model.get(iter, 0)[0])
+ iter = model.iter_next(iter)
+
+ JournalData = {}
+ JournalData['callsignlist'] = callsignlist
+ if (self.help):
+ JournalData['messages'] = "Message Window"
+ else:
+ JournalData['messages'] = self.messagebuffer.get_text(self.messagebuffer.get_start_iter(), self.messagebuffer.get_end_iter())
+ data = json.write(JournalData)
+
+ f = open(file_path, 'w')
+ try:
+ f.write(data)
+ finally:
+ f.close()
+
+ except Exception, e:
+ self.status_write("write_file(): %s\n" % e)
+
+ def read_file(self, file_path):
+ self.statusbuffer.set_text("Status Window\n\n")
self.calltext.set_text(self.metadata.get('callsign', ""))
self.passtext.set_text(self.metadata.get('password', ""))
- self.latDDtext.set_text(self.metadata.get('latDD', "00"))
- self.latMMtext.set_text(self.metadata.get('latMM', "00"))
- self.latmmtext.set_text(self.metadata.get('latmm', "00"))
-# self.latcombo.set_active(self.metadata.get('lat', ""))
- self.lonDDDtext.set_text(self.metadata.get('lonDDD', "000"))
- self.lonMMtext.set_text(self.metadata.get('lonMM', "00"))
- self.lonmmtext.set_text(self.metadata.get('lonmm', "00"))
-# self.loncombo.set_active(self.metadata.get('lon', ""))
-# self.nametext.set_text(self.metadata.get('nick_name', "Joe"))
-# self.locbutton.set_active(self.metadata.get('location', ""))
- self.stationtext.set_text(self.metadata.get('stationtext', "test text"))
- self.ziptext.set_text(self.metadata.get('zip', ""))
-# self.beaconbutton.set_active(self.metadata.get('beacon', ""))
+ self.latDDtext.set_text(self.metadata.get('latDD', "DD"))
+ self.latMMtext.set_text(self.metadata.get('latMM', "MM"))
+ self.latmmtext.set_text(self.metadata.get('latmm', "mm"))
+ if (self.metadata.get('lat', "N") == "N"):
+ self.latcombo.set_active(0)
+ else:
+ self.latcombo.set_active(1)
+ self.lonDDDtext.set_text(self.metadata.get('lonDDD', "DDD"))
+ self.lonMMtext.set_text(self.metadata.get('lonMM', "MM"))
+ self.lonmmtext.set_text(self.metadata.get('lonmm', "mm"))
+ if (self.metadata.get('lon', "W") == "W"):
+ self.loncombo.set_active(0)
+ else:
+ self.loncombo.set_active(1)
+ stationtext = self.metadata.get('stationtext', "")
+ if (stationtext == ""):
+ firstName = profile.get_nick_name().split(None, 1)[0].capitalize()
+ self.stationtext.set_text("%s's XO at home." % firstName)
+ else:
+ self.stationtext.set_text(stationtext)
+ if (self.metadata.get('beacon', "True") == "True"):
+ self.beaconbutton.set_active(True)
+ else:
+ self.beaconbutton.set_active(False)
+
+ JournalData = {}
+ callsignlist = ["ALL", "BEACON", "CQ", "QST"]
+ messages = "Message Window"
+ try:
+ f = open(file_path, 'r')
+ JournalData = json.read(f.read())
+ if JournalData.has_key('callsignlist'):
+ callsignlist = JournalData['callsignlist']
+ if JournalData.has_key('messages'):
+ messages = JournalData['messages']
+ except:
+ pass
+ finally:
+ f.close()
+ self.messagebuffer.set_text(messages)
+ self.help = False
+ if (messages == "Message Window"):
+ self.messagebox = True
+ else:
+ self.messagebox = False
+ for currentcall in callsignlist:
+ self.add_callsign(currentcall, False)
def msg_check(self, data):
firstcheck = data.find("::")
@@ -937,7 +999,7 @@ class APRSActivity(activity.Activity):
bln_id = "%s-%s" % (fromcall, strippedtocall)
if (not bln_id in self.seen_bulletins):
self.seen_bulletins[bln_id] = 1
- self.message_write("%s %s:%s> %s\n" % (time.strftime("%m/%d %H:%M", time.localtime()), fromcall, strippedtocall, message))
+ self.message_write("%s %s:%s> %s\n" % (time.strftime("%m/%d %H:%M", time.localtime()), fromcall, strippedtocall, message), True)
else:
if (strippedtocall == self.calltext.get_text()):
self.add_callsign(fromcall, False)
@@ -980,7 +1042,7 @@ class APRSActivity(activity.Activity):
self.timers.append(gobject.timeout_add(120 * 1000, self.send_ack, tocall, sequence))
else:
# TODO beep?
- self.message_write("%s %s> %s\n" % (time.strftime("%m/%d %H:%M", time.localtime()), fromcall, message))
+ self.message_write("%s %s> %s\n" % (time.strftime("%m/%d %H:%M", time.localtime()), fromcall, message), True)
self.sent_acks[id] = time.time() # to help a cleanup thread later
self.sent_acks[fromcall] = sequence # to help with reply acks later
else:
@@ -1014,7 +1076,7 @@ class APRSActivity(activity.Activity):
self.recv_acks[ackid] = 1
else:
# TODO beep?
- self.message_write("%s %s> %s\n" % (time.strftime("%m/%d %H:%M", time.localtime()), fromcall, message))
+ self.message_write("%s %s> %s\n" % (time.strftime("%m/%d %H:%M", time.localtime()), fromcall, message), True)
def disable_beacon(self, widget, data=None):
if (self.sock != None):
@@ -1206,6 +1268,14 @@ class APRSActivity(activity.Activity):
iter.forward_chars(15 + len(call))
self.message_marks[id] = self.messagebuffer.create_mark(None, iter, True)
# self.message_marks[id].set_visible(True)
+
+ bold_end = iter.copy()
+ bold_start = iter.copy()
+ bold_end.forward_to_line_end()
+ bold_end = bold_end.backward_search("<", gtk.TEXT_SEARCH_TEXT_ONLY)
+ bold_start.forward_chars(2)
+ self.messagebuffer.apply_tag(self.messagebold, bold_start, bold_end[0])
+
return True
def send_msg_queue(self, call):
@@ -1226,7 +1296,6 @@ class APRSActivity(activity.Activity):
isbulletin = self.bulletin_check(call)
if (isbulletin):
self.send_data(":%s:%s" % (call.ljust(9), message))
- # TODO what are the correct timings for bulletins?
gobject.timeout_add(600 * 1000, self.msg_timer, call, message, "", 2, 600)
else:
replyack = self.replyack(call)
@@ -1266,6 +1335,9 @@ class APRSActivity(activity.Activity):
self.messagebuffer.insert(iter, " 1/%s" % MAXRETRIES)
def cancel_message(self, id):
+ if (self.recv_acks[id] == 1):
+ return
+
self.recv_acks[id] = 1
# remove status