~ubuntu-branches/ubuntu/oneiric/agtl/oneiric

« back to all changes in this revision

Viewing changes to freerunner/usr/lib/site-python/advancedcaching/biggui.py

  • Committer: Bazaar Package Importer
  • Author(s): Heiko Stuebner
  • Date: 2009-09-11 20:39:19 UTC
  • Revision ID: james.westby@ubuntu.com-20090911203919-v0oh5cf3w8ly1366
Tags: upstream-0.3.0+git20090911
ImportĀ upstreamĀ versionĀ 0.3.0+git20090911

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/python
 
2
# -*- coding: utf-8 -*-
 
3
 
 
4
#       Copyright (C) 2009 Daniel Fett
 
5
#       This program is free software: you can redistribute it and/or modify
 
6
#   it under the terms of the GNU General Public License as published by
 
7
#   the Free Software Foundation, either version 3 of the License, or
 
8
#   (at your option) any later version.
 
9
#
 
10
#   This program is distributed in the hope that it will be useful,
 
11
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
#   GNU General Public License for more details.
 
14
#
 
15
#   You should have received a copy of the GNU General Public License
 
16
#   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
17
#
 
18
#       Author: Daniel Fett simplecaching@fragcom.de
 
19
#
 
20
 
 
21
 
 
22
### For the gui :-)
 
23
import math
 
24
import thread
 
25
 
 
26
import extListview
 
27
import geo
 
28
import geocaching
 
29
import gobject
 
30
import gtk
 
31
from htmlentitydefs import name2codepoint as n2cp
 
32
import openstreetmap
 
33
import pango
 
34
import provider
 
35
import re
 
36
 
 
37
 
 
38
class BigGui(GtkGui):
 
39
    MAP_FACTOR = 0
 
40
    CACHE_SIZE = 20
 
41
    CLICK_RADIUS = 10
 
42
    TOO_MUCH_POINTS = 400
 
43
        
 
44
        
 
45
    SETTINGS_CHECKBOXES = [
 
46
        'download_visible',
 
47
        'download_notfound',
 
48
        'download_new',
 
49
        'download_nothing',
 
50
        'download_create_index',
 
51
        'download_run_after',
 
52
        'download_resize',
 
53
        'options_show_name'
 
54
    ]
 
55
    SETTINGS_INPUTS = [
 
56
        'download_run_after_string',
 
57
        'download_output_dir',
 
58
        'download_resize_pixel',
 
59
        'options_username',
 
60
        'options_password'
 
61
    ]
 
62
        
 
63
    def __init__(self, core, pointprovider, userpointprovider):
 
64
        self.ts = ts = openstreetmap.TileServer()
 
65
                
 
66
        self.core = core
 
67
        self.pointprovider = pointprovider
 
68
        self.userpointprovider = userpointprovider
 
69
                
 
70
        self.current_cache = None
 
71
        self.dragging = False
 
72
        self.block_changes = False
 
73
                
 
74
        self.drawing_area_configured = False
 
75
        self.drag_offset_x = 0
 
76
        self.drag_offset_y = 0
 
77
        self.map_center_x, self.map_center_y = 100, 100
 
78
        self.inhibit_zoom = False
 
79
        self.draw_lock = thread.allocate_lock()
 
80
                
 
81
        global builder
 
82
                
 
83
        builder = gtk.Builder()
 
84
        builder.add_from_file("../../glade/main.glade")
 
85
        self.window = builder.get_object("window")
 
86
                
 
87
        builder.connect_signals({"on_window_destroy": self.destroy,
 
88
                                "on_zoomin_clicked": self.on_zoomin_clicked,
 
89
                                "on_zoomout_clicked": self.on_zoomout_clicked,
 
90
                                "on_download_clicked": self.on_download_clicked,
 
91
                                'save_config': self.on_save_config,
 
92
                                'on_button_download_now_clicked': self.on_download_descriptions_clicked,
 
93
                                'on_spinbutton_zoom_change_value': self.on_zoom_changed,
 
94
                                'start_search': self.on_start_search_simple,
 
95
                                'on_entry_search_key_release_event': self.on_search_simple_key_release,
 
96
                                #       'on_vscale_search_terrain_change_value' : self.search_value_terrain_change,
 
97
                                #       'on_vscale_search_diff_change_value' : self.search_value_diff_change
 
98
                                'on_button_advanced_search_clicked': self.on_search_advanced_clicked,
 
99
                                'on_check_search_find_no_details_toggled': self.on_search_details_toggled
 
100
                                })
 
101
 
 
102
                
 
103
        self.drawing_area = builder.get_object('drawingarea')
 
104
        self.drawing_area.connect("expose_event", self.expose_event)
 
105
        self.drawing_area.connect("configure_event", self.configure_event)
 
106
        self.drawing_area.connect("button_press_event", self.drag_start)
 
107
        self.drawing_area.connect("scroll_event", self.scroll)
 
108
        self.drawing_area.connect("button_release_event", self.drag_end)
 
109
        self.drawing_area.connect("motion_notify_event", self.drag)
 
