source: subversion/applications/editors/potlatch/relation.as @ 12005

Last change on this file since 12005 was 11933, checked in by richard, 11 years ago

finished Rails-friendly amf_controller. Note that this requires Tom's patched composite_primary_keys to work unless you tell Potlatch to use SQL reads

  • Property svn:executable set to *
File size: 13.8 KB
Line 
1
2        // =====================================================================================
3        // relations.as
4        // Potlatch relation-handling code
5        // =====================================================================================
6
7        // ** highlight isn't yellow if it's part of a relation (should be)
8        // ** default tags: type, name
9        // ** verboseText isn't very good
10
11        // =====================================================================================
12        // Classes - OSMRelation
13
14        function OSMRelation() {
15                this.members = new Array();
16                this.attr=new Array();
17                this.isHighlighting = false;
18                this.clean=true;                                        // altered since last upload?
19                this.uploading=false;                           // currently uploading?
20                this.locked=false;                                      // locked against upload?
21                this.version=0;
22        };
23        OSMRelation.prototype=new MovieClip();
24
25
26        // OSMRelation.verboseText - create long description of relation
27
28        OSMRelation.prototype.verboseText = function() {
29                var text = this._name+": ";
30                var type = undefined;
31                if ( this.attr['type'] ) {
32                        type = this.attr['type'];
33                        text += type + " ";
34                }
35
36                if ( type == 'route' ) {
37                        if ( this.attr['route'] )       text += this.attr['route'] + " ";
38                        if ( this.attr['network'] )     text += this.attr['network'] + " ";
39                        if ( this.attr['ref'] )         text += this.attr['ref']+" ";
40                        if ( this.attr['name'] )        text += this.attr['name']+" ";
41                        if ( this.attr['state'] )       text += "("+this.attr['state']+") ";
42                } else if ( this.attr['name'] ) text += this.attr['name'];
43
44                return text;
45        };
46
47        // OSMRelation.getType/getName - summary info used in property window
48
49        OSMRelation.prototype.getType=function() {
50                if (!this.attr['type']) { return "relation"; }
51                if (this.attr['type']=='route') {
52                        if (this.attr['network']) { return this.attr['network']; }
53                        if (this.attr['route']) { return this.attr['route']; }
54                }
55                return this.attr['type'];
56        };
57       
58        OSMRelation.prototype.getName=function() {
59                if (this.attr['ref' ]) { return this.attr['ref' ]; }
60                if (this.attr['name']) { return this.attr['name']; }
61                return '';
62        };
63
64        // OSMRelation.load - load from remote server
65
66        OSMRelation.prototype.load=function() {
67                responder = function() { };
68                responder.onResult = function(result) {
69                        _root.relsreceived+=1;
70                        var w=result[0];
71                        var i,id;
72                        _root.map.relations[w].clean=true;
73                        _root.map.relations[w].locked=false;
74                        _root.map.relations[w].attr=result[1];
75                        _root.map.relations[w].members=result[2];
76                        _root.map.relations[w].version=result[3];
77                        _root.map.relations[w].redraw();
78                };
79                remote_read.call('getrelation',responder,Math.floor(this._name));
80        };
81
82        OSMRelation.prototype.reload=function() {
83                if ( this._name < 0 )
84                        this.removeMovieClip();
85                else {
86                        _root.relsrequested++;
87                        this.load();
88                }
89        };
90
91        // OSMRelation.upload - save to remote server
92
93        OSMRelation.prototype.upload=function() {
94                putresponder=function() { };
95                putresponder.onResult=function(result) {
96                        var code=result.shift(); if (code) { handleError(code,result); return; }
97                        var nw=result[1];       // new relation ID
98                        if (result[0]!=nw) {
99                                _root.map.relations[result[0]]._name=nw;
100                        }
101                        _root.map.relations[nw].uploading=false;
102                        _root.writesrequested--;
103                };
104
105                // ways/nodes for negative IDs should have been previously put
106                // so the server should know about them
107                if (!this.uploading && !this.locked && !_root.sandbox ) {
108                        this.uploading=true;
109                        _root.writesrequested++;
110                        remote_write.call('putrelation', putresponder,
111                                _root.usertoken, _root.changeset,
112                                Math.floor(this._name),
113                                this.attr, this.members, 1);
114                        this.clean=true;
115                }
116        };
117
118
119        // OSMRelation.redraw           - show on map
120        // OSMRelation.drawPoint
121        // OSMRelation.setHighlight
122
123        OSMRelation.prototype.redraw=function() {
124                this.createEmptyMovieClip("line",1);                                    // clear line
125                var linewidth=Math.max(_root.linewidth*3,10);
126                var linealpha= this.isHighlighting ? 75 : 50;
127                var c = this.isHighlighting ? 0xff8800 : 0x8888ff;
128
129                var type = this.getType();
130                if ( !this.isHighlighting ) {
131                        if ( relcolours[type] != undefined ) {
132                                c = relcolours[type]; linewidth = relwidths[type]; linealpha = relalphas[type];
133                        }
134                }
135                this.line.lineStyle(linewidth,c,linealpha,false,"none");
136
137                var ms = this.members;
138                for ( var m = 0; m < ms.length; m++ ) {
139                        if ( ms[m][0] == 'way' && _root.map.ways[ms[m][1]] ) {
140                                var way = _root.map.ways[ms[m][1]];
141               
142                                this.line.moveTo(way.path[0].x,way.path[0].y);
143                                for (var i=1; i<way.path.length; i+=1) {
144                                        this.line.lineTo(way.path[i].x,way.path[i].y);
145                                }
146                        } else if ( ms[m][0] == 'node' && _root.map.pois[ms[m][1]] ) {
147                                var poi = _root.map.pois[ms[m][1]];
148                                this.drawPoint(poi._x, poi._y);
149                        } else if ( ms[m][0] == 'node' ) {
150                                this.drawPoint(nodes[ms[m][1]].x,nodes[ms[m][1]].y);
151                        }
152                }
153        };
154
155        OSMRelation.prototype.drawPoint = function(x, y) {
156                var z = Math.max(100/Math.pow(2,_root.scale-13),6.25)/30;
157                this.line.moveTo(x-z,y-z);
158                this.line.lineTo(x-z,y+z);
159                this.line.lineTo(x+z,y+z);
160                this.line.lineTo(x+z,y-z);
161                this.line.lineTo(x-z,y-z);
162        };
163
164        OSMRelation.prototype.setHighlight = function(highlight) {
165                if ( this.isHighlighting == highlight )
166                        return;
167
168                this.isHighlighting = highlight;
169                this.redraw();
170        };
171
172        // ---- Editing and information functions
173
174        OSMRelation.prototype.getWayRole=function(way_id) {
175                return this.getRole('way', way_id);
176        };
177
178        OSMRelation.prototype.getRole=function(type, id) {
179                var ws = this.members;
180                var role;
181                for ( var m = 0; m < ws.length && role == undefined; m++ ) {
182                        if ( ws[m][0] == type && ws[m][1] == id ) {
183                                role = ws[m][2];
184                        }
185                }
186                return role;
187        };
188
189        OSMRelation.prototype.renumberMember=function(type, id, new_id) {
190                var ws = this.members;
191                var set = false;
192                for ( var m = 0; m < ws.length && !set; m++ ) {
193                        if ( ws[m][0] == type && ws[m][1] == id ) {
194                                ws[m][1] = new_id;
195                                set = true;
196                        }
197                }
198        };
199
200        OSMRelation.prototype.setRole=function(type, id, role) {
201                var ws = this.members;
202                var set = false;
203                var diff = true;
204                for ( var m = 0; m < ws.length && !set; m++ ) {
205                        if ( ws[m][0] == type && ws[m][1] == id ) {
206                                diff = (ws[m][2] != role);
207                                ws[m][2] = role;
208                                set = true;
209                        }
210                }
211                if ( !set )
212                        this.members.push([type, id, role]);
213                if ( diff ) {
214                        this.clean = false;
215                        this.redraw();
216                }
217        };
218
219        OSMRelation.prototype.setWayRole=function(way_id, role) {
220                this.setRole('way', way_id, role);
221        };
222
223        OSMRelation.prototype.hasWay=function(way_id) {
224                var role = this.getWayRole(way_id);
225                return role == undefined ? false : true;
226        };
227
228        OSMRelation.prototype.getNodeRole=function(node_id) {
229                return this.getRole('node', node_id);
230        };
231
232        OSMRelation.prototype.setNodeRole=function(node_id, role) {
233                this.setRole('node', node_id, role);
234        };
235
236        OSMRelation.prototype.hasNode=function(node_id) {
237                var role = this.getNodeRole(node_id);
238                return role == undefined ? false : true;
239        };
240
241        OSMRelation.prototype.removeMember=function(type, id) {
242                this.removeMemberDirty(type, id, true);
243        };
244
245        OSMRelation.prototype.removeMemberDirty=function(type, id, markDirty) {
246                var ws = this.members;
247                for (var m in ws) {
248                        if ( ws[m][0] == type && ws[m][1] == id ) {
249                                ws.splice(m, 1);
250                                if ( markDirty )
251                                        this.clean = false;
252                                this.redraw();
253                        }
254                }
255        };
256
257        OSMRelation.prototype.removeWay=function(way_id) {
258                this.removeMember('way', way_id);
259        };
260
261        OSMRelation.prototype.removeNode=function(node_id) {
262                this.removeMember('node', node_id);
263        };
264
265        // ----- UI
266
267        OSMRelation.prototype.editRelation = function() {
268                var rel = this;
269                var completeEdit = function() {
270                        rel.setHighlight(false);
271                        _root.panel.properties.reinit();
272                };
273
274                rel.setHighlight(true);
275                _root.panel.properties.enableTabs(false);
276               
277                _root.windows.attachMovie("modal","relation",++windowdepth);
278                _root.windows.relation.init(402, 255, ["OK"], completeEdit);
279                var z=5;
280                var box=_root.windows.relation.box;
281               
282                box.createTextField("title",z++,7,7,400-14,20);
283                with (box.title) {
284                        type='dynamic';
285                        text=this._name; setTextFormat(plainText);
286                        setNewTextFormat(boldText); replaceSel("Relation ");
287                }
288
289                // Light grey background
290                box.createEmptyMovieClip('lightgrey',z++);
291                with (box.lightgrey) {
292                        beginFill(0xF3F3F3,100);
293                        moveTo(10,30); lineTo(392,30);
294                        lineTo(392,213); lineTo(10,213);
295                        lineTo(10,30); endFill();
296                };
297
298                box.attachMovie("propwindow","properties",z++);
299                with (box.properties) { _x=14; _y=34; };
300                _root.editingrelation = this;
301                box.properties.ynumber = 9;
302                box.properties.init("relation",2,9);
303
304                box.attachMovie("newattr", "newattr", z++);
305                with ( box.newattr ) {
306                        _x = 400-16; _y = 18;
307                }
308                box.newattr.onRelease =function() { box.properties.enterNewAttribute(); };
309                box.newattr.onRollOver=function() { setFloater(iText("Add a new tag",'tip_addtag')); };
310                box.newattr.onRollOut =function() { clearFloater(); };
311        };
312
313        Object.registerClass("relation",OSMRelation);
314
315
316        // ===============================
317        // Support functions for relations
318
319        function redrawRelationsForMember(type, id) {
320                var rels = type == 'way' ? getRelationsForWay(id) : getRelationsForNode(id);
321                for ( r in rels )
322                        _root.map.relations[rels[r]].redraw();
323        }
324
325        // the server-side handles removing a deleted object from a relation
326        // but we need to keep the client side in sync
327        function memberDeleted(type, id) {
328                var rels = _root.map.relations;
329                for ( r in rels )
330                        rels[r].removeMemberDirty(type, id, false);
331        }
332
333        function renumberMemberOfRelation(type, id, new_id) {
334                var rels = _root.map.relations;
335                for ( r in rels )
336                        rels[r].renumberMember(type, id, new_id);
337        }
338
339        function getRelationsForWay(way) {
340                var rels = [];
341                var z = _root.map.relations;
342                for ( var i in z ) {
343                        if ( z[i].hasWay(way) )
344                                rels.push(i);
345                }
346                return rels;
347        }
348
349        function getRelationsForNode(node) {
350                var rels = [];
351                var z = _root.map.relations;
352                for ( var i in z ) {
353                        if ( z[i].hasNode(node) )
354                                rels.push(i);
355                }
356                return rels;
357        }
358
359        function uploadDirtyRelations() {
360                var rs = _root.map.relations;
361                for ( var i in rs ) {
362                        if ( !rs[i].clean ) {
363                                rs[i].upload();
364                        }
365                }
366        }
367
368        function revertDirtyRelations() {
369                var rs = _root.map.relations;
370                for ( var i in rs ) {
371                        if ( !rs[i].clean ) {
372                                rs[i].reload();
373                        }
374                }
375        }
376
377        // addToRelation - add a way/point to a relation
378        //                                 called when user clicks '+' relation button
379
380        function addToRelation() {
381                var proptype = _root.panel.properties.proptype;
382                var type, id;
383                switch (proptype) {
384                        case 'way':             type='way' ; id=wayselected; break;
385                        case 'point':   type='node'; id=_root.ws.path[_root.pointselected].id; break;
386                        case 'POI':             type='node'; id=poiselected; break;
387                }
388                if ( type == undefined || id == undefined ) return;
389
390                var completeAdd = function(button) {
391
392                        if ( button != iText("Ok",'ok') ) return false;
393
394                        var box=_root.windows.relation.box;
395                        var radio=box.reloption.selected;
396                        var keepDialog = false;
397
398                        switch (radio) {
399                                case 1: // Add to an existing relation
400                                                var selected=box.addroute_menu.selected;
401                                                var rs=_root.map.relations;
402                                                var i=0;
403                                                for (var r in rs) {
404                                                        if (selected==i) { 
405                                                        rs[r].setRole(type, id, ''); }
406                                                        i++;
407                                                }
408                                                break;
409                                case 2: // Create a new relation
410                                                var nid = newrelid--;
411                                                _root.map.relations.attachMovie("relation",nid,++reldepth);
412                                                _root.map.relations[nid].setRole(type, id, '');
413                                                _root.map.relations[nid].attr['type'] = undefined;
414                                                _root.windows.relation.remove(); keepDialog = true;
415                                                _root.map.relations[nid].editRelation();
416                                                break;
417                                case 3: // Find a relation
418                                                keepDialog=true;
419                                                if (box.search.text=='') { break; }
420                                                findresponder=function() {};
421                                                findresponder.onResult=function(rellist) {
422                                                        for (r in rellist) {
423                                                                var w=rellist[r][0];
424                                                                if (!_root.map.relations[w]) {
425                                                                        _root.map.relations.attachMovie("relation",w,++reldepth);
426                                                                        _root.map.relations[w].attr=rellist[r][1];
427                                                                        _root.map.relations[w].members=rellist[r][2];
428                                                                        _root.relcount++;
429                                                                }
430                                                        }
431                                                        createRelationMenu(_root.windows.relation.box,20);
432                                                        _root.windows.relation.box.search.text='';
433                                                };
434                                                remote_read.call('findrelations',findresponder,box.search.text);
435                                                break;
436                        }
437                        _root.panel.properties.reinit();
438                        if (keepDialog) { _root.panel.properties.enableTabs(false); }
439                        return keepDialog;
440                };
441
442                // Create dialogue
443
444                _root.panel.properties.enableTabs(false);
445                _root.windows.attachMovie("modal","relation",++windowdepth);
446                _root.windows.relation.init(300, 150, [iText("Cancel",'cancel'), iText("Ok",'ok')], completeAdd);
447                var z = 5;
448                var box = _root.windows.relation.box;
449               
450                box.createTextField("title",z++,7,7,300-14,20);
451                box.title.text = iText("Add $1 to a relation",'prompt_addtorelation',proptype);
452                with (box.title) {
453                        wordWrap=true;
454                        setTextFormat(boldText);
455                        selectable=false; type='dynamic';
456                }
457               
458                box.createTextField("instr",z++,7,30,300-14,40);
459
460                // Create radio buttons and menu
461
462                box.attachMovie("radio","reloption",z++);
463                box.reloption.addButton(10,35,iText("Add to an existing relation",'existingrelation'));
464                box.reloption.addButton(10,75,iText("Create a new relation",'createrelation'));
465                box.reloption.addButton(10,95,iText("Find a relation containing",'findrelation'));
466
467                createRelationMenu(box,20);
468
469                var w=box.reloption[3].prompt._width+25;
470                box.createTextField("search",z++,w,90,290-w,17);
471                box.search.setNewTextFormat(plainSmall);
472                box.search.type='input';
473                box.search.backgroundColor=0xDDDDDD;
474                box.search.background=true;
475                box.search.border=true;
476                box.search.borderColor=0xFFFFFF;
477                box.search.onSetFocus=function() { this._parent.reloption.select(3); };
478        }
479
480        function createRelationMenu(box,z) {
481                var relations=new Array();
482                var rs = _root.map.relations;
483                for ( var r in rs ) {
484                        relations.push(rs[r].verboseText());
485                }
486
487                if (relations.length==0) {
488                        relations.push(iText("No relations in current area",'norelations'));
489                        box.reloption.disable(1);
490                        box.reloption.select(2);
491                } else {
492                        box.reloption.enable(1);
493                        box.reloption.select(1);
494                }
495                box.attachMovie("menu", "addroute_menu", z);
496                box.addroute_menu.init(25, 50, 0, relations,
497                                        iText('Add to the chosen route','tip_selectrelation'),null, null, 268);
498        }
Note: See TracBrowser for help on using the repository browser.