changeset 1051:981339d774b8

merged stammdatengrids to default.
author Raimund Renkert <raimund.renkert@intevation.de>
date Tue, 01 Mar 2016 14:12:39 +0100
parents eacf25f071c0 (current diff) e0b5e64928c9 (diff)
children d2165ba7e8f1
files app.js app/controller/Filter.js app/controller/Ort.js app/controller/form/Ort.js app/controller/grid/Ort.js app/controller/grid/Ortszuordnung.js app/model/DatensatzErzeuger.js app/model/MessprogrammKategorie.js app/model/Messung.js app/model/Ort.js app/model/Probenehmer.js app/view/form/Ortszuordnung.js app/view/grid/DatensatzErzeuger.js app/view/grid/MessprogrammKategorie.js app/view/grid/Ortszuordnung.js app/view/grid/Probenehmer.js app/view/panel/Map.js app/view/panel/Ort.js app/view/widget/DynamicGrid.js app/view/window/OrtCreate.js app/view/window/OrtEdit.js app/view/window/ProbeEdit.js resources/i18n/Lada_de-DE.properties
diffstat 29 files changed, 1080 insertions(+), 740 deletions(-) [+]
line wrap: on
line diff
--- a/app.js	Mon Feb 29 15:10:17 2016 +0100
+++ b/app.js	Tue Mar 01 14:12:39 2016 +0100
@@ -23,6 +23,7 @@
     // Setting up translations. This is done using a ext-plgin which can be
     // found on https://github.com/elmasse/Ext.i18n.Bundle
     requires: [
+        'Lada.view.Viewport',
         'Lada.override.Table',
         'Lada.override.RestProxy',
         'Lada.override.RowEditor',
@@ -30,6 +31,13 @@
         'Lada.override.JSON',
         'Ext.i18n.Bundle',
         'Ext.layout.container.Column',
+        'Lada.store.Deskriptoren',
+        'Lada.store.Ortszuordnung',
+        'Lada.store.Messungen',
+        'Lada.store.Zusatzwerte',
+        'Lada.store.Status',
+        'Lada.store.Messwerte',
+        'Lada.store.MKommentare',
         'Lada.store.Datenbasis',
         'Lada.store.Messeinheiten',
         'Lada.store.Messgroessen',
@@ -136,7 +144,8 @@
             storeId: 'netzbetreiber'
         });
         Ext.create('Lada.store.Orte', {
-            storeId: 'orte'
+            storeId: 'orte',
+            defaultPageSize: 0
         });
         Ext.create('Lada.store.Pflichtmessgroessen', {
             storeId: 'pflichtmessgroessen'
@@ -216,21 +225,22 @@
     controllers: [
         'Lada.controller.Filter',
         'Lada.controller.ModeSwitcher',
+        'Lada.controller.Map',
+        'Lada.controller.Ort',
         'Lada.controller.grid.ProbeList',
         'Lada.controller.grid.MessprogrammeList',
         'Lada.controller.grid.Datensatzerzeuger',
         'Lada.controller.grid.Probenehmer',
         'Lada.controller.form.Probe',
         'Lada.controller.form.Messung',
-        'Lada.controller.form.Ort',
-        'Lada.controller.grid.Ort',
         'Lada.controller.grid.Probenzusatzwert',
         'Lada.controller.grid.PKommentar',
         'Lada.controller.grid.MKommentar',
         'Lada.controller.grid.Messung',
         'Lada.controller.grid.Messwert',
         'Lada.controller.grid.Status',
-        'Lada.controller.Map',
+        'Lada.controller.grid.Ortszuordnung',
+        'Lada.controller.form.Ortszuordnung',
         'Lada.controller.form.Location',
         'Lada.controller.form.Messprogramm',
         'Lada.controller.grid.Messmethode',
--- a/app/controller/Filter.js	Mon Feb 29 15:10:17 2016 +0100
+++ b/app/controller/Filter.js	Tue Mar 01 14:12:39 2016 +0100
@@ -15,6 +15,8 @@
 
     requires: [
         'Lada.view.widget.Messstelle',
+        'Lada.view.grid.MessprogrammeList',
+        'Lada.view.grid.ProbeList',
         'Lada.view.window.FilterManagement',
         'Lada.view.widget.Umwelt'
     ],
@@ -147,7 +149,7 @@
                     resultGrid = Ext.create('Lada.view.grid.DatensatzErzeuger');
                     break;
                 case 'ort':
-                    resultGrid = Ext.create('Lada.view.grid.Orte');
+                    resultGrid = Ext.create('Lada.view.panel.Ort');
                     break;
                 case 'probenehmer':
                     resultGrid = Ext.create('Lada.view.grid.Probenehmer');
@@ -344,6 +346,11 @@
         if (store) {
             store.addListener('beforeload', this.loadingAnimationOn, resultGrid);
             store.addListener('load', this.loadingAnimationOff, resultGrid);
+            if (type === 'ort') {
+                var panel = resultGrid.up('ortpanel');
+                store.addListener('load', panel.down('map').addLocations, panel.down('map'));
+                panel.connectListeners();
+            }
 
             resultGrid.setStore(store);
             //TODO: Check if this is still necessary, as a Grid exists
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/app/controller/Ort.js	Tue Mar 01 14:12:39 2016 +0100
@@ -0,0 +1,123 @@
+/**
+ *
+ */
+Ext.define('Lada.controller.Ort', {
+    extend: 'Ext.app.Controller',
+
+    /**
+     * @private
+     * Initialize the controller.
+     */
+    init: function() {
+        var me = this;
+        this.control({
+            'ortpanel button[action=addMap]': {
+                click: me.addFeature
+            },
+            'ortpanel button[action=add]': {
+                click: me.addRecord
+            },
+            'ortpanel button[action=delete]': {
+                click: me.deleteItem
+            },
+            'ortpanel ortstammdatengrid': {
+                edit: me.gridSave,
+                canceledit: me.cancelEdit,
+                select: me.activateButtons,
+                deselect: me.deactivateButtons
+            }
+        });
+    },
+
+    addFeature: function(button) {
+        console.log('add feature');
+    },
+
+    addRecord: function(button) {
+        console.log('add record');
+    },
+
+    deleteItem: function(button) {
+        console.log('delete item');
+    },
+
+    /**
+     * This function is called when the grids roweditor saves
+     * the record.
+     * On success it refreshes the windows which contains the grid
+     * On failure it displays a message
+     */
+    gridSave: function(editor, context) {
+        var i18n = Lada.getApplication().bundle;
+        context.record.save({
+            success: function(record, response) {
+                //Do Nothing
+            },
+            failure: function(record, response) {
+              var json = response.request.scope.reader.jsonData;
+              if (json) {
+                if (json.message){
+                    Ext.Msg.alert(i18n.getMsg('err.msg.save.title')
+                        +' #'+json.message,
+                        i18n.getMsg(json.message));
+                   } else {
+                         Ext.Msg.alert(i18n.getMsg('err.msg.save.title'),
+                            i18n.getMsg('err.msg.generic.body'));
+                   }
+              }
+            }
+        });
+    },
+
+    /**
+     * When the edit was canceled,
+     * the empty row might have been created by the roweditor is removed
+     */
+    cancelEdit: function(editor, context) {
+        if (!context.record.get('id') ||
+            context.record.get('id') === '') {
+            editor.getCmp().store.remove(context.record);
+        }
+        context.grid.getSelectionModel().deselect(context.record);
+    },
+    /**
+     * Toggles the buttons in the toolbar
+     **/
+    activateButtons: function(rowModel, record) {
+        var panel = rowModel.view.up('ortpanel');
+        this.buttonToggle(true, panel);
+    },
+
+    /**
+     * Toggles the buttons in the toolbar
+     **/
+    deactivateButtons: function(rowModel, record) {
+        var panel = rowModel.view.up('ortpanel');
+        // Only disable buttons when nothing is selected
+        if (rowModel.selected.items == 0) {
+            this.buttonToggle(false, panel);
+        }
+    },
+
+    /**
+     * Enables/Disables a set of buttons
+     **/
+    buttonToggle: function(enabled, panel) {
+        if (!enabled &&
+            panel.down('button[action=delete]')) {
+            panel.down('button[action=delete]').disable();
+        }
+        else {
+            if (panel.down('ortstammdatengrid').getPlugin('rowedit') &&
+                !panel.down('ortstammdatengrid').getPlugin('rowedit').editing &&
+                panel.down('button[action=delete]')) {
+            //only enable buttons, when grid is not beeing edited
+                panel.down('button[action=delete]').enable();
+            }
+            //else turn them off again!
+            else if (panel.down('button[action=delete]')) {
+                panel.down('button[action=delete]').disable();
+            }
+        }
+    }
+});
--- a/app/controller/form/Ort.js	Mon Feb 29 15:10:17 2016 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,135 +0,0 @@
-/* Copyright (C) 2013 by Bundesamt fuer Strahlenschutz
- * Software engineering by Intevation GmbH
- *
- * This file is Free Software under the GNU GPL (v>=3)
- * and comes with ABSOLUTELY NO WARRANTY! Check out
- * the documentation coming with IMIS-Labordaten-Application for details.
- */
-
-/*
- * This is a controller for an Ort Form
- */
-Ext.define('Lada.controller.form.Ort', {
-    extend: 'Ext.app.Controller',
-
-    /**
-     * Initialize the Controller with 4 listeners
-     */
-    init: function() {
-        this.control({
-            'ortform button[action=save]': {
-                click: this.save
-            },
-            'ortform button[action=discard]': {
-                click: this.discard
-            },
-            'ortform': {
-                dirtychange: this.dirtyForm
-            },
-            'ortform combobox[name=ort]': {
-                select: this.updateDetails
-            }
-        });
-    },
-
-     /**
-      * The save function saves the content of the Ort form.
-      * On success it will reload the Store,
-      * on failure, it will display an Errormessage
-      */
-     save: function(button) {
-        var formPanel = button.up('ortform');
-        var data = formPanel.getForm().getFieldValues(true);
-        for (var key in data) {
-            formPanel.getForm().getRecord().set(key, data[key]);
-        }
-        if (!formPanel.getForm().getRecord().get('letzteAenderung')) {
-            formPanel.getForm().getRecord().data.letzteAenderung = new Date();
-        }
-        formPanel.getForm().getRecord().save({
-            success: function(record, response) {
-                var json = Ext.decode(response.response.responseText);
-                if (json) {
-                    button.setDisabled(true);
-                    button.up('toolbar').down('button[action=discard]')
-                        .setDisabled(true);
-                    formPanel.clearMessages();
-                    formPanel.setRecord(record);
-                    formPanel.setMessages(json.errors, json.warnings);
-                    formPanel.up('window').grid.store.reload();
-                }
-            },
-            failure: function(record, response) {
-                button.setDisabled(true);
-                button.up('toolbar').down('button[action=discard]')
-                    .setDisabled(true);
-                formPanel.getForm().loadRecord(formPanel.getForm().getRecord());
-                var json = response.request.scope.reader.jsonData;
-                if (json) {
-                    if(json.errors.totalCount > 0 || json.warnings.totalCount > 0){
-                        formPanel.setMessages(json.errors, json.warnings);
-                    }
-
-                    if(json.message){
-                        Ext.Msg.alert(Lada.getApplication().bundle.getMsg('err.msg.save.title')
-                            +' #'+json.message,
-                            Lada.getApplication().bundle.getMsg(json.message));
-                    } else {
-                         Ext.Msg.alert(Lada.getApplication().bundle.getMsg('err.msg.save.title'),
-                            Lada.getApplication().bundle.getMsg('err.msg.generic.body'));
-                    }
-                } else {
-                    Ext.Msg.alert(Lada.getApplication().bundle.getMsg('err.msg.save.title'),
-                        Lada.getApplication().bundle.getMsg('err.msg.response.body'));
-                }
-            }
-        });
-    },
-
-   /**
-    * The discard function resets the Location form
-    * to its original state.
-    */
-   discard: function(button) {
-        var formPanel = button.up('form');
-        formPanel.getForm().loadRecord(formPanel.getForm().getRecord());
-        var win = button.up('window');
-        var id = formPanel.getForm().getRecord().get('ort');
-        var toLoad = Ext.data.StoreManager.get('locations').getById(id);
-        win.down('locationform').setRecord(toLoad);
-        win.down('map').selectFeature(id);
-    },
-
-     /**
-      * The dirtyForm function enables or disables the save and discard
-      * button which are present in the toolbar of the form.
-      * The Buttons are only active if the content of the form was altered
-      * (the form is dirty).
-      */
-    dirtyForm: function(form, dirty) {
-        if (dirty) {
-            form.owner.down('button[action=save]').setDisabled(false);
-            form.owner.down('button[action=discard]').setDisabled(false);
-        }
-        else {
-            form.owner.down('button[action=save]').setDisabled(true);
-            form.owner.down('button[action=discard]').setDisabled(true);
-        }
-    },
-
-    /**
-     *  updateDetails is used when a value is selected within the ort combobox
-     *  When this function is called, the map element within the window
-     *  which is embedding this form is updated.
-     */
-    updateDetails: function(combobox, record) {
-        var win = combobox.up('window');
-        var details = win.down('locationform');
-        var id = record[0].get('id');
-        if (details) {
-            var toLoad = Ext.data.StoreManager.get('locations').getById(id);
-            win.down('locationform').setRecord(toLoad);
-            win.down('map').selectFeature(id);
-        }
-    }
-});
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/app/controller/form/Ortszuordnung.js	Tue Mar 01 14:12:39 2016 +0100
@@ -0,0 +1,163 @@
+/* Copyright (C) 2013 by Bundesamt fuer Strahlenschutz
+ * Software engineering by Intevation GmbH
+ *
+ * This file is Free Software under the GNU GPL (v>=3)
+ * and comes with ABSOLUTELY NO WARRANTY! Check out
+ * the documentation coming with IMIS-Labordaten-Application for details.
+ */
+
+/*
+ * This is a controller for an Ortszuordnung Form
+ */
+Ext.define('Lada.controller.form.Ortszuordnung', {
+    extend: 'Ext.app.Controller',
+
+    /**
+     * Initialize the Controller with 4 listeners
+     */
+    init: function() {
+        this.control({
+            'ortszuordnungform button[action=setOrt]': {
+                toggle: this.pickOrt
+            },
+            'ortszuordnungform button[action=save]': {
+                click: this.save
+            },
+            'ortszuordnungform button[action=discard]': {
+                click: this.discard
+            },
+            'ortszuordnungform': {
+                dirtychange: this.dirtyForm
+            }
+        });
+    },
+
+     /**
+      * The save function saves the content of the Ort form.
+      * On success it will reload the Store,
+      * on failure, it will display an Errormessage
+      */
+     save: function(button) {
+
+        var formPanel = button.up('ortszuordnungform');
+
+        //try to disable ortPickerButton:
+        try {
+           formPanel.down('button[action=setOrt]').toggle(false);
+        }
+        catch (e) {
+        }
+
+        var data = formPanel.getForm().getFieldValues(true);
+        var i18n = Lada.getApplication().bundle;
+        for (var key in data) {
+            formPanel.getForm().getRecord().set(key, data[key]);
+        }
+        if (!formPanel.getForm().getRecord().get('letzteAenderung')) {
+            formPanel.getForm().getRecord().data.letzteAenderung = new Date();
+        }
+        formPanel.getForm().getRecord().save({
+            success: function(record, response) {
+                var json = Ext.decode(response.response.responseText);
+                if (json) {
+                    button.setDisabled(true);
+                    button.up('toolbar').down('button[action=discard]')
+                        .setDisabled(true);
+                    formPanel.clearMessages();
+                    formPanel.setRecord(record);
+                    formPanel.setMessages(json.errors, json.warnings);
+                    formPanel.up('window').grid.store.reload();
+                }
+                //try to refresh the Grid of the Probe
+                try {
+                    formPanel.up('window').parentWindow
+                        .down('ortszuordnunggrid').store.reload();
+                }
+                catch (e) {
+
+                }
+            },
+            failure: function(record, response) {
+                button.setDisabled(true);
+                button.up('toolbar').down('button[action=discard]')
+                    .setDisabled(true);
+                formPanel.getForm().loadRecord(formPanel.getForm().getRecord());
+                var json = response.request.scope.reader.jsonData;
+                if (json) {
+                    if(json.errors.totalCount > 0 || json.warnings.totalCount > 0){
+                        formPanel.setMessages(json.errors, json.warnings);
+                    }
+
+                    if(json.message){
+                        Ext.Msg.alert(i18n.getMsg('err.msg.save.title')
+                            +' #'+json.message,
+                            i18n.getMsg(json.message));
+                    } else {
+                         Ext.Msg.alert(i18n.getMsg('err.msg.save.title'),
+                            i18n.getMsg('err.msg.generic.body'));
+                    }
+                } else {
+                    Ext.Msg.alert(i18n.getMsg('err.msg.save.title'),
+                        i18n.getMsg('err.msg.response.body'));
+                }
+            }
+        });
+    },
+
+    /**
+     * The discard function resets the Location form
+     * to its original state.
+     */
+    discard: function(button) {
+        var formPanel = button.up('form');
+        var record = formPanel.getForm().getRecord();
+        formPanel.getForm().loadRecord(record);
+        try {
+            formPanel.refreshOrt(record.get('ortId'));
+            formPanel.down('button[action=setOrt]').toggle(false);
+        }
+        catch (e) {
+        }
+        //set undirty.
+        formPanel.fireEvent('dirtychange', formPanel.getForm(), false);
+    },
+
+    /**
+     * When the button is Active, a Record can be selected.
+     * If the Record was selected from a grid this function
+     *  sets the ortzuordnung.
+     * TODO: Check if the selected Record is a ORT
+     * TODO: Enable picking from Maps
+     */
+     pickOrt: function(button, pressed, opts) {
+        var i18n = Lada.getApplication().bundle;
+        var oForm = button.up('form');
+        var osg = button.up('window').down('ortstammdatengrid');
+        if (button.pressed) {
+            button.setText(i18n.getMsg('ortszuordnung.form.setOrt.pressed'));
+            osg.addListener('select',oForm.setOrt, oForm);
+        }
+        else {
+            button.setText(i18n.getMsg('ortszuordnung.form.setOrt'));
+            osg.removeListener('select',oForm.setOrt, oForm);
+        }
+     },
+
+
+    /**
+     * The dirtyForm function enables or disables the save and discard
+     * button which are present in the toolbar of the form.
+     * The Buttons are only active if the content of the form was altered
+     * (the form is dirty).
+     */
+    dirtyForm: function(form, dirty) {
+        if (dirty) {
+            form.owner.down('button[action=save]').setDisabled(false);
+            form.owner.down('button[action=discard]').setDisabled(false);
+        }
+        else {
+            form.owner.down('button[action=save]').setDisabled(true);
+            form.owner.down('button[action=discard]').setDisabled(true);
+        }
+    }
+});
--- a/app/controller/grid/Ort.js	Mon Feb 29 15:10:17 2016 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,103 +0,0 @@
-/* Copyright (C) 2013 by Bundesamt fuer Strahlenschutz
- * Software engineering by Intevation GmbH
- *
- * This file is Free Software under the GNU GPL (v>=3)
- * and comes with ABSOLUTELY NO WARRANTY! Check out
- * the documentation coming with IMIS-Labordaten-Application for details.
- */
-
-/**
- * This is a controller for a grid of Orte
- */
-Ext.define('Lada.controller.grid.Ort', {
-    extend: 'Ext.app.Controller',
-
-    requires: [
-        'Lada.view.window.OrtEdit',
-        'Lada.view.window.OrtCreate'
-    ],
-
-    /**
-     * Inhitialize the controller
-     * It has 3 listeners
-     */
-    init: function() {
-        this.control({
-            'ortgrid': {
-                itemdblclick: this.open
-            },
-            'ortgrid button[action=add]': {
-                click: this.add
-            },
-            'ortgrid button[action=delete]': {
-                click: this.remove
-            }
-        });
-    },
-
-    /**
-     * When open is called, a {@link Lada.view.window.OrtEdit}
-     * is created which allows to edit the Orte
-     */
-    open: function(grid, record) {
-        var probe = grid.up('window').record;
-        var win = Ext.create('Lada.view.window.OrtEdit', {
-            parentWindow: grid.up('window'),
-            probe: probe,
-            record: record,
-            grid: grid
-        });
-        win.show();
-        win.initData();
-    },
-
-    /**
-     * This function adds a new row to add an Ort
-     */
-    add: function(button) {
-        var probe = button.up('window').record;
-        var win = Ext.create('Lada.view.window.OrtCreate', {
-            record: probe,
-            grid: button.up('ortgrid')
-        });
-        win.show();
-        win.initData();
-    },
-
-    /**
-     * A Ort-row can be removed from the grid with the remove
-     * function. It asks the user for confirmation
-     * If the removal was confirmed, it reloads the parent window on success,
-     * on failure, an error message is shown.
-     */
-    remove: function(button) {
-        var grid = button.up('grid');
-        var selection = grid.getView().getSelectionModel().getSelection()[0];
-        Ext.MessageBox.confirm('Ortsangabe löschen', 'Sind Sie sicher?', function(btn) {
-            if (btn === 'yes') {
-                selection.destroy({
-                    success: function() {
-                        button.up('window').initData();
-                    },
-                    failure: function(request, response) {
-                        var json = response.request.scope.reader.jsonData;
-                        if (json) {
-                            if (json.message){
-                                Ext.Msg.alert(Lada.getApplication().bundle.getMsg('err.msg.delete.title')
-                                    +' #'+json.message,
-                                    Lada.getApplication().bundle.getMsg(json.message));
-                            } else {
-                                Ext.Msg.alert(Lada.getApplication().bundle.getMsg('err.msg.delete.title'),
-                                    Lada.getApplication().bundle.getMsg('err.msg.generic.body'));
-                            }
-                        } else {
-                            Ext.Msg.alert(Lada.getApplication().bundle.getMsg('err.msg.delete.title'),
-                                Lada.getApplication().bundle.getMsg('err.msg.response.body'));
-                        }
-                    }
-                });
-            }
-        });
-        grid.down('button[action=delete]').disable();
-    }
-});
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/app/controller/grid/Ortszuordnung.js	Tue Mar 01 14:12:39 2016 +0100
@@ -0,0 +1,107 @@
+/* Copyright (C) 2013 by Bundesamt fuer Strahlenschutz
+ * Software engineering by Intevation GmbH
+ *
+ * This file is Free Software under the GNU GPL (v>=3)
+ * and comes with ABSOLUTELY NO WARRANTY! Check out
+ * the documentation coming with IMIS-Labordaten-Application for details.
+ */
+
+/**
+ * This is a controller for a grid of Orte
+ */
+Ext.define('Lada.controller.grid.Ortszuordnung', {
+    extend: 'Ext.app.Controller',
+
+    requires: [
+        'Lada.view.window.Ortszuordnung'
+    ],
+
+    /**
+     * Inhitialize the controller
+     * It has 3 listeners
+     */
+    init: function() {
+        this.control({
+            'ortszuordnunggrid': {
+                itemdblclick: this.open
+            },
+            'ortszuordnunggrid button[action=add]': {
+                click: this.add
+            },
+            'ortszuordnunggrid button[action=delete]': {
+                click: this.remove
+            }
+        });
+    },
+
+    /**
+     * When open is called, a {@link Lada.view.window.Ortszuordnung}
+     * is created which allows to edit the Orte
+     */
+    open: function(grid, record) {
+        var probe = grid.up('window').record;
+        var win = Ext.create('Lada.view.window.Ortszuordnung', {
+            parentWindow: grid.up('window'),
+            probe: grid.up('window').down('probeform').record,
+            record: record,
+            grid: grid
+        });
+        win.show();
+        win.initData();
+    },
+
+    /**
+     * This function adds a new row to add an Ort
+     */
+    add: function(button) {
+        var probe = button.up('window').record;
+        var win = Ext.create('Lada.view.window.Ortszuordnung', {
+            parentWindow: button.up('window'),
+            probe: probe,
+            record: null,
+            grid: button.up('ortszuordnung')
+        });
+        win.show();
+        win.initData();
+    },
+
+    /**
+     * A Ort-row can be removed from the grid with the remove
+     * function. It asks the user for confirmation
+     * If the removal was confirmed, it reloads the parent window on success,
+     * on failure, an error message is shown.
+     */
+    remove: function(button) {
+        var grid = button.up('grid');
+        var selection = grid.getView().getSelectionModel().getSelection()[0];
+        var i18n = Lada.getApplication().bundle;
+        Ext.MessageBox.confirm(i18n.getMsg('delete'), i18n.getMsg('confirmation.question'),
+                                function(btn) {
+                if (btn === 'yes') {
+                selection.destroy({
+                    success: function() {
+                        button.up('window').initData();
+                    },
+                    failure: function(request, response) {
+                        var i18n = Lada.getApplication().bundle;
+                        var json = response.request.scope.reader.jsonData;
+                        if (json) {
+                            if (json.message){
+                                Ext.Msg.alert(i18n.getMsg('err.msg.delete.title')
+                                    +' #'+json.message,
+                                    i18n.getMsg(json.message));
+                            } else {
+                                Ext.Msg.alert(i18n.getMsg('err.msg.delete.title'),
+                                    i18n.getMsg('err.msg.generic.body'));
+                            }
+                        } else {
+                            Ext.Msg.alert(i18n.getMsg('err.msg.delete.title'),
+                                i18n.getMsg('err.msg.response.body'));
+                        }
+                    }
+                });
+            }
+        });
+        grid.down('button[action=delete]').disable();
+    }
+});
--- a/app/model/DatensatzErzeuger.js	Mon Feb 29 15:10:17 2016 +0100
+++ b/app/model/DatensatzErzeuger.js	Tue Mar 01 14:12:39 2016 +0100
@@ -43,6 +43,7 @@
         url: 'lada-server/rest/datensatzerzeuger',
         reader: {
             type: 'json',
+            totalProperty: 'totalCount',
             root: 'data'
         }
     }
--- a/app/model/MessprogrammKategorie.js	Mon Feb 29 15:10:17 2016 +0100
+++ b/app/model/MessprogrammKategorie.js	Tue Mar 01 14:12:39 2016 +0100
@@ -41,6 +41,7 @@
         url: 'lada-server/rest/messprogrammkategorie',
         reader: {
             type: 'json',
+            totalProperty: 'totalCount',
             root: 'data'
         }
     }
--- a/app/model/Messung.js	Mon Feb 29 15:10:17 2016 +0100
+++ b/app/model/Messung.js	Tue Mar 01 14:12:39 2016 +0100
@@ -91,7 +91,7 @@
 
     proxy: {
         type: 'rest',
-        url: 'lada-server/rest/messung',
+        url: 'lada-server/rest/messung/',
         reader: {
             type: 'json',
             root: 'data'
--- a/app/model/Ort.js	Mon Feb 29 15:10:17 2016 +0100
+++ b/app/model/Ort.js	Tue Mar 01 14:12:39 2016 +0100
@@ -82,6 +82,7 @@
         url: 'lada-server/rest/ort',
         reader: {
             type: 'json',
+            totalProperty: 'totalCount',
             root: 'data'
         }
     }
--- a/app/model/Probenehmer.js	Mon Feb 29 15:10:17 2016 +0100
+++ b/app/model/Probenehmer.js	Tue Mar 01 14:12:39 2016 +0100
@@ -59,6 +59,7 @@
         url: 'lada-server/rest/probenehmer',
         reader: {
             type: 'json',
+            totalProperty: 'totalCount',
             root: 'data'
         }
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/app/view/form/Ortszuordnung.js	Tue Mar 01 14:12:39 2016 +0100
@@ -0,0 +1,225 @@
+/* Copyright (C) 2013 by Bundesamt fuer Strahlenschutz
+ * Software engineering by Intevation GmbH
+ *
+ * This file is Free Software under the GNU GPL (v>=3)
+ * and comes with ABSOLUTELY NO WARRANTY! Check out
+ * the documentation coming with IMIS-Labordaten-Application for details.
+ */
+
+/**
+ * Form to edit the Ortszuordnung of a Probe
+ */
+Ext.define('Lada.view.form.Ortszuordnung', {
+    extend: 'Ext.form.Panel',
+    alias: 'widget.ortszuordnungform',
+
+    model: 'Lada.model.Ortszuordnung',
+
+    requires: [
+        'Lada.view.widget.Verwaltungseinheit',
+        'Lada.view.widget.Staat'
+    ],
+
+    layout: 'fit',
+    margin: 5,
+    border: 0,
+
+    record: null,
+
+    trackResetOnLoad: true,
+
+    initComponent: function() {
+        var i18n = Lada.getApplication().bundle;
+        this.items = [{
+            xtype: 'fieldset',
+            title: i18n.getMsg('ortszuordnung.form.fset.title'),
+            layout: 'fit',
+            items: [{
+                layout: 'hbox',
+                border: 0,
+                margin: '0, 0, 10, 0',
+                dockedItems: [{
+                    xtype: 'toolbar',
+                    dock: 'bottom',
+                    border: '0, 1, 1, 1',
+                    style: {
+                        borderBottom: '1px solid #b5b8c8 !important',
+                        borderLeft: '1px solid #b5b8c8 !important',
+                        borderRight: '1px solid #b5b8c8 !important'
+                    },
+                    items: [{
+                        text: i18n.getMsg('ortszuordnung.form.setOrt'),
+                        qtip: i18n.getMsg('ortszuordnung.form.setOrt.qtip'),
+                        icon: 'resources/img/dialog-ok-apply.png',
+                        action: 'setOrt',
+                        enableToggle: true,
+                        disabled: true
+                    }, '->', {
+                        text: i18n.getMsg('save'),
+                        qtip: i18n.getMsg('save.qtip'),
+                        icon: 'resources/img/dialog-ok-apply.png',
+                        action: 'save',
+                        disabled: true
+                    }, {
+                        text: i18n.getMsg('discard'),
+                        qtip: i18n.getMsg('discard.qtip'),
+                        icon: 'resources/img/dialog-cancel.png',
+                        action: 'discard',
+                        disabled: true
+                    }]
+                }],
+                items: [{
+                    layout: 'vbox',
+                    border: 0,
+                    margin: '0, 10, 0, 0',
+                    items: [{
+                        xtype: 'tfield',
+                        labelWidth: 125,
+                        maxLength: 100,
+                        name: 'ortszusatztext',
+                        fieldLabel: i18n.getMsg('ortszuordnung.form.field.ortszusatztext')
+                    }, {
+                        xtype: 'tfield',
+                        labelWidth: 125,
+                        maxLength: 100,
+                        name: 'ortszuordnungTyp',
+                        fieldLabel: i18n.getMsg('ortszuordnung.form.field.ortszuordnungtyp')
+                    }, {
+                        xtype: 'textfield',
+                        submitValue: true,
+                        readOnly: true,
+                        hidden: true,
+                        name: 'ortId'
+                    }]
+                }, {
+                    layout: 'vbox',
+                    flex: 1,
+                    margin: '0, 10, 0, 0',
+                    border: 0,
+                    items: [{
+                        xtype: 'displayfield',
+                        labelWidth: 125,
+                        fieldLabel: i18n.getMsg('orte.gemeinde'),
+                        name: 'gemeinde'
+                    }, {
+                        xtype: 'displayfield',
+                        labelWidth: 125,
+                        fieldLabel: i18n.getMsg('staat'),
+                        name: 'staat'
+                    }]
+                }, {
+                    layout: 'vbox',
+                    flex: 1,
+                    margin: '0, 10, 0, 0',
+                    border: 0,
+                    items: [{
+                        xtype: 'displayfield',
+                        labelWidth: 125,
+                        fieldLabel: i18n.getMsg('orte.lon'),
+                        name: 'lon'
+                    }, {
+                        xtype: 'displayfield',
+                        labelWidth: 125,
+                        fieldLabel: i18n.getMsg('orte.lat'),
+                        name: 'lat'
+                    }]
+                }]
+            }]
+        }];
+        this.callParent(arguments);
+    },
+
+    setRecord: function(record) {
+        this.getForm().loadRecord(record);
+
+        if (! record.get('readonly')) {
+            this.down('[action=setOrt]').enable();
+            this.setReadOnly(false);
+        }
+        else {
+            this.setReadOnly(true);
+        }
+        var ortId = this.getRecord().get('ortId');
+        this.refreshOrt(ortId);
+    },
+
+    refreshOrt: function(ortId) {
+        var orteStore = Ext.StoreManager.get('orte');
+        var ort = orteStore.getById(ortId);
+        var verwStore = Ext.StoreManager.get('verwaltungseinheiten');
+        var verw = verwStore.getById(ort.get('gemId'));
+        var staatStore = Ext.StoreManager.get('staaten');
+        var staat = staatStore.getById(ort.get('staatId'));
+
+        this.getForm().setValues({
+            gemeinde: verw.get('bezeichnung'),
+            staat: staat.get('staatIso'),
+            lon: ort.get('longitude'),
+            lat: ort.get('latitude')
+        });
+    },
+
+    /**
+     * setOrt can be called from a CallbackFunction, ie select from a grid.
+     *  it will set the ortId of this record
+     */
+    setOrt: function(row, selRecord, index, opts) {
+        var newOrtId = selRecord.get('id');
+        var r = this.getRecord();
+        if (newOrtId) {
+            if (newOrtId != r.get('ortId')) {
+                r.set('ortId', newOrtId);
+                this.getForm().setValues({ortId: newOrtId});
+                this.refreshOrt(newOrtId);
+                //set dirty...
+                this.fireEvent('dirtychange', this.getForm(), true);
+            }
+        }
+    },
+
+    setMessages: function(errors, warnings) {
+        var key;
+        var element;
+        var content;
+        var i18n = Lada.getApplication().bundle;
+        if (warnings) {
+            for (key in warnings) {
+                element = this.down('component[name=' + key + ']');
+                if (!element) {
+                    continue;
+                }
+                content = warnings[key];
+                var warnText = '';
+                for (var i = 0; i < content.length; i++) {
+                    warnText += i18n.getMsg(content[i].toString()) + '\n';
+                }
+                element.showWarnings(warnText);
+            }
+        }
+        if (errors) {
+            for (key in errors) {
+                element = this.down('component[name=' + key + ']');
+                if (!element) {
+                    continue;
+                }
+                content = errors[key];
+                var errorText = '';
+                for (var i = 0; i < content.length; i++) {
+                    errorText += i18n.getMsg(content[i].toString()) + '\n';
+                }
+                element.showErrors(errorText);
+            }
+        }
+     },
+
+    clearMessages: function() {
+        this.down('tfield[name=ortszusatztext]').clearWarningOrError();
+        this.down('tfield[name=ortszuordnungTyp]').clearWarningOrError();
+     },
+
+    setReadOnly: function(value) {
+        this.down('tfield[name=ortszusatztext]').setReadOnly(value);
+        this.down('tfield[name=ortszuordnungTyp]').setReadOnly(value);
+    }
+});
+
--- a/app/view/grid/DatensatzErzeuger.js	Mon Feb 29 15:10:17 2016 +0100
+++ b/app/view/grid/DatensatzErzeuger.js	Tue Mar 01 14:12:39 2016 +0100
@@ -149,6 +149,7 @@
         if (store) {
             this.removeDocked(Ext.getCmp('ptbar'), true);
             this.reconfigure(store);
+            this.down('button[action=add]').enable();
             this.addDocked([{
                 xtype: 'pagingtoolbar',
                 id: 'ptbar',
--- a/app/view/grid/MessprogrammKategorie.js	Mon Feb 29 15:10:17 2016 +0100
+++ b/app/view/grid/MessprogrammKategorie.js	Tue Mar 01 14:12:39 2016 +0100
@@ -11,7 +11,7 @@
  */
 Ext.define('Lada.view.grid.MessprogrammKategorie', {
     extend: 'Ext.grid.Panel',
-    alias: 'widget.mkgrid',
+    alias: 'widget.messprogrammkategoriegrid',
 
     // minHeight and deferEmptyText are needed to be able to show the
     // emptyText message.
@@ -46,7 +46,6 @@
             dock: 'top',
             items: [{
                 xtype: 'tbtext',
-                id: 'tbtitle',
                 text: i18n.getMsg('mk.gridTitle')
             },
             '->',
@@ -89,12 +88,14 @@
             header: i18n.getMsg('mplId'),
             dataIndex: 'mplId',
             editor: {
+                xtype: 'textfield',
                 allowBlank: false
             }
         }, {
             header: i18n.getMsg('bezeichnung'),
             dataIndex: 'bezeichnung',
             editor: {
+                xtype: 'textfield',
                 allowBlank: false
             }
         }, {
@@ -103,16 +104,6 @@
             format: 'd.m.Y H:i',
             dataIndex: 'letzteAenderung'
         }];
-        this.listeners = {
-           select: {
-               fn: this.activateRemoveButton,
-               scope: this
-            },
-            deselect: {
-                fn: this.deactivateRemoveButton,
-                scope: this
-            }
-        };
         this.callParent(arguments);
     },
 
@@ -125,14 +116,21 @@
             this.down('button[action=add]').enable();
         }
 
-        this.removeDocked(Ext.getCmp('ptbar'), true);
-        this.reconfigure(store);
-        this.addDocked([{
-            xtype: 'pagingtoolbar',
-            id: 'ptbar',
-            dock: 'bottom',
-            store: store,
-            displayInfo: true
-        }]);
+        if (store) {
+            this.reconfigure(store);
+
+            var ptbar = this.down('pagingtoolbar');
+            if (ptbar) {
+                this.removeDocked(ptbar);
+            }
+
+            this.down('button[action=add]').enable();
+            this.addDocked([{
+                xtype: 'pagingtoolbar',
+                dock: 'bottom',
+                store: store,
+                displayInfo: true
+            }]);
+        }
     }
 });
--- a/app/view/grid/MessprogrammeList.js	Mon Feb 29 15:10:17 2016 +0100
+++ b/app/view/grid/MessprogrammeList.js	Tue Mar 01 14:12:39 2016 +0100
@@ -24,7 +24,6 @@
             dock: 'top',
             items: [{
                 xtype: 'tbtext',
-                id: 'tbtitle',
                 text: i18n.getMsg('messprogramme.gridTitle')
             },
             '->',
--- a/app/view/grid/Orte.js	Mon Feb 29 15:10:17 2016 +0100
+++ b/app/view/grid/Orte.js	Tue Mar 01 14:12:39 2016 +0100
@@ -26,32 +26,22 @@
     errors: null,
     readOnly: true,
     allowDeselect: true,
+    editableGrid: true,
 
     initComponent: function() {
         var i18n = Lada.getApplication().bundle;
         this.emptyText = i18n.getMsg('orte.emptyGrid');
 
-        this.dockedItems = [{
-            xtype: 'toolbar',
-            dock: 'top',
-            items: [{
-                xtype: 'tbtext',
-                id: 'tbtitle',
-                text: i18n.getMsg('orte.gridTitle')
-            },
-            '->',
-            {
-                text: i18n.getMsg('orte.button.add'),
-                icon: 'resources/img/list-add.png',
-                action: 'add',
-                disabled: true // disabled on startup, will be enabled by setStore
-            }, {
-                text: i18n.getMsg('orte.button.delete'),
-                icon: 'resources/img/list-remove.png',
-                action: 'delete',
-                disabled: true // disabled on startup, will be enabled by controller if necessary
-            }]
-        }];
+        if (this.editableGrid) {
+            this.rowEditing = Ext.create('Ext.grid.plugin.RowEditing', {
+                clicksToMoveEditor: 1,
+                autoCancel: false,
+                disabled: false,
+                pluginId: 'rowedit'
+            });
+            this.plugins = [this.rowEditing];
+        }
+
         this.columns = [{
             header: i18n.getMsg('orte.ortId'),
             dataIndex: 'ortId'
@@ -134,26 +124,6 @@
             header: i18n.getMsg('orte.letzteAenderung'),
             dataIndex: 'letzteAenderung'
         }];
-        this.listeners = {
-           select: {
-               fn: this.activateRemoveButton,
-               scope: this
-            },
-            deselect: {
-                fn: this.deactivateRemoveButton,
-                scope: this
-            }
-        };
-        this.listeners = {
-           select: {
-               fn: this.activateRemoveButton,
-               scope: this
-            },
-            deselect: {
-                fn: this.deactivateRemoveButton,
-                scope: this
-            }
-        };
         this.callParent(arguments);
     },
 
@@ -164,16 +134,27 @@
         var i18n = Lada.getApplication().bundle;
 
         if (store) {
-            this.removeDocked(Ext.getCmp('ptbar'), true);
             this.reconfigure(store);
-            this.down('button[action=add]').enable();
-            this.addDocked([{
-                xtype: 'pagingtoolbar',
-                id: 'ptbar',
-                dock: 'bottom',
-                store: store,
-                displayInfo: true
-            }]);
+
+            var ptbar = this.down('pagingtoolbar');
+            if (ptbar) {
+                this.removeDocked(ptbar);
+            }
+
+            if (store.pageSize > 0) {
+                this.addDocked([{
+                    xtype: 'pagingtoolbar',
+                    dock: 'bottom',
+                    store: store,
+                    displayInfo: true
+                }]);
+            }
         }
+    },
+
+    selectOrt: function(map, feature) {
+        var id = feature[0].data.id;
+        var record = this.store.getById(id);
+        this.getSelectionModel().select(record);
     }
 });
--- a/app/view/grid/Ortszuordnung.js	Mon Feb 29 15:10:17 2016 +0100
+++ b/app/view/grid/Ortszuordnung.js	Tue Mar 01 14:12:39 2016 +0100
@@ -11,7 +11,7 @@
  */
 Ext.define('Lada.view.grid.Ortszuordnung', {
     extend: 'Ext.grid.Panel',
-    alias: 'widget.ortgrid',
+    alias: 'widget.ortszuordnunggrid',
 
     maxHeight: 350,
     emptyText: 'Keine Orte gefunden.',
@@ -47,15 +47,15 @@
         }];
         this.columns = [{
             header: 'Typ',
-            dataIndex: 'ortsTyp',
-            width: 50,
+            dataIndex: 'ortszuordnungTyp',
+            flex: 1,
             editor: {
                 allowBlank: false
             }
         }, {
             header: 'Staat',
-            dataIndex: 'ort',
-            width: 70,
+            dataIndex: 'ortId',
+            flex: 1,
             renderer: function(value) {
                 var store = Ext.data.StoreManager.get('orte');
                 var staaten = Ext.data.StoreManager.get('staaten');
@@ -64,9 +64,9 @@
                 return record.get('staatIso');
             }
         }, {
-            header: 'Gemeineschlüssel',
-            dataIndex: 'ort',
-            width: 120,
+            header: 'Gemeindeschlüssel',
+            dataIndex: 'ortId',
+            flex: 3,
             renderer: function(value) {
                 var store = Ext.data.StoreManager.get('orte');
                 var record = store.getById(value);
@@ -74,8 +74,8 @@
             }
         }, {
             header: 'Gemeindename',
-            dataIndex: 'ort',
-            flex: 1,
+            dataIndex: 'ortId',
+            flex: 4,
             renderer: function(value) {
                 var store = Ext.data.StoreManager.get('orte');
                 var gemeinden =
@@ -86,13 +86,9 @@
                 return record2.get('bezeichnung');
             }
         }, {
-            header: 'Messpunkt',
-            dataIndex: 'ort',
-            renderer: function(value) {
-                var store = Ext.getStore('orte');
-                var record = store.getById(value);
-                return record.get('bezeichnung');
-            }
+            header: 'Ortszusatztext',
+            flex: 6,
+            dataIndex: 'ortszusatztext'
         }];
         this.listeners = {
            select: {
--- a/app/view/grid/ProbeList.js	Mon Feb 29 15:10:17 2016 +0100
+++ b/app/view/grid/ProbeList.js	Tue Mar 01 14:12:39 2016 +0100
@@ -24,7 +24,6 @@
             dock: 'top',
             items: [{
                 xtype: 'tbtext',
-                id: 'tbtitle',
                 text: i18n.getMsg('probe.gridTitle')
             },
             '->',
--- a/app/view/grid/Probenehmer.js	Mon Feb 29 15:10:17 2016 +0100
+++ b/app/view/grid/Probenehmer.js	Tue Mar 01 14:12:39 2016 +0100
@@ -180,6 +180,7 @@
         if (store) {
             this.removeDocked(Ext.getCmp('ptbar'), true);
             this.reconfigure(store);
+            this.down('button[action=add]').enable();
             this.addDocked([{
                 xtype: 'pagingtoolbar',
                 id: 'ptbar',
--- a/app/view/panel/Map.js	Mon Feb 29 15:10:17 2016 +0100
+++ b/app/view/panel/Map.js	Tue Mar 01 14:12:39 2016 +0100
@@ -14,9 +14,15 @@
 Ext.define('Lada.view.panel.Map', {
     extend: 'Ext.panel.Panel',
     alias: 'widget.map',
+    name: 'map',
 
     record: null,
     locationRecord: null,
+    externalOrteStore: false,
+    /*
+     * if externalOrteStore is true, the mappanel will not load the orte
+     * store on it's own; it expects an already loaded store instead
+     */
 
     /**
      * @cfg
@@ -62,7 +68,6 @@
         keyControl.activate();
         this.bodyStyle = {background: '#fff'};
         this.initData();
-        this.tbar = Ext.create('Lada.view.widget.MapToolbar');
         this.addEvents('featureselected');
         this.callParent(arguments);
     },
@@ -73,58 +78,15 @@
      */
     initData: function() {
         var me = this;
-        this.locationFeatures = [];
-        this.locationStore = Ext.data.StoreManager.get('locations');
-        for (var i = 0; i < this.locationStore.count(); i++) {
-            this.locationFeatures.push(new OpenLayers.Feature.Vector(
-                new OpenLayers.Geometry.Point(
-                    this.locationStore.getAt(i).get('longitude'),
-                    this.locationStore.getAt(i).get('latitude')
-                ),
-                {
-                    id: this.locationStore.getAt(i).get('id'),
-                    bez: this.locationStore.getAt(i).get('bezeichnung')
-                }
-            ));
+
+        if (!this.externalOrteStore) {
+            this.locationStore = Ext.data.StoreManager.get('orte');
+            this.addLocations(locationStore);
         }
-        this.featureLayer = new OpenLayers.Layer.Vector('vector_' + this.map.name, {
-            styleMap: new OpenLayers.StyleMap({
-                'default': new OpenLayers.Style(OpenLayers.Util.applyDefaults({
-                    externalGraphic: 'resources/lib/OpenLayers/img/marker-green.png',
-                    graphicOpacity: 1,
-                    pointRadius: 10,
-                    label: '${bez}',
-                    labelAlign: 'rt',
-                    fontColor: 'green',
-                    fontWeight: 'bold'
-                }, OpenLayers.Feature.Vector.style['default'])),
-                'select': new OpenLayers.Style({
-                    externalGraphic: 'resources/lib/OpenLayers/img/marker-blue.png',
-                    pointRadius: 15,
-                    label: '${bez}',
-                    labelAlign: 'rt',
-                    fontColor: 'blue',
-                    fontWeight: 'bold'
-                })
-            })
-        });
-        this.featureLayer.addFeatures(this.locationFeatures);
-        this.map.addLayer(this.featureLayer);
-
-        this.selectControl = new OpenLayers.Control.SelectFeature(this.featureLayer, {
-            clickout: false,
-            toggle: false,
-            multiple: false,
-            hover: false,
-            onSelect: me.selectedFeature,
-            scope: me
-        });
-        this.map.addControl(this.selectControl);
-        this.selectControl.activate();
     },
 
-    selectFeature: function(id) {
-        var feature = this.featureLayer.getFeaturesByAttribute('id', id);
+    selectFeature: function(model, record) {
+        var feature = this.featureLayer.getFeaturesByAttribute('id', record.get('id'));
         this.map.setCenter(
             new OpenLayers.LonLat(feature[0].geometry.x, feature[0].geometry.y));
         this.map.zoomToScale(this.mapOptions.scales[5]);
@@ -151,6 +113,65 @@
         this.selectControl.select(features.feature);
     },
 
+    addLocations: function(locationStore) {
+        var me = this;
+        locationFeatures = [];
+
+        // Iterate the Store and create features from it
+        for (var i = 0; i < locationStore.count(); i++) {
+            locationFeatures.push(new OpenLayers.Feature.Vector(
+                new OpenLayers.Geometry.Point(
+                    locationStore.getAt(i).get('longitude'),
+                    locationStore.getAt(i).get('latitude')
+                ),
+                {
+                    id: locationStore.getAt(i).get('id'),
+                    bez: locationStore.getAt(i).get('ortId')
+                }
+            ));
+        }
+
+        // Create a new Feature Layer and add it to the map
+        if (!this.featureLayer) {
+            this.featureLayer = new OpenLayers.Layer.Vector('vector_' + this.map.name, {
+                styleMap: new OpenLayers.StyleMap({
+                    'default': new OpenLayers.Style(OpenLayers.Util.applyDefaults({
+                        externalGraphic: 'resources/lib/OpenLayers/img/marker-green.png',
+                        graphicOpacity: 1,
+                        pointRadius: 10,
+                        label: '${bez}',
+                        labelAlign: 'rt',
+                        fontColor: 'green',
+                        fontWeight: 'bold'
+                    }, OpenLayers.Feature.Vector.style['default'])),
+                    'select': new OpenLayers.Style({
+                        externalGraphic: 'resources/lib/OpenLayers/img/marker-blue.png',
+                        pointRadius: 15,
+                        label: '${bez}',
+                        labelAlign: 'rt',
+                        fontColor: 'blue',
+                        fontWeight: 'bold'
+                    })
+                })
+            });
+            this.selectControl = new OpenLayers.Control.SelectFeature(this.featureLayer, {
+                clickout: false,
+                toggle: false,
+                multiple: false,
+                hover: false,
+                onSelect: me.selectedFeature,
+                scope: me
+            });
+            this.map.addControl(this.selectControl);
+            this.selectControl.activate();
+        }
+        this.featureLayer.removeAllFeatures();
+        this.featureLayer.addFeatures(locationFeatures);
+        this.map.addLayer(this.featureLayer);
+
+    },
+
+
     /**
      * @private
      * Override to display and update the map view in the panel.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/app/view/panel/Ort.js	Tue Mar 01 14:12:39 2016 +0100
@@ -0,0 +1,147 @@
+Ext.define('Lada.view.panel.Ort', {
+    extend: 'Ext.panel.Panel',
+    alias: 'widget.ortpanel',
+
+    requires: [
+        'Lada.view.panel.Map',
+        'Lada.view.grid.Orte'
+    ],
+
+    width: '100%',
+    //height: 200,
+
+    layout: {
+        type: 'border'
+    },
+    toolbarPos: 'top',
+
+    editableGrid: true,
+
+    initComponent: function() {
+        var i18n = Lada.getApplication().bundle;
+
+        // Different Layout of toolbar depending on the bars position.
+        if (this.toolbarPos == 'top') {
+            this.dockedItems = [{
+                xtype: 'toolbar',
+                dock: 'top',
+                items: [{
+                    xtype: 'tbtext',
+                    text: i18n.getMsg('orte.gridTitle')
+                },
+                '->',
+                {
+                    text: i18n.getMsg('map.button.add'),
+                    icon: 'resources/img/list-add.png',
+                    action: 'addMap',
+                    disabled: true // disabled on startup, will be enabled by setStore
+                }, {
+                    text: i18n.getMsg('orte.button.add'),
+                    icon: 'resources/img/list-add.png',
+                    action: 'add',
+                    disabled: true // disabled on startup, will be enabled by setStore
+                }, {
+                    text: i18n.getMsg('orte.button.delete'),
+                    icon: 'resources/img/list-remove.png',
+                    action: 'delete',
+                    disabled: true // disabled on startup, will be enabled by controller if necessary
+                }]
+            }];
+        }
+        else {
+            this.dockedItems = [{
+                xtype: 'toolbar',
+                dock: this.toolbarPos,
+                items: [ '->',
+                {
+                    text: i18n.getMsg('map.button.add'),
+                    icon: 'resources/img/list-add.png',
+                    action: 'addMap',
+                    disabled: true // disabled on startup, will be enabled by setStore
+                }, {
+                    text: i18n.getMsg('orte.button.add'),
+                    icon: 'resources/img/list-add.png',
+                    action: 'add',
+                    disabled: true // disabled on startup, will be enabled by setStore
+                }]
+            }];
+        }
+
+        this.items = [{
+            xtype: 'ortstammdatengrid',
+            width: '60%',
+            editableGrid: this.editableGrid,
+            collapsible: true,
+            region: 'east'
+        }, {
+            xtype: 'map',
+            region: 'center',
+            layout: 'border',
+            title: i18n.getMsg('map.title'),
+            externalOrteStore: true,
+            listeners: {
+                beforecollapse: function() {
+                    var c = this.map.getControlsByClass('OpenLayers.Control.ScaleLine');
+                    this.map.removeControl(c[0]);
+                },
+                expand: function() {
+                    this.map.addControl(new OpenLayers.Control.ScaleLine());
+                }
+            }
+        }];
+
+        this.callParent(arguments);
+    },
+
+    afterRender: function() {
+        this.superclass.afterRender.apply(this, arguments);
+        this.down('map').map.zoomToMaxExtent();
+    },
+
+    setStore: function(store) {
+        var me = this;
+        var osg = this.down('ortstammdatengrid');
+        var map = this.down('map');
+
+        if (!store) {
+            var ortstore = Ext.create('Lada.store.Orte', {
+                defaultPageSize: 0,
+                listeners: {
+                    beforeload: {
+                        fn: function() {
+                            osg.setLoading(true);
+                            map.setLoading(true);
+                        }
+                    },
+                    load: {
+                        fn: function() {
+                            osg.setLoading(false);
+                            map.setLoading(false);
+                            osg.setStore(ortstore);
+                            map.addLocations(ortstore);
+                        }
+                    }
+                }
+            });
+        }
+        else {
+            osg.setStore(store);
+            map.addLocations(store);
+        }
+        this.connectListeners();
+        //enable buttons
+        me.down('toolbar button[action=add]').enable();
+        me.down('toolbar button[action=addMap]').enable();
+    },
+
+    getStore: function() {
+        return this.down('grid').getStore();
+    },
+
+    connectListeners: function() {
+        var osg = this.down('ortstammdatengrid');
+        var map = this.down('map');
+        map.addListener('featureselected', osg.selectOrt, osg);
+        osg.addListener('select', map.selectFeature, map);
+    }
+});
--- a/app/view/widget/DynamicGrid.js	Mon Feb 29 15:10:17 2016 +0100
+++ b/app/view/widget/DynamicGrid.js	Tue Mar 01 14:12:39 2016 +0100
@@ -35,11 +35,14 @@
     setStore: function(store){
         var i18n = Lada.getApplication().bundle;
 
-        this.removeDocked(Ext.getCmp('ptbar'), true);
         this.reconfigure(store);
+        var ptbar = this.down('pagingtoolbar');
+        if (ptbar) {
+            this.removeDocked(ptbar);
+        }
+
         this.addDocked([{
             xtype: 'pagingtoolbar',
-            id: 'ptbar',
             dock: 'bottom',
             store: store,
             displayInfo: true
--- a/app/view/window/OrtCreate.js	Mon Feb 29 15:10:17 2016 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,146 +0,0 @@
-/* Copyright (C) 2013 by Bundesamt fuer Strahlenschutz
- * Software engineering by Intevation GmbH
- *
- * This file is Free Software under the GNU GPL (v>=3)
- * and comes with ABSOLUTELY NO WARRANTY! Check out
- * the documentation coming with IMIS-Labordaten-Application for details.
- */
-
-/**
- * Window to create a Ort
- */
-Ext.define('Lada.view.window.OrtCreate', {
-    extend: 'Ext.window.Window',
-    alias: 'widget.ortcreate',
-
-    requires: [
-        'Lada.view.panel.Map',
-        'Lada.view.form.Ort',
-        'Lada.view.form.Location'
-    ],
-
-    collapsible: true,
-    maximizable: true,
-    autoshow: true,
-    layout: 'border',
-    constrain: true,
-
-    record: null,
-    grid: null,
-
-    /**
-     * This function initialises the Window
-     */
-    initComponent: function() {
-        this.title = 'Ort';
-        this.buttons = [{
-            text: 'Schließen',
-            scope: this,
-            handler: this.close
-        }];
-        this.width = 900;
-        this.height = 515;
-        this.bodyStyle = {background: '#fff'};
-
-        // add listeners to change the window appearence when it becomes inactive
-        this.on({
-            activate: function(){
-                this.getEl().removeCls('window-inactive');
-            },
-            deactivate: function(){
-                this.getEl().addCls('window-inactive');
-            }
-        });
-
-        this.items = [{
-            region: 'west',
-            border: 0,
-            layout: 'vbox',
-            items: [{
-                xtype: 'ortform',
-                margin: 5
-            }, {
-                xtype: 'locationform',
-                margin: 5
-            }]
-        }, {
-            xtype: 'fset',
-            bodyStyle: {
-                background: '#fff'
-            },
-            layout: 'border',
-            name: 'mapfield',
-            title: 'Karte',
-            region: 'center',
-            padding: '5, 5',
-            margin: 5,
-            items: [{
-                xtype: 'map',
-                region: 'center',
-                layout: 'border',
-                bodyStyle: {
-                    background: '#fff'
-                },
-                name: 'map',
-                listeners: { //A listener which listens to the mappanels featureselected event
-                    featureselected: this.selectedFeature
-                }
-            }]
-        }];
-        this.callParent(arguments);
-    },
-
-    /**
-     * Initialise the Data of this Window
-     */
-    initData: function() {
-        var ort = Ext.create('Lada.model.Ort', {
-            probeId: this.record.get('id')
-        });
-        this.down('ortform').setRecord(ort);
-    },
-
-    /**
-     * @private
-     * Override to display and update the map view in the panel.
-     */
-    afterRender: function(){
-        this.superclass.afterRender.apply(this, arguments);
-        var map = this.down('map');
-        map.map.zoomToMaxExtent();
-    },
-
-    /**
-     * This function is used by the MapPanel, when a Feature was selected
-     */
-    selectedFeature: function(context, args) {
-    var feature = args[0];
-        if (feature.attributes.id &&
-            feature.attributes.id !== '') {
-            var record = Ext.data.StoreManager.get('locations').getById(feature.attributes.id);
-            context.up('window').down('locationform').setRecord(record);
-            context.up('window').down('locationform').setReadOnly(true);
-            context.up('window').down('ortform').down('combobox').setValue(record.id);
-        }
-        else {
-            context.up('window').down('locationform').setRecord(this.locationRecord);
-            context.up('window').down('locationform').setReadOnly(false);
-        }
-    },
-
-    /**
-     * Instructs the fields / forms listed in this method to set a message.
-     * @param errors These Errors shall be shown
-     * @param warnings These Warning shall be shown
-     */
-    setMessages: function(errors, warnings) {
-        //todo this is a stub
-    },
-
-    /**
-     * Instructs the fields / forms listed in this method to clear their messages.
-     */
-    clearMessages: function() {
-        //todo this is a stub
-    }
-});
--- a/app/view/window/OrtEdit.js	Mon Feb 29 15:10:17 2016 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,204 +0,0 @@
-/* Copyright (C) 2013 by Bundesamt fuer Strahlenschutz
- * Software engineering by Intevation GmbH
- *
- * This file is Free Software under the GNU GPL (v>=3)
- * and comes with ABSOLUTELY NO WARRANTY! Check out
- * the documentation coming with IMIS-Labordaten-Application for details.
- */
-
-/**
- * Window to edit a Ort
- */
-Ext.define('Lada.view.window.OrtEdit', {
-    extend: 'Ext.window.Window',
-    alias: 'widget.ortedit',
-
-    requires: [
-        'Lada.view.panel.Map',
-        'Lada.view.form.Ort',
-        'Lada.view.form.Location'
-    ],
-
-    collapsible: true,
-    maximizable: true,
-    autoshow: true,
-    layout: 'border',
-    constrain: true,
-
-    parentWindow: null,
-    probe: null,
-    record: null,
-    grid: null,
-
-    /**
-     * This function initialises the Window
-     */
-    initComponent: function() {
-        if (this.record === null) {
-            Ext.Msg.alert('Kein valider Ort ausgewählt!');
-            this.callParent(arguments);
-            return;
-        }
-        if (this.probe === null) {
-            Ext.Msg.alert('Zu dem Ort existiert keine Probe!');
-            this.callParent(arguments);
-            return;
-        }
-        this.title = 'Ort';
-        this.buttons = [{
-            text: 'Schließen',
-            scope: this,
-            handler: this.close
-        }];
-        this.width = 900;
-        this.height = 515;
-        this.bodyStyle = {background: '#fff'};
-
-        // add listeners to change the window appearence when it becomes inactive
-        this.on({
-            activate: function(){
-                this.getEl().removeCls('window-inactive');
-            },
-            deactivate: function(){
-                this.getEl().addCls('window-inactive');
-            }
-        });
-
-        this.items = [{
-            region: 'west',
-            border: 0,
-            layout: 'vbox',
-            items: [{
-                xtype: 'ortform',
-                margin: 5,
-                recordId: this.record.get('id')
-            }, {
-                xtype: 'locationform',
-                margin: 5,
-                recordId: this.record.get('id')
-            }]
-        }, {
-            xtype: 'fset',
-            bodyStyle: {
-                background: '#fff'
-            },
-            layout: 'border',
-            name: 'mapfield',
-            title: 'Karte',
-            region: 'center',
-            padding: '5, 5',
-            margin: 5,
-            items: [{
-                xtype: 'map',
-                region: 'center',
-                layout: 'border',
-                record: this.record,
-                bodyStyle: {
-                    background: '#fff'
-                },
-                name: 'map',
-                listeners: { //A listener which listens to the mappanels featureselected event
-                    featureselected: this.selectedFeature
-                }
-            }]
-        }];
-        this.callParent(arguments);
-    },
-
-    /**
-     * Initialise the Data of this Window
-     */
-    initData: function() {
-        Ext.ClassManager.get('Lada.model.Ort').load(this.record.get('id'), {
-            failure: function(record, action) {
-                // TODO
-            },
-            success: function(record, response) {
-                var me = this;
-                if (record.get('treeModified') < record.get('parentModified')) {
-                    Ext.Msg.show({
-                        title: 'Probe nicht aktuell!',
-                        msg: 'Die zugehörige Probe wurde verändert.\nMöchten Sie zu der Probe zurückkehren und neu laden?\nOhne das erneute Laden der Probe wird das Speichern des Ortes nicht möglich sein.',
-                        buttons: Ext.Msg.OKCANCEL,
-                        icon: Ext.Msg.WARNING,
-                        closable: false,
-                        fn: function(button) {
-                            if (button === 'ok') {
-                                me.close();
-                                me.parentWindow.initData();
-                            }
-                            else {
-                                me.record.set('treeModified', me.probe.get('treeModified'));
-                            }
-                        }
-                    });
-                }
-                this.down('ortform').setRecord(record);
-                if (this.probe.get('readonly')) {
-                    this.down('ortform').setReadOnly(true);
-                }
-                this.record = record;
-            },
-            scope: this
-        });
-        Ext.ClassManager.get('Lada.model.Location').load(this.record.get('ort'), {
-            failure: function(record, action) {
-                // TODO
-            },
-            success: function(record, response) {
-                this.down('locationform').setRecord(record);
-                this.down('locationform').setReadOnly(true);
-            },
-            scope: this
-        });
-    },
-
-    /**
-     * @private
-     * Override to display and update the map view in the panel.
-     */
-    afterRender: function(){
-        this.superclass.afterRender.apply(this, arguments);
-        var map = this.down('map');
-        if (this.record) {
-            map.selectFeature(this.record.get('ort'));
-        }
-        else {
-            map.map.zoomToMaxExtent();
-        }
-    },
-
-    /**
-     * This function is used by the MapPanel, when a Feature was selected
-     */
-    selectedFeature: function(context, args) {
-    var feature = args[0];
-        if (feature.attributes.id &&
-            feature.attributes.id !== '') {
-            var record = Ext.data.StoreManager.get('locations').getById(feature.attributes.id);
-            context.up('window').down('locationform').setRecord(record);
-            context.up('window').down('locationform').setReadOnly(true);
-            context.up('window').down('ortform').down('combobox').setValue(record.id);
-        }
-        else {
-            context.up('window').down('locationform').setRecord(this.locationRecord);
-            context.up('window').down('locationform').setReadOnly(false);
-        }
-    },
-
-    /**
-     * Instructs the fields / forms listed in this method to set a message.
-     * @param errors These Errors shall be shown
-     * @param warnings These Warning shall be shown
-     */
-    setMessages: function(errors, warnings) {
-        //todo this is a stub
-    },
-
-    /**
-     * Instructs the fields / forms listed in this method to clear their messages.
-     */
-    clearMessages: function() {
-        //todo this is a stub
-    }
-});
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/app/view/window/Ortszuordnung.js	Tue Mar 01 14:12:39 2016 +0100
@@ -0,0 +1,133 @@
+/* Copyright (C) 2013 by Bundesamt fuer Strahlenschutz
+ * Software engineering by Intevation GmbH
+ *
+ * This file is Free Software under the GNU GPL (v>=3)
+ * and comes with ABSOLUTELY NO WARRANTY! Check out
+ * the documentation coming with IMIS-Labordaten-Application for details.
+ */
+
+/**
+ * Window to create/edit the Ort / Probe Relation
+ */
+Ext.define('Lada.view.window.Ortszuordnung', {
+    extend: 'Ext.window.Window',
+    alias: 'widget.ortszuordnungwindow',
+
+    requires: [
+        'Lada.view.form.Ortszuordnung',
+        'Lada.view.panel.Ort'
+    ],
+
+    collapsible: true,
+    maximizable: true,
+    autoshow: true,
+    layout: 'vbox',
+    constrain: true,
+
+    probe: null,
+    parentWindow: null,
+    record: null,
+    grid: null,
+
+    /**
+     * This function initialises the Window
+     */
+    initComponent: function() {
+        var i18n = Lada.getApplication().bundle;
+
+        this.title = i18n.getMsg('ortszuordnung.window.title');
+
+        if (this.record && this.probe) {
+            // A record be edited
+            this.title = i18n.getMsg('ortszuordnung.window.title')
+                            + ' '
+                            + i18n.getMsg('ortszuordnung.window.title2')
+                            + ' '
+                            + i18n.getMsg('probe')
+                            + ' '
+                            + this.probe.get('hauptprobennr')
+                            + ' '
+                            + i18n.getMsg('edit');
+        }
+        else if (this.probe) {
+            // A new record will be created
+            this.title = i18n.getMsg('ortszuordnung.window.title')
+                            + ' '
+                            + i18n.getMsg('ortszuordnung.window.title2')
+                            + ' '
+                            + i18n.getMsg('probe')
+                            + ' '
+                            + this.probe.get('hauptprobennr')
+                            + ' '
+                            + i18n.getMsg('create');
+        }
+
+        this.buttons = [{
+            text: i18n.getMsg('close'),
+            scope: this,
+            handler: this.close
+        }];
+        this.width = 900;
+        this.height = 515;
+        this.bodyStyle = {background: '#fff'};
+
+        // add listeners to change the window appearence when it becomes inactive
+        this.on({
+            activate: function(){
+                this.getEl().removeCls('window-inactive');
+            },
+            deactivate: function(){
+                this.getEl().addCls('window-inactive');
+            }
+        });
+
+        this.items = [{
+            xtype: 'ortszuordnungform',
+            layout: 'fit',
+            width: '100%',
+            margin: 5
+        }, {
+            xtype: 'ortpanel',
+            editableGrid: false,
+            flex: 1,
+            toolbarPos: 'bottom',
+            margin: 5
+        }];
+        this.callParent(arguments);
+    },
+
+    /**
+     * Initialise the Data of this Window
+     */
+    initData: function() {
+        this.down('ortszuordnungform').setRecord(this.record);
+        this.down('ortpanel').setStore();
+    },
+
+    /**
+     * @private
+     * Override to display and update the map view in the panel.
+     */
+    afterRender: function(){
+        this.superclass.afterRender.apply(this, arguments);
+        var map = this.down('ortpanel').down('map');
+        map.map.zoomToMaxExtent();
+    },
+
+    /**
+     * Instructs the fields / forms listed in this method to set a message.
+     * @param errors These Errors shall be shown
+     * @param warnings These Warning shall be shown
+     */
+    setMessages: function(errors, warnings) {
+        //todo this is a stub
+    },
+
+    /**
+     * Instructs the fields / forms listed in this method to clear their messages.
+     */
+    clearMessages: function() {
+        //todo this is a stub
+    }
+});
+
--- a/app/view/window/ProbeEdit.js	Mon Feb 29 15:10:17 2016 +0100
+++ b/app/view/window/ProbeEdit.js	Tue Mar 01 14:12:39 2016 +0100
@@ -75,7 +75,7 @@
                 padding: '5, 5',
                 margin: 5,
                 items: [{
-                    xtype: 'ortgrid',
+                    xtype: 'ortszuordnunggrid',
                     recordId: this.record.get('id')
                 }]
              }, {
@@ -182,8 +182,9 @@
             // Disable only when the User is not the owner of the Probe
             // Works in symbiosis with success callback some lines above.
             this.down('fset[name=messungen]').down('messunggrid').setReadOnly(true);
+            this.down('fset[name=messungen]').down('messunggrid').readOnly = true;
         }
-        this.down('fset[name=orte]').down('ortgrid').setReadOnly(true);
+        this.down('fset[name=orte]').down('ortszuordnunggrid').setReadOnly(true);
         this.down('fset[name=probenzusatzwerte]').down('probenzusatzwertgrid').setReadOnly(true);
         this.down('fset[name=pkommentare]').down('pkommentargrid').setReadOnly(true);
     },
@@ -193,7 +194,7 @@
      */
     enableChildren: function() {
         this.down('fset[name=messungen]').down('messunggrid').setReadOnly(false);
-        this.down('fset[name=orte]').down('ortgrid').setReadOnly(false);
+        this.down('fset[name=orte]').down('ortszuordnunggrid').setReadOnly(false);
         this.down('fset[name=probenzusatzwerte]').down('probenzusatzwertgrid').setReadOnly(false);
         this.down('fset[name=pkommentare]').down('pkommentargrid').setReadOnly(false);
     },
--- a/index.html	Mon Feb 29 15:10:17 2016 +0100
+++ b/index.html	Tue Mar 01 14:12:39 2016 +0100
@@ -20,7 +20,7 @@
     <script type="text/javascript" src="resources/lib/Blob/Blob.js"></script>
     <!-- <x-compile> -->
     <!-- <x-bootstrap> -->
-    <script type="text/javascript" src="extjs/ext-all.js"></script>
+    <script type="text/javascript" src="extjs/ext-all-dev.js"></script>
     <script type="text/javascript" src="extjs/locale/ext-lang-de.js"></script>
     <!-- </x-bootstrap> -->
     <script type="text/javascript" src="app.js"></script>
--- a/resources/i18n/Lada_de-DE.properties	Mon Feb 29 15:10:17 2016 +0100
+++ b/resources/i18n/Lada_de-DE.properties	Tue Mar 01 14:12:39 2016 +0100
@@ -46,6 +46,7 @@
 proben:Proben
 stammdaten:Stammdaten
 
+probe:Probe
 name:Name
 mstId:Messstelle
 datenbasisId:Datenbasis
@@ -119,6 +120,14 @@
 about.window.text.clientversion:Clientversion:
 
 
+ortszuordnung.window.title:Ortszuordnung
+ortszuordnung.window.title2:zu
+
+ortszuordnung.form.fset.title:Ortszuordnung
+ortszuordnung.form.field.ortszusatztext:Ortszusatztext
+ortszuordnung.form.field.ortszuordnungtyp:Typ der Ortszuordnung
+
+
 load.statuswert:Lade aktuellen Statuswert...
 load.statusstufe:Lade aktuelle Statusstufe...
 load.statuswert.error:Fehler beim auflösen der Statuswerte

http://lada.wald.intevation.org