110
        self.drawing_area.set_events(gtk.gdk.EXPOSURE_MASK | gtk.gdk.BUTTON_PRESS_MASK | gtk.gdk.BUTTON_RELEASE_MASK | gtk.gdk.POINTER_MOTION_MASK | gtk.gdk.SCROLL)
 
111
        #self.drawing_area.show()
 
112
                
 
113
                
 
114
        self.zoom_adjustment = builder.get_object('spinbutton_zoom').get_adjustment()
 
115
                
 
116
        self.hpaned = builder.get_object("hpaned1")
 
117
        self.hpaned.set_position(0)
 
118
        self.cache_elements = {
 
119
            'name_downloaded':  builder.get_object('link_cache_name'),
 
120
            'name_not_downloaded': builder.get_object('button_cache_name'),
 
121
            'title': builder.get_object('label_cache_title'),
 
122
            'type': builder.get_object('label_cache_type'),
 
123
            'size': builder.get_object('label_cache_size'),
 
124
            'terrain': builder.get_object('label_cache_terrain'),
 
125
            'difficulty': builder.get_object('label_cache_difficulty'),
 
126
            'desc': builder.get_object('label_cache_desc'),
 
127
            'shortdesc': builder.get_object('label_cache_shortdesc'),
 
128
            'hints': builder.get_object('label_cache_hints'),
 
129
            'coords': builder.get_object('label_cache_coords'),
 
130
            'found': builder.get_object('check_cache_found'),
 
131
            'homepage': builder.get_object('link_cache_homepage'),
 
132
            'log': builder.get_object('link_cache_log'),
 
133
            'notebook': builder.get_object('notebook_cache')
 
134
        }
 
135
                
 
136
        self.search_elements = {
 
137
            'name': builder.get_object('entry_search_name'),
 
138
            'owner': builder.get_object('entry_search_owner'),
 
139
            'found': {
 
140
                'true': builder.get_object('radio_search_found_true'),
 
141
                'false': builder.get_object('radio_search_found_false')
 
142
                },
 
143
            'type': {
 
144
                'regular': builder.get_object('check_search_type_traditional'),
 
145
                'multi': builder.get_object('check_search_type_multi'),
 
146
                'unknown': builder.get_object('check_search_type_unknown'),
 
147
                'virtual': builder.get_object('check_search_type_virtual'),
 
148
                'other': builder.get_object('check_search_type_other')
 
149
                },
 
150
            'size': {
 
151
                '1': builder.get_object('check_search_size_1'),
 
152
                '2': builder.get_object('check_search_size_2'),
 
153
                '3': builder.get_object('check_search_size_3'),
 
154
                '4': builder.get_object('check_search_size_4'),
 
155
                '5': builder.get_object('check_search_size_other')
 
156
                },
 
157
            'terrain': {
 
158
                'lower': builder.get_object('vscale_search_terrain_lower'),
 
159
                'upper': builder.get_object('vscale_search_terrain_upper')
 
160
                },
 
161
            'diff': {
 
162
                'lower': builder.get_object('vscale_search_diff_lower'),
 
163
                'upper': builder.get_object('vscale_search_diff_upper')
 
164
                },
 
165
            'frames': {
 
166
                'type': builder.get_object('frame_search_type'),
 
167
                'size': builder.get_object('frame_search_size'),
 
168
                'terrain': builder.get_object('frame_search_terrain'),
 
169
                'diff': builder.get_object('frame_search_diff'),
 
170
            },
 
171
            'no_details': builder.get_object('check_search_no_details')
 
172
        }
 
173
        self.search_elements['terrain']['lower'].get_adjustment().set_value(1)
 
174
        self.search_elements['terrain']['upper'].get_adjustment().set_value(5)
 
175
        self.search_elements['diff']['lower'].get_adjustment().set_value(1)
 
176
        self.search_elements['diff']['upper'].get_adjustment().set_value(5)
 
177
                
 
178
        #
 
179
        # setting up TABLES
 
180
        #
 
181
                
 
182
        strings = self.pointprovider.get_titles_and_names()
 
183
        liststore = gtk.ListStore(gobject.TYPE_STRING)
 
184
        for string in strings:
 
185
            liststore.append([string])
 
186
        comp = builder.get_object('entrycompletion_search')
 
187
        entry = builder.get_object('entry_search')
 
188
        entry.set_completion(comp)
 
189
        comp.set_model(liststore)
 
190
        comp.set_text_column(0)
 
191
        self.entry_search = entry
 
192
                
 
193
                
 
194
        # Create the renderer used in the listview
 
195
        txtRdr    = gtk.CellRendererText()
 
196
        pixbufRdr = gtk.CellRendererPixbuf()
 
197
        (
 
198
         ROW_FOUND,
 
199
         ROW_TYPE,
 
200
         ROW_SIZE,
 
201
         ROW_TERRAIN,
 
202
         ROW_DIFF,
 
203
         ROW_ID,
 
204
         ROW_TITLE,
 
205
         ) = range(7)
 
