source: subversion/applications/editors/josm/plugins/indoorhelper/src/controller/IndoorHelperController.java

Last change on this file was 34741, checked in by donvip, 5 months ago

fix #17030 - remove indoorhelper validator file

File size: 21.4 KB
Line 
1/*
2 * Indoorhelper is a JOSM plug-in to support users when creating their own indoor maps.
3 *  Copyright (C) 2016  Erik Gruschka
4 *  Copyright (C) 2018  Rebecca Schmidt
5 *
6 *  This program is free software: you can redistribute it and/or modify
7 *  it under the terms of the GNU General Public License as published by
8 *  the Free Software Foundation, either version 3 of the License, or
9 *  (at your option) any later version.
10 *
11 *  This program is distributed in the hope that it will be useful,
12 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 *  GNU General Public License for more details.
15 *
16 *  You should have received a copy of the GNU General Public License
17 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20package controller;
21
22import static org.openstreetmap.josm.tools.I18n.tr;
23
24import java.awt.event.ActionEvent;
25import java.awt.event.ActionListener;
26import java.awt.event.ItemEvent;
27import java.awt.event.ItemListener;
28import java.awt.event.KeyEvent;
29import java.awt.event.WindowEvent;
30import java.awt.event.WindowListener;
31import java.util.ArrayList;
32import java.util.Collection;
33import java.util.HashMap;
34import java.util.List;
35import java.util.Map;
36import java.util.Optional;
37
38import javax.swing.AbstractAction;
39import javax.swing.JOptionPane;
40
41import org.openstreetmap.josm.actions.ValidateAction;
42import org.openstreetmap.josm.actions.mapmode.DrawAction;
43import org.openstreetmap.josm.actions.mapmode.SelectAction;
44import org.openstreetmap.josm.data.Preferences;
45import org.openstreetmap.josm.data.osm.OsmDataManager;
46import org.openstreetmap.josm.data.osm.OsmPrimitive;
47import org.openstreetmap.josm.data.osm.Tag;
48import org.openstreetmap.josm.gui.MainApplication;
49import org.openstreetmap.josm.gui.MapFrame;
50import org.openstreetmap.josm.gui.help.HelpBrowser;
51import org.openstreetmap.josm.gui.mappaint.MapPaintStyles;
52import org.openstreetmap.josm.spi.preferences.Config;
53import org.openstreetmap.josm.spi.preferences.MapListSetting;
54import org.openstreetmap.josm.spi.preferences.Setting;
55import org.openstreetmap.josm.tools.Shortcut;
56
57import model.IndoorHelperModel;
58import model.IndoorLevel;
59import model.TagCatalog.IndoorObject;
60import views.LevelSelectorView;
61import views.ToolBoxView;
62
63/**
64*
65* Class for the Controller which provides the communication between
66* the IndoorHelperModel and the different views.
67*
68* @author egru
69* @author rebsc
70*
71*/
72public class IndoorHelperController {
73
74   private IndoorHelperModel model;
75   private ToolBoxView toolboxView;
76   private String sep;
77   private String levelValue, levelNum;
78   private MapFrame map;
79   private DrawAction drawAction;
80   private SelectAction selectAction;
81   private SpaceAction spaceAction;
82   private transient Shortcut spaceShortcut;
83   private EnterAction enterAction;
84   private transient Shortcut enterShortcut;
85   private boolean outerHelp, innerHelp, levelHelp;
86   private Collection<OsmPrimitive> innerRelation;
87   private LevelSelectorView selectorView;
88
89   /**
90    * Constructor for the {@link IndoorHelperController} which initiates model and views.
91    *
92    */
93   public IndoorHelperController() {
94
95       this.model = new IndoorHelperModel();
96       this.toolboxView = new ToolBoxView();
97
98       this.sep = System.getProperty("file.separator");
99       setPluginPreferences(true);
100
101       // Multipolygon actions
102       this.drawAction = new DrawAction();
103       this.map = MainApplication.getMap();
104       this.selectAction = new SelectAction(map);
105
106       // Ui elements
107       toolboxView.setAllUiElementsEnabled(true);
108       toolboxView.setROUiElementsEnabled(false);
109
110       addToolboxListeners();
111       MainApplication.getMap().addToggleDialog(toolboxView);
112
113       // Shortcuts
114       spaceShortcut = Shortcut.registerShortcut("mapmode:space",
115               "ConfirmObjectDrawing", KeyEvent.VK_SPACE, Shortcut.DIRECT);
116       this.spaceAction = new SpaceAction();
117       MainApplication.registerActionShortcut(spaceAction, spaceShortcut);
118
119       enterShortcut = Shortcut.registerShortcut("mapmode:enter",
120               "ConfirmMultipolygonSelection", KeyEvent.VK_ENTER, Shortcut.DIRECT);
121       this.enterAction = new EnterAction();
122       MainApplication.registerActionShortcut(enterAction, enterShortcut);
123
124       // Helper
125       outerHelp = false;
126       innerHelp = false;
127       levelHelp = false;
128       innerRelation = null;
129       levelValue = new String();
130       levelNum = new String();
131
132   }
133
134
135    /**
136     * Adds the button- and box-listeners to the {@link ToolBoxView}.
137     */
138    private void addToolboxListeners() {
139
140        if (this.toolboxView != null) {
141            this.toolboxView.setApplyButtonListener(new ToolApplyButtonListener());
142            this.toolboxView.setLevelCheckBoxListener(new ToolLevelCheckBoxListener());
143            this.toolboxView.setHelpButtonListener(new ToolHelpButtonListener());
144            this.toolboxView.setAddLevelButtonListener(new ToolAddLevelButtonListener());
145            this.toolboxView.setObjectItemListener(new ToolObjectItemListener());
146            this.toolboxView.setOuterButtonListener(new ToolOuterButtonListener());
147            this.toolboxView.setInnerButtonListener(new ToolInnerButtonListener());
148            this.toolboxView.setMultiCheckBoxListener(new ToolMultiCheckBoxListener());
149            this.toolboxView.setPreset1Listener(new Preset1Listener());
150            this.toolboxView.setPreset2Listener(new Preset2Listener());
151            this.toolboxView.setPreset3Listener(new Preset3Listener());
152            this.toolboxView.setPreset4Listener(new Preset4Listener());
153        }
154    }
155
156    /**
157     * Adds the button-listeners to the {@link LevelSelectorView}.
158     */
159    private void addLevelSelectorListeners() {
160        if (this.selectorView != null) {
161            this.selectorView.setOkButtonListener(new ToolLevelOkButtonListener());
162            this.selectorView.setCancelButtonListener(new ToolLevelCancelButtonListener());
163            this.selectorView.setSelectorWindowListener(new ToolSelectorWindowSListener());
164        }
165
166    }
167
168   /**
169    * The listener which provides the handling of the applyButton.
170    * Gets the texts which were written by the user and writes them to the OSM-data.
171    * After that it checks the tagged data.
172    *
173    * @author egru
174    * @author rebsc
175    */
176   class ToolApplyButtonListener implements ActionListener {
177
178       @Override
179       public void actionPerformed(ActionEvent e) {
180
181           IndoorObject indoorObject = toolboxView.getSelectedObject();
182
183               // collecting all tags
184               List<Tag> tags = new ArrayList<>();
185               if (!toolboxView.getLevelCheckBoxStatus() && !levelValue.equals("")) {
186                   tags.add(new Tag("level", levelValue));
187               }
188               if (!toolboxView.getLevelNameText().isEmpty() && !toolboxView.getLevelCheckBoxStatus()) {
189                      tags.add(new Tag("level_name", toolboxView.getLevelNameText()));
190               }
191               if (!toolboxView.getNameText().isEmpty()) {
192                   tags.add(new Tag("name", toolboxView.getNameText()));
193               }
194               if (!toolboxView.getRefText().isEmpty()) {
195                   tags.add(new Tag("ref", toolboxView.getRefText()));
196               }
197               if (!toolboxView.getRepeatOnText().isEmpty()) {
198                   tags.add(new Tag("repeat_on", toolboxView.getRepeatOnText()));
199               }
200               if (!toolboxView.getLevelNameText().isEmpty() && !toolboxView.getLevelCheckBoxStatus()) {
201                   tags.add(new Tag("level_name", toolboxView.getLevelNameText()));
202               }
203
204           // Tagging to OSM Data
205           model.addTagsToOSM(indoorObject, tags);
206
207           // Reset UI elements
208           toolboxView.resetUiElements();
209
210           //Do the validation process
211           ValidateAction validateAction = new ValidateAction();
212           validateAction.doValidate(true);
213
214           refreshPresets();
215
216       }
217   }
218
219   /**
220    * The listener which is called when a new item in the object list is selected.
221    *
222    * @author egru
223    * @author rebsc
224    *
225    */
226   class ToolObjectItemListener implements ItemListener {
227
228       @Override
229       public void itemStateChanged(ItemEvent e) {
230           if (toolboxView.getSelectedObject().equals(IndoorObject.ROOM)) {
231               toolboxView.setNRUiElementsEnabled(true);
232               toolboxView.setROUiElementsEnabled(false);
233           } else if (toolboxView.getSelectedObject().equals(IndoorObject.STEPS) ||
234                   toolboxView.getSelectedObject().equals(IndoorObject.ELEVATOR)) {
235                    toolboxView.setROUiElementsEnabled(true);
236                    toolboxView.setNRUiElementsEnabled(true);
237           } else {
238               toolboxView.setROUiElementsEnabled(false);
239           }
240       }
241   }
242
243   /**
244    * The listener which is called when the LevelCheckBox is selected.
245    *
246    * @author rebsc
247    */
248   class ToolLevelCheckBoxListener implements ItemListener {
249       @Override
250       public void itemStateChanged(ItemEvent e) {
251           if (e.getStateChange() == ItemEvent.SELECTED) {
252               toolboxView.setLVLUiElementsEnabled(false);
253           } else {
254               toolboxView.setLVLUiElementsEnabled(true);
255           }
256       }
257   }
258
259   /**
260    * The listener which is called when the helpButton got pushed.
261    *
262    * @author rebsc
263    */
264   static class ToolHelpButtonListener implements ActionListener {
265
266       @Override
267       public void actionPerformed(ActionEvent e) {
268           String topic = "Plugin/IndoorHelper";
269           //Open HelpBrowser for short description about the plugin
270           HelpBrowser.setUrlForHelpTopic(Optional.ofNullable(topic).orElse("/"));
271       }
272   }
273
274   /**
275    * The listener which is called when the addLevelButton got pushed.
276    *
277    * @author rebsc
278    */
279   class ToolAddLevelButtonListener implements ActionListener {
280
281       @Override
282       public void actionPerformed(ActionEvent e) {
283
284           if (selectorView == null) {
285               selectorView = new LevelSelectorView();
286               addLevelSelectorListeners();
287
288               //Show LevelSelectorView
289               selectorView.setVisible(true);
290           } else {
291               //Put focus back on LevelSelectorView
292               selectorView.toFront();
293           }
294
295       }
296   }
297
298   /**
299    * The listener which is called when the MultiCheckBox is selected.
300    *
301    * @author rebsc
302    */
303   class ToolMultiCheckBoxListener implements ItemListener {
304       @Override
305       public void itemStateChanged(ItemEvent e) {
306           if (e.getStateChange() == ItemEvent.SELECTED) {
307               toolboxView.setMultiUiElementsEnabled(false);
308           } else {
309               toolboxView.setMultiUiElementsEnabled(true);
310           }
311       }
312   }
313
314   /**
315    * The listener which is called when the OUTER Button got pushed.
316    *
317    * @author rebsc
318    */
319   class ToolOuterButtonListener implements ActionListener {
320
321       @Override
322       public void actionPerformed(ActionEvent e) {
323           // Select drawing action
324           map.selectMapMode(drawAction);
325
326           // For space shortcut to add the relation after spacebar got pushed {@link SpaceAction}
327           outerHelp = true;
328           innerHelp = false;
329       }
330   }
331
332   /**
333    * The listener which is called when the INNER Button got pushed.
334    *
335    * @author rebsc
336    */
337   class ToolInnerButtonListener implements ActionListener {
338       @Override
339       public void actionPerformed(ActionEvent e) {
340           // Select drawing action
341           map.selectMapMode(drawAction);
342
343           // For space shortcut to edit the relation after enter got pushed {@link SpaceAction}{@link EnterAction}
344           innerHelp = true;
345           outerHelp = false;
346
347       }
348   }
349
350   /**
351    * Listener for preset button 1.
352    * @author egru
353    *
354    */
355   class Preset1Listener implements ActionListener {
356
357       @Override
358       public void actionPerformed(ActionEvent e) {
359           model.addTagsToOSM(toolboxView.getPreset1());
360       }
361   }
362
363   /**
364    * Listener for preset button 2.
365    * @author egru
366    *
367    */
368   class Preset2Listener implements ActionListener {
369
370       @Override
371       public void actionPerformed(ActionEvent e) {
372           model.addTagsToOSM(toolboxView.getPreset2());
373       }
374   }
375
376   /**
377    * Listener for preset button 3.
378    * @author egru
379    *
380    */
381   class Preset3Listener implements ActionListener {
382
383       @Override
384       public void actionPerformed(ActionEvent e) {
385           model.addTagsToOSM(toolboxView.getPreset3());
386       }
387   }
388
389   /**
390    * Listener for preset button 4.
391    * @author egru
392    *
393    */
394   class Preset4Listener implements ActionListener {
395
396       @Override
397       public void actionPerformed(ActionEvent e) {
398           model.addTagsToOSM(toolboxView.getPreset4());
399       }
400   }
401
402   /**
403    * Updates the preset button from the current ranking.
404    */
405   private void refreshPresets() {
406       toolboxView.setPresetButtons(model.getPresetRanking());
407   }
408
409   /**
410    * Specific listener for the applyButton
411    * @author rebsc
412    *
413    */
414   class ToolLevelOkButtonListener implements ActionListener {
415
416       @Override
417       public void actionPerformed(ActionEvent e) {
418           levelHelp = true;
419
420           // Get insert level number out of SelectorView
421           if (!selectorView.getLevelNumber().equals("")) {
422               levelNum = selectorView.getLevelNumber();
423
424               //Unset visibility
425               selectorView.dispose();
426               //Select draw-action
427               map.selectMapMode(drawAction);
428
429           } else {
430               JOptionPane.showMessageDialog(null, tr("Please insert a value."), tr("Error"), JOptionPane.ERROR_MESSAGE);
431           }
432
433           selectorView = null;
434       }
435   }
436
437   /**
438    * Specific listener for the cancelButton
439    * @author rebsc
440    *
441    */
442   class ToolLevelCancelButtonListener implements ActionListener {
443
444       @Override
445       public void actionPerformed(ActionEvent e) {
446           selectorView.dispose();
447           selectorView = null;
448       }
449   }
450
451   /**
452    * General listener for LevelSelectorView window
453    * @author rebsc
454    *
455    */
456   class ToolSelectorWindowSListener implements WindowListener {
457
458    @Override
459    public void windowClosed(WindowEvent e) {
460        selectorView = null;
461    }
462
463    @Override
464    public void windowClosing(WindowEvent e) {
465        selectorView = null;
466    }
467
468    @Override
469    public void windowActivated(WindowEvent arg0) {
470        // TODO Auto-generated method stub
471
472    }
473
474    @Override
475    public void windowDeactivated(WindowEvent arg0) {
476        // TODO Auto-generated method stub
477
478    }
479
480    @Override
481    public void windowDeiconified(WindowEvent arg0) {
482        // TODO Auto-generated method stub
483
484    }
485
486    @Override
487    public void windowIconified(WindowEvent arg0) {
488        // TODO Auto-generated method stub
489
490    }
491
492    @Override
493    public void windowOpened(WindowEvent arg0) {
494        // TODO Auto-generated method stub
495
496    }
497   }
498
499   /**
500    * Shortcut for spacebar
501    * @author rebsc
502    */
503   private class SpaceAction extends AbstractAction {
504
505    private static final long serialVersionUID = 1L;
506
507    @Override
508       public void actionPerformed(ActionEvent e) {
509           if (outerHelp) {
510
511               //Create new relation and add the currently drawn object to it
512               model.addRelation("outer");
513               map.selectMapMode(selectAction);
514               outerHelp = false;
515
516               //Clear currently selection
517               MainApplication.getLayerManager().getEditDataSet().clearSelection();
518           } else if (innerHelp) {
519
520               //Save new drawn relation for adding
521               innerRelation = MainApplication.getLayerManager().getEditDataSet().getAllSelected();
522                     map.selectMapMode(selectAction);
523
524               //Clear currently selection
525               MainApplication.getLayerManager().getEditDataSet().clearSelection();
526           } else if (levelHelp) {
527
528               List<Tag> tags = new ArrayList<>();
529               tags.add(new Tag("level", levelNum));
530
531               //Add level tag
532               model.addTagsToOSM(tags);
533
534               //Change action
535               map.selectMapMode(selectAction);
536               levelHelp = false;
537           }
538       }
539   }
540
541   /**
542    * Shortcut for enter
543    * @author rebsc
544    */
545   private class EnterAction extends AbstractAction {
546
547    private static final long serialVersionUID = 1L;
548
549       @Override
550       public void actionPerformed(ActionEvent e) {
551           if (innerHelp && !outerHelp) {
552               // Edit the new drawn relation member to selected relation
553               model.editRelation("inner", innerRelation);
554               innerHelp = false;
555           } else if ((innerHelp && outerHelp) || (outerHelp && !innerHelp)) {
556               JOptionPane.showMessageDialog(null,
557                       tr("Please press spacebar first to add \"outer\" object to relation."), tr("Relation-Error"), JOptionPane.ERROR_MESSAGE);
558               resetHelper();
559           }
560       }
561   }
562
563   /**
564    * Function which unsets the disabled state of currently hidden and/or disabled objects which have a
565    * specific tag (key). Just unsets the disabled state if object has a tag-value which is part of the
566    * current working level.
567    *
568    * @author rebsc
569    * @param key sepcific key to unset hidden objects which contains it
570    */
571   public void unsetSpecificKeyFilter(String key) {
572
573     Collection<OsmPrimitive> p = OsmDataManager.getInstance().getEditDataSet().allPrimitives();
574     int level = Integer.parseInt(levelValue);
575
576     //Find all primitives with the specific tag and check if value is part of the current
577     //workinglevel. After that unset the disabled status.
578     for (OsmPrimitive osm: p) {
579         if ((osm.isDisabledAndHidden() || osm.isDisabled()) && osm.hasKey(key)) {
580             for (Map.Entry<String, String> e: osm.getInterestingTags().entrySet()) {
581                if (e.getKey().equals(key)) {
582                    //Compare values to current working level
583                    if (IndoorLevel.isPartOfWorkingLevel(e.getValue(), level)) {
584                        osm.unsetDisabledState();
585                    } else {
586                        osm.setDisabledState(true);
587                    }
588                }
589             }
590         }
591     }
592   }
593
594    /**
595     * Function which updates the current working level tag
596     *
597     * @param indoorLevel current working level
598     */
599    public void setIndoorLevel(String indoorLevel) {
600       this.toolboxView.setLevelLabel(indoorLevel);
601    }
602
603    /**
604     * Function which gets the current working level tag
605     *
606     * @param indoorLevel current working level
607     */
608    public void getIndoorLevel(String indoorLevel) {
609        levelValue = indoorLevel;
610    }
611
612    /**
613     * Function which resets the helper for relation adding
614     */
615    private void resetHelper() {
616        innerHelp = false;
617        outerHelp = false;
618    }
619
620    /**
621     * Forces JOSM to load the mappaint settings.
622     */
623    private void updateSettings() {
624        Preferences.main().init(false);
625        MapPaintStyles.readFromPreferences();
626    }
627
628    /**
629     * Enables or disables the preferences for the mapcss-style.
630     *
631     * @param enabled Activates or disables the settings.
632     */
633    private void setPluginPreferences(boolean enabled) {
634       Map<String, Setting<?>> settings = Preferences.main().getAllSettings();
635
636       MapListSetting styleMapListSetting = (MapListSetting) settings.
637               get("mappaint.style.entries");
638       List<Map<String, String>> styleMaps = new ArrayList<>();
639       if (styleMapListSetting != null) {
640           styleMaps = styleMapListSetting.getValue();
641       }
642
643       if (enabled) {
644           //set mappaint active
645
646           List<Map<String, String>> styleMapsNew = new ArrayList<>();
647           if (!styleMaps.isEmpty()) {
648               styleMapsNew.addAll(styleMaps);
649           }
650
651           for (Map<String, String> map : styleMapsNew) {
652               if (map.containsValue(tr("Indoor"))) {
653                   styleMapsNew.remove(map);
654                   break;
655               }
656           }
657           Map<String, String> indoorMapPaint = new HashMap<>();
658           indoorMapPaint.put("title", tr("Indoor"));
659           indoorMapPaint.put("active", "true");
660           indoorMapPaint.put("url", Config.getDirs().getUserDataDirectory(true) + sep + "styles"
661                   + sep + "sit.mapcss");
662           styleMapsNew.add(indoorMapPaint);
663           Config.getPref().putListOfMaps("mappaint.style.entries", styleMapsNew);
664
665           updateSettings();
666       } else {
667           //set mappaint inactive
668
669           List<Map<String, String>> styleMapsNew = new ArrayList<>();
670           if (!styleMaps.isEmpty()) {
671               styleMapsNew.addAll(styleMaps);
672           }
673           for (Map<String, String> map : styleMapsNew) {
674               if (map.containsValue(tr("Indoor"))) {
675                   styleMapsNew.remove(map);
676                   break;
677               }
678           }
679           Map<String, String> indoorMapPaint = new HashMap<>();
680           indoorMapPaint.put("title", tr("Indoor"));
681           indoorMapPaint.put("active", "false");
682           indoorMapPaint.put("url", Config.getDirs().getUserDataDirectory(true) + sep + "styles"
683                   + sep + "sit.mapcss");
684           styleMapsNew.add(indoorMapPaint);
685           Config.getPref().putListOfMaps("mappaint.style.entries", styleMapsNew);
686
687           updateSettings();
688       }
689   }
690}
Note: See TracBrowser for help on using the repository browser.