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

Last change on this file since 14979 was 14830, checked in by richard, 10 years ago

Potlatch 0.11a

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