206
        columns = (
 
207
                   ('gefunden?', [(txtRdr, gobject.TYPE_STRING)], (ROW_FOUND, ROW_ID), False, True),
 
208
                   ('Typ', [(txtRdr, gobject.TYPE_STRING)], (ROW_TYPE, ), False, True),
 
209
                   ('GrĆ¶ĆŸe', [(txtRdr, gobject.TYPE_STRING)], (ROW_SIZE, ROW_ID), False, True),
 
210
                   ('Terrain', [(txtRdr, gobject.TYPE_STRING)], (ROW_TERRAIN, ROW_ID), False, True),
 
211
                   ('Difficulty', [(txtRdr, gobject.TYPE_STRING)], (ROW_DIFF, ROW_ID), False, True),
 
212
                   ('ID', [(txtRdr, gobject.TYPE_STRING)], (ROW_ID, ), False, True),
 
213
                   ('Titel', [(txtRdr, gobject.TYPE_STRING)], (ROW_TITLE, ), False, True),
 
214
                   )
 
215
        self.cachelist = listview = extListview.ExtListView(columns, sortable=True, useMarkup=False, canShowHideColumns=False)
 
216
        builder.get_object('scrolledwindow_search').add(listview)
 
217
        listview.connect('extlistview-button-pressed', self.on_search_cache_clicked)
 
218
                
 
219
        # Create the renderer used in the listview for user defined points
 
220
                
 
221
        txtRdr    = gtk.CellRendererText()
 
222
        pixbufRdr = gtk.CellRendererPixbuf()
 
223
        (
 
224
         ROW_COORD,
 
225
         ROW_COMMENT,
 
226
         ) = range(2)
 
227
        columns = (
 
228
                   ('Position', [(txtRdr, gobject.TYPE_STRING)], (ROW_COORD), False, True),
 
229
                   ('Kommentar', [(txtRdr, gobject.TYPE_STRING)], (ROW_COMMENT, ), False, True),
 
230
                   )
 
231
        self.userpointlist = extListview.ExtListView(columns, sortable=True, useMarkup=False, canShowHideColumns=False)
 
232
        builder.get_object('scrolledwindow_userpoints').add(self.userpointlist)
 
233
                
 
234
        '''
 
235
        def center(coord):
 
236
                point = self.ts.deg2num(coord)
 
237
                size = self.ts.tile_size()
 
238
                p_x = (point[0] * size - self.map_center_x * size)
 
239
                p_y = (point[1] * size - self.map_center_y * size)
 
240
                '''
 
241
        
 
242
                
 
243
    def __configure_event(self, widget, event):
 
244
        
 
245
        x, y, width, height = widget.get_allocation()
 
246
        self.map_width = int(width  + 2 * width * self.MAP_FACTOR)
 
247
        self.map_height = int(height + 2 * height * self.MAP_FACTOR)
 
248
        try:
 
249
            openstreetmap.TileLoader.drawlock.acquire()
 
250
            self.pixmap = gtk.gdk.Pixmap(widget.window, self.map_width, self.map_height)
 
251
        finally:
 
252
            openstreetmap.TileLoader.drawlock.release()
 
253
                        
 
254
        self.xgc = widget.get_style().fg_gc[gtk.STATE_NORMAL]
 
255
        #xgc.line_width = 3
 
256
        self.drawing_area_configured = True
 
257
        self.draw_at_x = 0
 
258
        self.draw_at_y = 0
 
259
        self.draw_root_x = int(-width * self.MAP_FACTOR)
 
260
        self.draw_root_y = int(-height * self.MAP_FACTOR)
 
261
        self.__draw_map()
 
262
                
 
263
    def __coord2point(self, coord):
 
264
        point = self.ts.deg2num(coord)
 
265
        size = self.ts.tile_size()
 
266
                
 
267
        p_x = int(point[0] * size - self.map_center_x * size + self.map_width / 2)
 
268
        p_y = int(point[1] * size - self.map_center_y * size + self.map_height / 2)
 
269
        return [p_x, p_y]
 
270
                
 
271
        
 
272
                
 
273
    def __decode_htmlentities(self, string):
 
274
        def substitute_entity(match):
 
275
            ent = match.group(3)
 
276
            if match.group(1) == "#":
 
277
                # decoding by number
 
278
                if match.group(2) == '':
 
279
                    # number is in decimal
 
280
                    return unichr(int(ent))
 
281
                elif match.group(2) == 'x':
 
282
                    # number is in hex
 
283
                    return unichr(int('0x' + ent, 16))
 
284
            else:
 
285
                # they were using a name
 
286
                cp = n2cp.get(ent)
 
287
                if cp:
 
288
                    return unichr(cp)
 
289
                else:
 
290
                    return match.group()
 
291
 
 
292
        entity_re = re.compile(r'&(#?)(x?)(\w+);')
 
293
        return entity_re.subn(substitute_entity, string)[0]
 
294
        
 
295
    def destroy(self, target):
 
296
        gtk.main_quit()
 
297
    # called by core
 
298
    def display_results_advanced(self, caches):
 
299
        rows = []
 
300
        for r in caches:
 
301
            if r.found:
 
302
                f = 'ja'
 
303
            else:
 
304
                f = '  '
 
305
            if r.size == -1:
 
306
                s = "?"
 
307
            else:
 
308
                s = "%d" % r.size
 
309
                                
 
310
            if r.difficulty == -1:
 
311
                d = "?"
 
312
            else:
 
