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

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

Potlatch 1.2a (source)

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