313
                d = "%.1f" % r.difficulty
 
314
                                
 
315
            if r.terrain == -1:
 
316
                t = "?"
 
317
            else:
 
318
                t = "%.1f" % r.terrain
 
319
                        
 
320
            rows.append((f, r.type, s, t, d, r.name, r.title))
 
321
        self.cachelist.replaceContent(rows)
 
322
                
 
323
    def __draw_map(self):
 
324
        if not self.drawing_area_configured:
 
325
            return False
 
326
        
 
327
        if self.map_width == 0 or self.map_height == 0:
 
328
            return
 
329
        size = self.ts.tile_size()
 
330
        xi = int(self.map_center_x)
 
331
        yi = int(self.map_center_y)
 
332
        span_x = int(math.ceil(float(self.map_width) / (size * 2.0)))
 
333
        span_y = int(math.ceil(float(self.map_height) / (size * 2.0)))
 
334
        tiles = []
 
335
        for i in range(0, span_x + 1, 1):
 
336
            for j in range(0, span_y + 1, 1):
 
337
                for dir in range(0, 4, 1):
 
338
                    dir_ns = dir_ew = 1
 
339
                    if dir % 2 == 1: # if dir == 1 or dir == 3
 
340
                        dir_ns = -1
 
341
                    if dir > 1:
 
342
                        dir_ew = -1
 
343
                                
 
344
                    tile = (xi + (i * dir_ew), yi + (j * dir_ns))
 
345
                    if not tile in tiles:
 
346
                        tiles.append(tile)
 
347
                        #print "Requesting ", tile, " zoom ", ts.zoom
 
348
                                        
 
349
                        d = openstreetmap.TileLoader(tile, self.ts.zoom, self)
 
350
                        d.start()
 
351
 
 
352
                
 
353
    def __drag(self, widget, event):
 
354
        if not self.dragging:
 
355
            return
 
356
        self.drag_offset_x = self.drag_start_x - event.x
 
357
        self.drag_offset_y = self.drag_start_y - event.y
 
358
                
 
359
    def __drag_end(self, widget, event):
 
360
        if not self.dragging:
 
361
            return
 
362
        self.dragging = False
 
363
        offset_x = (self.drag_start_x - event.x)
 
364
        offset_y = (self.drag_start_y - event.y)
 
365
        if abs(offset_x) < 3 or abs(offset_y) < 3:
 
366
            x, y = event.x, event.y
 
367
            c = self.screenpoint2coord([x, y])
 
368
            c1 = self.screenpoint2coord([x-self.CLICK_RADIUS, y-self.CLICK_RADIUS])
 
369
            c2 = self.screenpoint2coord([x + self.CLICK_RADIUS, y + self.CLICK_RADIUS])
 
370
            cache = self.pointprovider.get_nearest_point_filter(c, c1, c2)
 
371
            self.core.on_cache_selected(cache)
 
372
            return
 
373
        self.map_center_x += (offset_x / self.ts.tile_size())
 
374
        self.map_center_y += (offset_y / self.ts.tile_size())
 
375
        self.__draw_map()
 
376
                
 
377
                        
 
378
    def __drag_draw(self):
 
379
        if not self.dragging:
 
380
            return False
 
381
        #if abs(self.drag_offset_x) < 3 or abs(self.drag_offset_y) < 3:
 
382
        #       return
 
383
        widget = self.drawing_area
 
384
        x, y, width, height = widget.get_allocation()
 
385
                
 
386
        widget.window.draw_drawable(widget.get_style().fg_gc[gtk.STATE_NORMAL],
 
387
                                    self.pixmap, -self.draw_at_x + self.drag_offset_x - self.draw_root_x, -self.draw_at_y + self.drag_offset_y - self.draw_root_y, 0, 0, width, height)
 
388
        return True
 
389
        
 
390
                
 
391
    def __drag_start(self, widget, event):
 
392
        self.drag_start_x = event.x
 
393
        self.drag_start_y = event.y
 
394
        self.drag_offset_x = 0
 
395
        self.drag_offset_y = 0
 
396
        self.last_drag_offset_x = 0
 
397
        self.last_drag_offset_y = 0
 
398
        self.dragging = True
 
399
        gobject.timeout_add(50, self.drag_draw)
 
400
                
 
401
                
 
402
                                        
 
403
    def __draw_marks(self, thr):
 
404
        xgc = self.xgc
 
405
        """
 
406
                position = Coordinate(49.75400, 6.66135)
 
407
                target = Coordinate(49.755900, 6.649933)
 
408
                bearing = 12
 
409
                
 
410
                p = self.coord2point(position)
 
411
                if p == False:
 
412
                        return
 
413
                
 
414
                t = self.coord2point(target)
 
415
                if t == False:
 
416
                        return
 
417
                
 
418
                xgc.line_width = 5              
 
419
                xgc.set_function(gtk.gdk.AND_INVERT)
 
420
                xgc.set_rgb_fg_color(gtk.gdk.color_parse("blue"))
 
421
                self.pixmap.draw_line(xgc, p[0], p[1], t[0], t[1])
 
422
                
 
423
                xgc.line_width = 1
 
424
                length = 0.001 * (2 ** ts.zoom)
 
425
                xgc.set_function(gtk.gdk.COPY)
 
426
                xgc.set_rgb_fg_color(gtk.gdk.color_parse("blue"))
 
427
                self.pixmap.draw_line(xgc, p[0], p[1], int(p[0] + math.cos(bearing) * length), int(p[1] + math.sin(bearing) * length))
 
428
                """
 
429
                
 
430
        #
 
431
        # draw geocaches
 
432
        #
 
433
                
 
434
        coords = self.pointprovider.get_points_filter((self.pixmappoint2coord([0, 0]), self.pixmappoint2coord([self.map_width, self.map_height])))
 
435
        draw_short = (len(coords) > self.TOO_MUCH_POINTS)
 
436
 
 
437
        xgc.set_function(gtk.gdk.AND)
 
438
        radius = 7
 
439
        color_default = gtk.gdk.color_parse('blue')
 
440
        color_found = gtk.gdk.color_parse('grey')
 
441
        color_regular = gtk.gdk.color_parse('green')
 
442
        color_multi = gtk.gdk.color_parse('orange')
 
443
        font = pango.FontDescription("Sans 8")
 
444
        num = 0
 
445
        for c in coords: # for each geocache
 
446
            color = color_default
 
447
            if c.found:
 
448
                color = color_found
 
449
            elif c.type == "regular":
 
450
                color = color_regular
 
451
            elif c.type == "multi":
 
452
                color = color_multi
 
453
                        
 
454
            p = self.__coord2point(c)
 
455
            xgc.set_rgb_fg_color(color)
 
456
                        
 
457
            xgc.line_width = 1
 
458
            self.pixmap.draw_line(xgc, p[0], p[1] - 2, p[0], p[1] + 3) #  |
 
459
            self.pixmap.draw_line(xgc, p[0] - 2, p[1], p[0] + 3, p[1]) # ---
 
460
                        
 
461
            if draw_short:
 
462
                continue
 
463
            xgc.line_width = 3
 
464
            self.pixmap.draw_rectangle(xgc, False, p[0] - radius, p[1] - radius, radius * 2, radius * 2)
 
465
                        
 
466
            # print the name?
 
467
            if self.settings['options_show_name']:
 
468
                layout = self.drawing_area.create_pango_layout(c.name)
 
469
                layout.set_font_description(font)
 
470
                self.pixmap.draw_layout(xgc, p[0] + 3 + radius, p[1] - 3 - radius, layout)
 
471
                        
 
472
            # if we have a description for this cache...
 
473
            if c.was_downloaded():
 
474
                # draw something like:
 
475
                # ----
 
476
                # ----
 
477
                # ----
 
478
                # besides the icon
 
479
                width = 6
 
480
                dist = 2
 
481
                pos_x = p[0] + radius + 3 + 1
 
482
                pos_y = p[1] + 2
 
483
                xgc.line_width = 1
 
484
                for i in range(0, 3):
 
485
                    self.pixmap.draw_line(xgc, pos_x, pos_y + dist * i, pos_x + width, pos_y + dist * i)
 
486
                        
 
487
            # if this cache is the active cache
 
488
            if self.current_cache != None and c.name == self.current_cache.name:
 
489
                xgc.line_width = 1
 
490
                xgc.set_rgb_fg_color(gtk.gdk.color_parse('black'))
 
491
                radius = 8
 
492
                self.pixmap.draw_rectangle(xgc, False, p[0] - radius, p[1] - radius, radius * 2, radius * 2)
 
493
                        
 
494
 
 
495
        # draw additional waypoints
 
496
        # --> print description!
 
497
        if self.current_cache != None and self.current_cache.waypoints != None:
 
498
            xgc.set_function(gtk.gdk.AND)
 
499
            xgc.set_rgb_fg_color(gtk.gdk.color_parse('red'))
 
500
            num = 0
 
501
            for w in self.current_cache.waypoints:
 
502
                if w['lat'] != -1 and w['lon'] != -1:
 
503
                    num = num + 1
 
504
                    xgc.line_width = 1
 
505
                    radius = 4
 
506
                    p = self.__coord2point(geo.Coordinate(w['lat'], w['lon']))
 
507
                    self.pixmap.draw_line(xgc, p[0], p[1] - 3, p[0], p[1] + 4) #  |
 
508
                    self.pixmap.draw_line(xgc, p[0] - 3, p[1], p[0] + 4, p[1]) # ---
 
509
                    self.pixmap.draw_arc(xgc, False, p[0] - radius, p[1] - radius, radius * 2, radius * 2, 0, 360 * 64)
 
510
                    layout = self.drawing_area.create_pango_layout('')
 
511
                    layout.set_markup('<i>%s</i>' % (w['id']))
 
512
                    layout.set_font_description(font)
 
513
                    self.pixmap.draw_layout(xgc, p[0] + 3 + radius, p[1] - 3 - radius, layout)
 
514
                
 
515
                        
 
516
        #
 
517
        # next, draw the user defined points
 
518
        #
 
519
                
 
520
        coords = self.userpointprovider.get_points_filter((self.pixmappoint2coord([0, 0]), self.pixmappoint2coord([self.map_width, self.map_height])))
 
521
 
 
522
        xgc.set_function(gtk.gdk.AND)
 
523
        radius = 7
 
524
        color = gtk.gdk.color_parse('darkorchid')
 
525
        for c in coords: # for each geocache
 
526
            p = self.__coord2point(c)
 
527
            xgc.line_width = 3
 
528
            xgc.set_rgb_fg_color(color)
 
529
            radius = 8
 
530
            self.pixmap.draw_line(xgc, p[0] - radius, p[1], p[0], p[1] + radius)
 
531
            self.pixmap.draw_line(xgc, p[0], p[1] + radius, p[0] + radius, p[1])
 
532
            self.pixmap.draw_line(xgc, p[0] + radius, p[1], p[0], p[1] - radius)
 
533
            self.pixmap.draw_line(xgc, p[0], p[1] - radius, p[0] - radius, p[1])
 
534
            xgc.line_width = 1
 
535
            self.pixmap.draw_line(xgc, p[0], p[1] - 2, p[0], p[1] + 3) #  |
 
536
            self.pixmap.draw_line(xgc, p[0] - 2, p[1], p[0] + 3, p[1]) # ---
 
537
            layout = self.drawing_area.create_pango_layout(c.name)
 
538
            layout.set_font_description(font)
 
539
            self.pixmap.draw_layout(xgc, p[0] + 3 + radius, p[1] - 3 - radius, layout)
 
540
                
 
541
        """
 
542
                xgc.line_width = 2      
 
543
                radius_o = 20
 
544
                radius_i = 7
 
545
                xgc.set_function(gtk.gdk.INVERT)
 
546
                xgc.set_rgb_fg_color(gtk.gdk.color_parse("black"))
 
547
                self.pixmap.draw_line(xgc, t[0] - radius_o, t[1], t[0] - radius_i, t[1])
 
548
                self.pixmap.draw_line(xgc, t[0] + radius_o, t[1], t[0] + radius_i, t[1])
 
549
                self.pixmap.draw_line(xgc, t[0], t[1] + radius_o, t[0], t[1] + radius_i)
 
550
                self.pixmap.draw_line(xgc, t[0], t[1] - radius_o, t[0], t[1] - radius_i)
 
551
                
 
552
                xgc.set_function(gtk.gdk.INVERT)
 
553
                self.pixmap.draw_point(xgc, t[0], t[1])
 
554
                """
 
555
                
 
556
        xgc.set_rgb_fg_color(gtk.gdk.color_parse("black"))
 
557
        xgc.set_function(gtk.gdk.COPY)
 
558
        self.refresh()
 
559
        return False
 
560
        
 
561
    def expose_event(self, widget, event):
 
562
        x, y, width, height = event.area
 
563
        try:
 
564
            openstreetmap.TileLoader.drawlock.acquire()
 
565
            widget.window.draw_drawable(widget.get_style().fg_gc[gtk.STATE_NORMAL],
 
566
                                        self.pixmap, x, y, self.draw_root_x + self.draw_at_x  + x, self.draw_root_y + self.draw_at_y + y, -1, -1)
 
567
            # width, height hier?
 
568
        finally:
 
569
            openstreetmap.TileLoader.drawlock.release()
 
570
        return False
 
571
 
 
572
    def get_visible_area(self):
 
573
        return (self.pixmappoint2coord([0, 0]), self.pixmappoint2coord([self.map_width, self.map_height]))
 
574
                
 
575
                
 
576
    def on_download_descriptions_clicked(self, something):
 
577
        self.core.on_download_descriptions(self.get_visible_area())
 
578
        self.__draw_map()
 
579
                
 
580
    def on_download_clicked(self, something):
 
581
        self.core.on_download(self.get_visible_area())
 
582
        self.__draw_map()
 
583
                                        
 
584
    def on_save_config(self, something):
 
585
        if not self.block_changes:
 
586
            self.core.on_config_changed(self.read_settings())
 
587
                
 
588
    def on_search_advanced_clicked(self, something):
 
589
        if self.search_elements['found']['true'].get_active():
 
590
            found = True
 
591
        elif self.search_elements['found']['false'].get_active():
 
592
            found = False
 
593
        else:
 
594
            found = None
 
595
                
 
596
        owner_search = self.search_elements['owner'].get_text()
 
597
        name_search = self.search_elements['name'].get_text()
 
598
                
 
599
        if not self.search_elements['type']['other'].get_active():
 
600
            ctype = []
 
601
            for type, el in self.search_elements['type'].items():
 
602
                if el.get_active():
 
603
                    ctype.append(type)
 
604
        else:
 
605
            ctype = None
 
606
                        
 
607
        if not self.search_elements['no_details'].get_active():
 
608
            size = []
 
609
            for s in range(1, 6):
 
610
                if self.search_elements['size'][str(s)].get_active():
 
611
                    size.append(s)
 
612
                                
 
613
            terrain = [self.search_elements['terrain']['lower'].get_adjustment().get_value(),
 
614
                self.search_elements['terrain']['upper'].get_adjustment().get_value()]
 
615
            diff = [self.search_elements['diff']['lower'].get_adjustment().get_value(),
 
616
                self.search_elements['diff']['upper'].get_adjustment().get_value()]
 
617
        else:
 
618
            size = terrain = diff = None
 
619
        self.core.on_start_search_advanced(found, owner_search, name_search, size, terrain, diff, ctype)
 
620
 
 
621
                
 
622
    def on_search_details_toggled(self, some=None):
 
623
        for k, i in self.search_elements['frames'].items():
 
624
            if k != 'type':
 
625
                i.set_sensitive(not self.search_elements['no_details'].get_active())
 
626
 
 
627
    def on_search_cache_clicked(self, listview, event, element):
 
628
        if event.type != gtk.gdk._2BUTTON_PRESS or element == None:
 
629
            return
 
630
                
 
631
        cachename = listview.getItem(element[0], 5)
 
632
        cache = self.pointprovider.find_by_string(cachename)
 
633
        self.core.on_cache_selected(cache)
 
634
                
 
635
                
 
636
    def on_search_key_release(self, widget, event):
 
637
        print event.keyval
 
638
        if event.keyval == 65293:  # seems to be keycode of return key
 
639
            self.core.on_start_search_simple(self.widget.get_text())
 
640
                
 
641
    def on_search_simple_key_release(self, something):
 
642
        self.core.on_start_search_simple(self.widget.get_text())
 
643
                
 
644
                
 
645
    def on_start_search_simple(self, something):
 
646
        self.core.on_start_search_simple(self.entry_search.get_text())
 
647
                        
 
648
    def on_zoom_changed(self, blub):
 
649
        if not self.inhibit_zoom:
 
650
            self.zoom()
 
651
                
 
652
    def on_zoomin_clicked(self, widget):
 
653
        self.zoom( + 1)
 
654
                
 
655
    def on_zoomout_clicked(self, widget):
 
656
        self.zoom(-1)
 
657
        
 
658
    def pixmappoint2coord(self, point):
 
659
        size = self.ts.tile_size()
 
660
        coord = self.ts.num2deg(
 
661
                                (point[0] + self.map_center_x * size - self.map_width / 2) / size,
 
662
                                (point[1] + self.map_center_y * size - self.map_height / 2) / size
 
663
                                )
 
664
        return coord
 
665
 
 
666
    def read_settings(self):
 
667
        c = self.ts.num2deg(self.map_center_x, self.map_center_y)
 
668
        settings = {
 
669
            'map_position_lat': c.lat,
 
670
            'map_position_lon': c.lon
 
671
        }
 
672
        for x in self.SETTINGS_CHECKBOXES:
 
673
            settings[x] = builder.get_object('check_%s' % x).get_active()
 
674
                
 
675
        for x in self.SETTINGS_INPUTS:
 
676
            settings[x] = builder.get_object('input_%s' % x).get_text()
 
677
                
 
678
        self.settings = settings
 
679
        return settings
 
680
                        
 
681
                
 
682
    def refresh(self):
 
683
        self.drawing_area.queue_draw()
 
684
                        
 
685
    def replace_image_tag(self, m):
 
686
        if m.group(1) != None and m.group(1).strip() != '':
 
687
            return ' [Bild: %s] ' % m.group(1).strip()
 
688
        else:
 
689
            return ' [Bild] '
 
690
                        
 
691
    def screenpoint2coord(self, point):
 
692
        size = self.ts.tile_size()
 
693
        coord = self.ts.num2deg(
 
694
                                ((point[0] - self.draw_root_x - self.draw_at_x) + self.map_center_x * size - self.map_width / 2) / size,
 
695
                                ((point[1] - self.draw_root_y - self.draw_at_y) + self.map_center_y * size - self.map_height / 2) / size
 
696
                                )
 
697
        return coord
 
698
        
 
699
    def scroll(self, widget, event):
 
700
        if event.direction == gtk.gdk.SCROLL_DOWN:
 
701
            self.zoom(-1)
 
702
        else:
 
703
            self.zoom( + 1)
 
704
    def show(self):
 
705
        self.window.show_all()
 
706
        gtk.main()
 
707
                
 
708
                        
 
709
    # called by core
 
710
    def show_cache(self, cache):
 
711
        if cache == None:
 
712
            self.hpaned.set_position(0)
 
713
            return
 
714
        self.current_cache = cache
 
715
        self.hpaned.set_position(-1)
 
716
        if cache.was_downloaded():
 
717
            uri = 'file://%s/%s.html' % (self.settings['download_output_dir'], cache.name)
 
718
            self.cache_elements['name_downloaded'].set_uri(uri)
 
719
            self.cache_elements['name_downloaded'].set_label(cache.name)
 
720
            self.cache_elements['name_downloaded'].show()
 
721
            self.cache_elements['name_not_downloaded'].hide()
 
722
        else:
 
723
            self.cache_elements['name_not_downloaded'].set_label(cache.name)
 
724
            self.cache_elements['name_downloaded'].hide()
 
725
            self.cache_elements['name_not_downloaded'].show()
 
726
        self.cache_elements['title'].set_text(cache.title)
 
727
        self.cache_elements['type'].set_text("%s" % cache.type)
 
728
        self.cache_elements['size'].set_text("%d/5" % cache.size)
 
729
        self.cache_elements['terrain'].set_text("%.1f/5" % (cache.terrain / 10.0))
 
730
        self.cache_elements['difficulty'].set_text("%.1f/5" % (cache.difficulty / 10.0))
 
731
                
 
732
        set_page = False
 
733
                
 
734
        text_shortdesc = self.__strip_html(cache.shortdesc).strip()[:600]
 
735
        if text_shortdesc == '':
 
736
            text_shortdesc = '(Keine Kurzbeschreibung vorhanden)'
 
737
        else:
 
738
            self.cache_elements['notebook'].set_current_page(0)
 
739
            set_page = True
 
740
                        
 
741
        text_desc = self.__strip_html(cache.desc).strip()[:600]
 
742
        if text_desc == '':
 
743
            text_desc = '(Keine Beschreibung vorhanden)'
 
744
        if not set_page:
 
745
            self.cache_elements['notebook'].set_current_page(1)
 
746
                        
 
747
        text_hints = cache.hints.strip()
 
748
        if text_hints == '':
 
749
            text_hints = '(Keine Hints vorhanden)'
 
750
                        
 
751
        text_coords = 'Start: %s\n' % cache
 
752
        for w in cache.waypoints:
 
753
            if not (w['lat'] == -1 and w['lon'] == -1):
 
754
                n = geo.Coordinate(w['lat'], w['lon'])
 
755
                latlon = "%s %s" % (re.sub(r' ', '', n.get_lat(geo.Coordinate.FORMAT_DM)), re.sub(r' ', '', n.get_lon(geo.Coordinate.FORMAT_DM)))
 
756
            else:
 
757
                latlon = "???"
 
758
            text_coords += "<b>%s</b> <tt>%s</tt> <i>%s</i>\n<small>%s</small>" % (w['id'], latlon, w['name'], w['comment'])
 
759
                        
 
760
        self.cache_elements['desc'].set_text(text_desc)
 
761
        self.cache_elements['shortdesc'].set_text(text_shortdesc)
 
762
        self.cache_elements['hints'].set_text(text_hints)
 
763
        self.cache_elements['coords'].set_use_markup(True)
 
764
        self.cache_elements['coords'].set_text(text_coords)
 
765
        self.cache_elements['found'].set_active(cache.found)
 
766
        self.cache_elements['homepage'].set_uri('http://www.geocaching.com/seek/cache_details.aspx?wp=%s' % cache.name)
 
767
        self.cache_elements['log'].set_uri('http://www.geocaching.com/seek/log.aspx?wp=%s' % cache.name)
 
768
                
 
769
                
 
770
    def set_center(self, coord):
 
771
        builder.get_object("notebook_all").set_current_page(0)
 
772
        self.map_center_x, self.map_center_y = self.ts.deg2num(coord)
 
773
        self.draw_at_x = 0
 
774
        self.draw_at_y = 0
 
775
        self.__draw_map()
 
776
 
 
777
        
 
778
    def __strip_html(self, text):
 
779
        text = re.sub(r"""(?i)<img[^>]+alt=["']?([^'"> ]+)[^>]+>""", self.replace_image_tag, text)
 
780
        text = re.sub(r'<[^>]*?>', '', text)
 
781
        text = self.__decode_htmlentities(text)
 
782
        text = re.sub(r'[\n\r]+\s*[\n\r]+', '\n', text)
 
783
        return text
 
784
                
 
785
    def write_settings(self, settings):
 
786
        self.settings = settings
 
787
        self.block_changes = True
 
788
        self.set_center(geo.Coordinate(self.settings['map_position_lat'], self.settings['map_position_lon']))
 
789
 
 
790
        for x in self.SETTINGS_CHECKBOXES:
 
791
            if x in self.settings.keys():
 
792
                builder.get_object('check_%s' % x).set_active(self.settings[x])
 
793
            elif x in self.DEFAULT_SETTINGS.keys():
 
794
                builder.get_object('check_%s' % x).set_active(self.DEFAULT_SETTINGS[x])
 
795
        
 
796
        for x in self.SETTINGS_INPUTS:
 
797
            if x in self.settings.keys():
 
798
                builder.get_object('input_%s' % x).set_text(str(self.settings[x]))
 
799
            elif x in self.DEFAULT_SETTINGS.keys():
 
800
                builder.get_object('input_%s' % x).set_text(self.DEFAULT_SETTINGS[x])
 
801
                                        
 
802
        self.block_changes = False
 
803
                
 
804
    def zoom(self, direction=None):
 
805
        size = self.ts.tile_size()
 
806
        center = self.ts.num2deg(self.map_center_x - float(self.draw_at_x) / size, self.map_center_y - float(self.draw_at_y) / size)
 
807
        if direction == None:
 
808
            newzoom = self.zoom_adjustment.get_value()
 
809
        else:
 
810
            newzoom = self.ts.get_zoom() + direction
 
811
        self.ts.set_zoom(newzoom)
 
812
        self.inhibit_zoom = True
 
813
        self.zoom_adjustment.set_value(self.ts.get_zoom())
 
814
        self.inhibit_zoom = False
 
815
        self.set_center(center)